#include #include #include #include #include #include #include #include #include #include #include #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); }