#include #include #include #include #include #include #include #include #include #include #include #include "alarmd_proto.h" struct alarm { UT_hash_handle hh; char uuid[16]; char *name; bool is_raised; // time_t last_change; }; static struct alarm *alarms; int8_t read_string(int sock, char (*buffer)[128]) { uint8_t length = 0; if (recv(sock, &length, sizeof(uint8_t), 0) < sizeof(uint8_t)) { return -1; } if (length >= 128) { return -1; } if (recv(sock, buffer, length, 0) < 0) { return -1; } (*buffer)[length] = '\0'; return length; } int main(void) { int sock = 0; int c_sock = 0; socklen_t c_addr_l = 0; struct addrinfo hints, *s_info, *p; struct sockaddr_storage c_addr; char buffer[128]; uint32_t packet_type = 0; ssize_t nread = 0; uint32_t count = 0; int reuse = 1; uuid_t uuid; char uuid_str[37]; struct alarm *target = NULL; bzero(&hints, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; if (getaddrinfo(NULL, ALARMD_PORT, &hints, &s_info) < 0) { perror("getaddrinfo"); return 1; } for (p = s_info; p != NULL; p = p->ai_next) { if ((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) { perror("socket"); continue; } if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) { perror("setsockopt"); return 1; } if (bind(sock, p->ai_addr, p->ai_addrlen) < 0) { perror("bind"); continue; } break; } if (!p) { fprintf(stderr, "No addresses to bind to\n"); return 1; } freeaddrinfo(s_info); if (listen(sock, 128) < 0) { perror("listen"); return 1; } c_addr_l = sizeof(c_addr); if ((c_sock = accept(sock, (struct sockaddr *)&c_addr, &c_addr_l)) < 0) { perror("accept"); return 1; } while (1) { /* read packet type */ nread = recv(c_sock, &packet_type, sizeof(packet_type), 0); if (nread < 0) { perror("read"); return 1; } else if (nread < sizeof(packet_type)) { fprintf(stderr, "Packet type too short\n"); return 1; } packet_type = ntohl(packet_type); switch(packet_type) { case ALARMD_PACKET_TYPE_REGISTER: if (read_string(c_sock, &buffer) < 0) { return 1; } uuid_generate(uuid); //uuid_unparse(uuid, uuid_str); //fprintf(stderr, "Registering alarm %s with uuid %s\n", buffer, uuid_str); if (send(c_sock, uuid, sizeof(uuid), 0) != sizeof(uuid)) { perror("send"); return 1; } struct alarm *new_alarm = malloc(sizeof(*new_alarm)); if (new_alarm == NULL) { perror("malloc"); return 1; } new_alarm->name = strdup(buffer); memcpy(new_alarm->uuid, uuid, 16); new_alarm->is_raised = 0; HASH_ADD(hh, alarms, uuid, 16, new_alarm); break; case ALARMD_PACKET_TYPE_DEREGISTER: /* FIXME 16 magic */ if (recv(c_sock, &buffer, 16, 0) < 16) { return 1; } uuid_unparse(buffer, uuid_str); fprintf(stderr, "Deregistering alarm %s\n", uuid_str); HASH_FIND(hh, alarms, buffer, 16, target); if (target != NULL) { HASH_DEL(alarms, target); free(target); } break; case ALARMD_PACKET_TYPE_RAISE: /* FIXME 16 magic */ if (recv(c_sock, &buffer, 16, 0) < 16) { return 1; } uuid_unparse(buffer, uuid_str); fprintf(stderr, "Raising alarm %s\n", uuid_str); HASH_FIND(hh, alarms, buffer, 16, target); if (target != NULL) { target->is_raised = 1; } break; case ALARMD_PACKET_TYPE_CLEAR: /* FIXME 16 magic */ if (recv(c_sock, &buffer, 16, 0) < 16) { return 1; } uuid_unparse(buffer, uuid_str); fprintf(stderr, "Clearing alarm %s\n", uuid_str); HASH_FIND(hh, alarms, buffer, 16, target); if (target != NULL) { target->is_raised = 0; } break; case ALARMD_PACKET_TYPE_QUERY: /* bounds-check HASH_COUNT*/ count = htonl(HASH_COUNT(alarms)); uint8_t length = 0; /* FIXME */ struct alarm *a = NULL; struct alarm *tmp = NULL; HASH_ITER(hh, alarms, a, tmp) { fprintf(stderr, "DEBUG : [%s] %s\n", a->is_raised ? "RAISE" : "CLEAR" , a->name); if (send(c_sock, &count, sizeof(count), 0) < sizeof(count)) { perror("send"); } /* FIXME factor out, idiot. also bounds check on strlen */ length = strlen(a->name); if (send(c_sock, &length, sizeof(length), 0) < sizeof(length)) { perror("send"); } if (send(c_sock, a->name, strlen(a->name), 0) < strlen(a->name)) { perror("send"); } if (send(c_sock, &(a->is_raised), sizeof(a->is_raised), 0) < sizeof(a->is_raised)) { perror("send"); } fprintf(stderr, "SENT.\n"); } break; default: fprintf(stderr, "Unknown packet type %d\n", packet_type); break; } } fprintf(stderr, "Server stopping\n"); close(sock); }