diff options
Diffstat (limited to 'send/sendd.c')
-rw-r--r-- | send/sendd.c | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/send/sendd.c b/send/sendd.c new file mode 100644 index 0000000..1b0c34e --- /dev/null +++ b/send/sendd.c @@ -0,0 +1,207 @@ +#include <sys/socket.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <ctype.h> +#include <stdbool.h> + +#include "util.h" + +/* + * CONNECT MSG: "connect NAME" + * SEND MSG: "msg XXXXX CONTENTS TIME" + * VALID MSG: 0 + * INVALID MSG: 1 + */ + +typedef struct client { + char *name; + int fd; + bool connected; +} client; + +typedef struct msg { + client *sender; + char *contents; + time_t time; +} msg; + +FILE *fout; +int VALID = 0; +int INVALID = 1; + +static int +init_daemon(int port) { + int s = socket(AF_INET, SOCK_STREAM, 0); + + struct sockaddr_in addr = {AF_INET, htons(port), INADDR_ANY}; + + if (bind(s, (struct sockaddr *)&addr, sizeof(addr))) + error("Failed to bind"); + + int flags = 10; + if (setsockopt(s, SOL_TCP, TCP_KEEPIDLE, (void *)&flags, sizeof(flags))) + error("Couldn't set socket opts"); + + flags = 5; + if (setsockopt(s, SOL_TCP, TCP_KEEPCNT, (void *)&flags, sizeof(flags))) + error("Couldn't set socket opts"); + + flags = 5; + if (setsockopt(s, SOL_TCP, TCP_KEEPINTVL, (void *)&flags, sizeof(flags))) + error("Couldn't set socket opts"); + + listen(s, 10); + return s; +} + +static void +stop_daemon(int s) { + close(s); +} + +static client * +accept_client(int s) { + client *c = malloc(sizeof(client)); + c->fd = accept(s, NULL, NULL); + + char buf[256] = {0}; + char *Pbuf = buf; + int n = recv(c->fd, buf, 256, 0); + if (n <= 0) { + warn("Client hungup"); + close(c->fd); + return NULL; + } + if (n <= 8) { + warn("Malformed connect msg"); + close(c->fd); + return NULL; + } + + if (memcmp(buf, "connect ", 8) != 0) { + warn("Malformed connect msg"); + close(c->fd); + return NULL; + } + + Pbuf += 8; + c->name = strdup(Pbuf); + c->connected = true; + + return c; +} + +static void +close_client(client *c) { + close(c->fd); + free(c->name); + free(c); +} + +static msg* +recv_msg(client *c) { + char buf[11] = {0}; + char *Pbuf = buf + 4; + int n = recv(c->fd, buf, 10, 0); + if (n <= 0) { + warn("Client hungup"); + close(c->fd); + c->connected = false; + return NULL; + } + if (n < 10) { + warn("Malformed msg msg"); + send(c->fd, &INVALID, sizeof(int), 0); + return NULL; + } + if (memcmp(buf, "msg ", 4) != 0) { + warn("Malformed msg msg"); + send(c->fd, &INVALID, sizeof(int), 0); + return NULL; + } + for (int i = 4; buf[i] != 0 && i < 9; i++) { + if (!isdigit(buf[i])) { + warn("Malformed msg msg"); + send(c->fd, &INVALID, sizeof(int), 0); + return NULL; + } + } + + int len = atoi(Pbuf); + char *contents = malloc(len); + memset(contents, 0, len); + + n = recv(c->fd, contents, len, 0); + if (n <= 0) { + warn("Client hungup"); + c->connected = false; + close(c->fd); + return NULL; + } + + msg *m = malloc(sizeof(msg)); + m->sender = c; + m->contents = contents; + + time_t t; + n = recv(c->fd, &t, sizeof(time_t), 0); + if (n <= 0) { + warn("Client hungup"); + c->connected = false; + close(c->fd); + return NULL; + } + m->time = t; + + send(c->fd, &VALID, sizeof(int), 0); + + return m; +} + +static void +free_msg(msg *m) { + free(m->contents); + free(m); +} + +static void +msg_loop(client *c) { + msg *m; + while (c->connected && (m = recv_msg(c))) { + fprintf(fout, "%lld:%s:%s\n", m->time, m->sender->name, m->contents); + free_msg(m); + } + close_client(c); + exit(0); +} + +int +main(int argc, char **argv) { + char *out; + if (argc <= 1) + out = "/dev/stdout"; + else + out = argv[1]; + + if (!(fout = fopen(out, "w"))) + error("Couldn't open outfile"); + + int s = init_daemon(1543); + + pid_t pid; + for (;;) { + client *c = accept_client(s); + if ((pid = fork()) == 0) + msg_loop(c); + else + continue; + } + + stop_daemon(s); +} |