summaryrefslogtreecommitdiff
path: root/send/sendd.c
diff options
context:
space:
mode:
Diffstat (limited to 'send/sendd.c')
-rw-r--r--send/sendd.c207
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);
+}