From 5f5316a034d68f8825a16e7b866c8e8b2b6c6bd8 Mon Sep 17 00:00:00 2001 From: David Phillips Date: Mon, 4 Jun 2018 00:09:02 +1200 Subject: Initial dump of prototype --- .gitignore | 4 + LICENCE | 26 ++++ Makefile | 6 + alarm-tools/Makefile | 4 + alarm-tools/alarmd_reference_client.c | 224 ++++++++++++++++++++++++++++++++++ alarm-tools/alarms-show.c | 109 +++++++++++++++++ alarmd/Makefile | 4 + alarmd/alarmd.c | 207 +++++++++++++++++++++++++++++++ inc/alarmd_proto.h | 23 ++++ lib/Makefile | 8 ++ lib/libalarm.c | 140 +++++++++++++++++++++ 11 files changed, 755 insertions(+) create mode 100644 .gitignore create mode 100644 LICENCE create mode 100644 Makefile create mode 100644 alarm-tools/Makefile create mode 100644 alarm-tools/alarmd_reference_client.c create mode 100644 alarm-tools/alarms-show.c create mode 100644 alarmd/Makefile create mode 100644 alarmd/alarmd.c create mode 100644 inc/alarmd_proto.h create mode 100644 lib/Makefile create mode 100644 lib/libalarm.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f792cfc --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +alarmd/alarmd +alarm-tools/alarms-show +*.so +*.o diff --git a/LICENCE b/LICENCE new file mode 100644 index 0000000..b8bc9d2 --- /dev/null +++ b/LICENCE @@ -0,0 +1,26 @@ +/* + * alarmd - Monitor state transition of client-reported fault conditions + * Copyright (c) 2018 David Phillips + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f53fb76 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +CFLAGS += "-I./inc/" +LDFLAGS += -L./lib/ + +.PHONY lib alarmd alarms-show + +all: lib alarmd alarm-tools diff --git a/alarm-tools/Makefile b/alarm-tools/Makefile new file mode 100644 index 0000000..75f3c5b --- /dev/null +++ b/alarm-tools/Makefile @@ -0,0 +1,4 @@ +LDFLAGS += -L../lib -lalarm +CFLAGS += -I../inc + +all: alarms-show diff --git a/alarm-tools/alarmd_reference_client.c b/alarm-tools/alarmd_reference_client.c new file mode 100644 index 0000000..d200e04 --- /dev/null +++ b/alarm-tools/alarmd_reference_client.c @@ -0,0 +1,224 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alarmd_proto.h" + +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)[127] = '\0'; + return length; +} + +int alarmd_dump_alarms(int sock) +{ + ssize_t i = 0; + ssize_t nread = 0; + size_t length = 0; + uint32_t count = 0; + uint32_t packet_type = 0; + uint8_t is_raised = 0; + char buffer[128]; + + packet_type = htonl(ALARMD_PACKET_TYPE_QUERY); + + if (send(sock, &packet_type, sizeof(packet_type), 0) != sizeof(packet_type)) { + perror("send"); + return 1; + } + + nread = recv(sock, &count, sizeof(count), 0); + if (nread < 0) { + perror("recv"); + return 1; + } else if (nread < sizeof(count)) { + fprintf(stderr, "Alarm count too small\n"); + return 1; + } + + count = ntohl(count); + + printf("Alarms\n" + "------\n"); + + for (i = 0; i < count; i++) { + if ((length = read_string(sock, &buffer)) < 0) { + perror("recv"); + break; + } + if (recv(sock, &is_raised, sizeof(is_raised), 0) != sizeof(is_raised)) { + perror("recv"); + break; + } + printf("[%s] %s\n", is_raised ? "\x1b[1;31mRAISE\x1b[0m" : "\x1b[1;32mCLEAR\x1b[0m", buffer); + } + + if (i < count) { + fprintf(stderr, "Not all alarms received, output must be missing some\n"); + return 1; + } + + printf("\n"); + + return 0; +} + +int alarmd_register(int sock, char *desc, char (*uuid)[16]) +{ + uint8_t length = 0; + uint32_t packet_type = 0; + + packet_type = htonl(ALARMD_PACKET_TYPE_REGISTER); + if (send(sock, &packet_type, sizeof(packet_type), 0) != sizeof(packet_type)) { + perror("send"); + return 1; + } + + length = strlen(desc); + if (send(sock, &length, sizeof(length), 0) != sizeof(length)) { + perror("send"); + return 1; + } + + if (send(sock, desc, strlen(desc), 0) != strlen(desc)) { + perror("send"); + return 1; + } + if (recv(sock, uuid, 16, 0) != 16) { + perror("recv"); + return 1; + } + return 0; +} + +int alarmd_deregister(int sock, char uuid[16]) +{ + uint32_t packet_type = 0; + + packet_type = htonl(ALARMD_PACKET_TYPE_DEREGISTER); + if (send(sock, &packet_type, sizeof(packet_type), 0) != sizeof(packet_type)) { + perror("send"); + return 1; + } + + /* FIXME 16 magic */ + if (send(sock, uuid, 16, 0) != 16) { + perror("send"); + return 1; + } + return 0; +} + +int alarmd_raise(int sock, char uuid[16]) +{ + uint32_t packet_type = 0; + + packet_type = htonl(ALARMD_PACKET_TYPE_RAISE); + if (send(sock, &packet_type, sizeof(packet_type), 0) != sizeof(packet_type)) { + perror("send"); + return 1; + } + + /* FIXME 16 magic */ + if (send(sock, uuid, 16, 0) != 16) { + perror("send"); + return 1; + } + return 0; +} + +int alarmd_clear(int sock, char uuid[16]) +{ + uint32_t packet_type = 0; + + packet_type = htonl(ALARMD_PACKET_TYPE_CLEAR); + if (send(sock, &packet_type, sizeof(packet_type), 0) != sizeof(packet_type)) { + perror("send"); + return 1; + } + + /* FIXME 16 magic */ + if (send(sock, uuid, 16, 0) != 16) { + perror("send"); + return 1; + } + return 0; +} + +int main(void) +{ + int sock = 0; + char buffer[128]; + struct addrinfo hints, *s_info, *p; + + bzero(&hints, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + /* FIXME spec custom hostname on cmd line */ + if (getaddrinfo("localhost", 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 (connect(sock, p->ai_addr, p->ai_addrlen) < 0) { + close(sock); + perror("connect"); + continue; + } + break; + } + + if (!p) { + fprintf(stderr, "Connection to server failed\n"); + return 1; + } + + + /**/ + char *name = "Some test alarm"; + char uuid[16]; + /**/ + + freeaddrinfo(s_info); + + printf(">>>Register\n"); + int i, j; + for (i = 0; i < 10000; i++) { + for (j = 0; j < 100; j++) { + alarmd_register(sock, name, &uuid); + } + fprintf(stderr, "%d", i); + } + +// alarmd_dump_alarms(sock); +// printf(">>>Raise\n"); +// alarmd_raise(sock, uuid); +// alarmd_dump_alarms(sock); +// printf(">>>Clear\n"); +// alarmd_clear(sock, uuid); +// alarmd_dump_alarms(sock); +// printf(">>>Deregister\n"); +// alarmd_deregister(sock, uuid); + close(sock); +} diff --git a/alarm-tools/alarms-show.c b/alarm-tools/alarms-show.c new file mode 100644 index 0000000..0d63d4a --- /dev/null +++ b/alarm-tools/alarms-show.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alarmd_proto.h" + +int dump_alarms(int sock) +{ + ssize_t i = 0; + ssize_t nread = 0; + size_t length = 0; + uint32_t count = 0; + uint32_t packet_type = 0; + uint8_t is_raised = 0; + char buffer[128]; + + packet_type = htonl(ALARMD_PACKET_TYPE_QUERY); + + if (send(sock, &packet_type, sizeof(packet_type), 0) != sizeof(packet_type)) { + perror("send"); + return 1; + } + + nread = recv(sock, &count, sizeof(count), 0); + if (nread < 0) { + perror("recv"); + return 1; + } else if (nread < sizeof(count)) { + fprintf(stderr, "Alarm count too small\n"); + return 1; + } + + count = ntohl(count); + + printf("Alarms\n" + "------\n"); + + for (i = 0; i < count; i++) { + if ((length = recv_string(sock, &buffer)) < 0) { + perror("recv"); + break; + } + if (recv(sock, &is_raised, sizeof(is_raised), 0) != sizeof(is_raised)) { + perror("recv"); + break; + } + printf("[%s] %s\n", is_raised ? "\x1b[1;31mRAISE\x1b[0m" : "\x1b[1;32mCLEAR\x1b[0m", buffer); + } + + if (i < count) { + fprintf(stderr, "Not all alarms received, output must be missing some\n"); + return 1; + } + + printf("\n"); + + return 0; +} + +int main(void) +{ + int sock = 0; + char buffer[128]; + struct addrinfo hints, *s_info, *p; + + bzero(&hints, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + /* FIXME spec custom hostname on cmd line */ + if (getaddrinfo("localhost", 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 (connect(sock, p->ai_addr, p->ai_addrlen) < 0) { + close(sock); + perror("connect"); + continue; + } + break; + } + + if (!p) { + fprintf(stderr, "Connection to server failed\n"); + return 1; + } + + + /**/ + char *name = "Some test alarm"; + char uuid[16]; + /**/ + + freeaddrinfo(s_info); + + dump_alarms(sock); + close(sock); +} diff --git a/alarmd/Makefile b/alarmd/Makefile new file mode 100644 index 0000000..b6c56d9 --- /dev/null +++ b/alarmd/Makefile @@ -0,0 +1,4 @@ +LDFLAGS += -L../lib -lalarm -luuid +CFLAGS += -I../inc + +all: alarmd diff --git a/alarmd/alarmd.c b/alarmd/alarmd.c new file mode 100644 index 0000000..239fc3b --- /dev/null +++ b/alarmd/alarmd.c @@ -0,0 +1,207 @@ +#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); +} diff --git a/inc/alarmd_proto.h b/inc/alarmd_proto.h new file mode 100644 index 0000000..ebeddf1 --- /dev/null +++ b/inc/alarmd_proto.h @@ -0,0 +1,23 @@ +#ifndef ALARMD_PROTO_H +#define ALARMD_PROTO_H + +#include + +#define ALARMD_PORT "1433" + +enum alarmd_packet_type { + ALARMD_PACKET_TYPE_REGISTER, + ALARMD_PACKET_TYPE_DEREGISTER, + ALARMD_PACKET_TYPE_RAISE, + ALARMD_PACKET_TYPE_CLEAR, + ALARMD_PACKET_TYPE_QUERY, +}; + +int8_t recv_string(int sock, char (*buffer)[128]); +int send_string(int sock, char *buffer); +int alarmd_register(int sock, char *desc, char (*uuid)[16]); +int alarmd_deregister(int sock, char uuid[16]); +int alarmd_raise(int sock, char uuid[16]); +int alarmd_clear(int sock, char uuid[16]); + +#endif /* ALARMD_PROTO_H */ diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 0000000..52368e0 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,8 @@ + +CFLAGS += "-I../inc/" + +libalarm.so: libalarm.o + $(CC) -shared -o $@ $< $(LDFLAGS) + +.o.c: + $(CC) -o $@ $< $(LDFLAGS) diff --git a/lib/libalarm.c b/lib/libalarm.c new file mode 100644 index 0000000..856d8f6 --- /dev/null +++ b/lib/libalarm.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include + +int8_t recv_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 send_string(int sock, char *buffer) +{ + ssize_t sent = 0; + size_t length = 0; + uint8_t length8 = 0; + + /* Protocol allows strings of length < 128 */ + if (length >= 128) { + return 1; + } + + /* bitmasking is unnecessary by now aside from clarity */ + length8 = length8 & 0xFF; + + if (send(sock, &length8, sizeof(length8), 0) < sizeof(length8)) { + return 1; + } + sent = send(sock, buffer, length8, 0); + if (sent < 0) { + perror("send"); + return 1; + } else if (sent < length8) { + return 1; + } + return 0; +} + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alarmd_proto.h" + +int alarmd_register(int sock, char *desc, char (*uuid)[16]) +{ + uint8_t length = 0; + uint32_t packet_type = 0; + + packet_type = htonl(ALARMD_PACKET_TYPE_REGISTER); + if (send(sock, &packet_type, sizeof(packet_type), 0) != sizeof(packet_type)) { + perror("send"); + return 1; + } + + length = strlen(desc); + if (send(sock, &length, sizeof(length), 0) != sizeof(length)) { + perror("send"); + return 1; + } + + if (send(sock, desc, strlen(desc), 0) != strlen(desc)) { + perror("send"); + return 1; + } + if (recv(sock, uuid, 16, 0) != 16) { + perror("recv"); + return 1; + } + return 0; +} + +int alarmd_deregister(int sock, char uuid[16]) +{ + uint32_t packet_type = 0; + + packet_type = htonl(ALARMD_PACKET_TYPE_DEREGISTER); + if (send(sock, &packet_type, sizeof(packet_type), 0) != sizeof(packet_type)) { + perror("send"); + return 1; + } + + /* FIXME 16 magic */ + if (send(sock, uuid, 16, 0) != 16) { + perror("send"); + return 1; + } + return 0; +} + +int alarmd_raise(int sock, char uuid[16]) +{ + uint32_t packet_type = 0; + + packet_type = htonl(ALARMD_PACKET_TYPE_RAISE); + if (send(sock, &packet_type, sizeof(packet_type), 0) != sizeof(packet_type)) { + perror("send"); + return 1; + } + + /* FIXME 16 magic */ + if (send(sock, uuid, 16, 0) != 16) { + perror("send"); + return 1; + } + return 0; +} + +int alarmd_clear(int sock, char uuid[16]) +{ + uint32_t packet_type = 0; + + packet_type = htonl(ALARMD_PACKET_TYPE_CLEAR); + if (send(sock, &packet_type, sizeof(packet_type), 0) != sizeof(packet_type)) { + perror("send"); + return 1; + } + + /* FIXME 16 magic */ + if (send(sock, uuid, 16, 0) != 16) { + perror("send"); + return 1; + } + return 0; +} -- cgit v1.1