aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/array.c47
-rw-r--r--src/common/better_string.c51
-rw-r--r--src/common/hash_table.c12
-rw-r--r--src/common/helpers.c36
-rw-r--r--src/common/opcodes.c20
-rw-r--r--src/common/tsv.c32
-rw-r--r--src/include/array.h24
-rw-r--r--src/include/better_string.h24
-rw-r--r--src/include/hash_table.h43
-rw-r--r--src/include/helpers.h17
-rw-r--r--src/include/opcodes.h47
-rw-r--r--src/include/protocol.h68
-rw-r--r--src/include/tsv.h16
-rw-r--r--src/msg/main.c6
-rw-r--r--src/ramen/main.c201
15 files changed, 644 insertions, 0 deletions
diff --git a/src/common/array.c b/src/common/array.c
new file mode 100644
index 0000000..4ebb67e
--- /dev/null
+++ b/src/common/array.c
@@ -0,0 +1,47 @@
+#include "../include/array.h"
+#include "../include/helpers.h"
+
+#include <stdlib.h>
+
+array_t *init_array() {
+ array_t *a = safe_calloc(1, sizeof(array_t));
+ a->capacity = DEFAULT_ARR_LEN;
+ a->size = 0;
+ a->items = safe_calloc(a->capacity, sizeof(void *));
+ return a;
+}
+
+void array_push(array_t *a, void *item) {
+ if (a->size >= a->capacity - 2) {
+ a->capacity *= 2;
+ a->items = realloc(a->items, a->capacity);
+ }
+ a->items[a->size] = item;
+ a->size++;
+}
+
+void *array_pop(array_t *a) {
+ if (a->size <= 0)
+ return NULL;
+ void *retval = a->items[a->size];
+ a->size--;
+ return retval;
+}
+
+array_t *array_reverse(array_t *a) {
+ array_t *reverse = init_array();
+ for (int i = 0; i < a->size; i ++) {
+ array_push(reverse, array_pop(a));
+ }
+ array_free(a, nothing);
+ return reverse;
+}
+
+void array_free(void *x, void (*freefunc)(void *)) {
+ array_t *a = (array_t *)x;
+ for (int i = 0; i < a->size; i++) {
+ freefunc(a->items[i]);
+ }
+ free(a->items);
+ free(a);
+}
diff --git a/src/common/better_string.c b/src/common/better_string.c
new file mode 100644
index 0000000..366dda6
--- /dev/null
+++ b/src/common/better_string.c
@@ -0,0 +1,51 @@
+#include "../include/better_string.h"
+#include "../include/helpers.h"
+#include <stdlib.h>
+#include <string.h>
+
+string_t *init_string(const char *src) {
+ string_t *s = safe_calloc(1, sizeof(string_t));
+ size_t len = src ? strlen(src) : DEFAULT_STR_SIZE;
+ size_t size = len * 2;
+ s->buf = safe_calloc(size, sizeof(char));
+ s->buf[0] = '\0';
+
+ if (src)
+ strcpy(s->buf, src);
+ s->len = len;
+ s->size = size;
+ return s;
+}
+
+void string_push(string_t *s, char c) {
+ if (s->len >= s->size - 2) {
+ s->size *= 2;
+ s->buf = safe_realloc(s->buf, s->size);
+ }
+ s->buf[s->len] = c;
+ s->len++;
+}
+
+char string_pop(string_t *s) {
+ char c = s->buf[s->len];
+ s->len--;
+ return c;
+}
+
+void string_concat_const(string_t *s1, const char *s2) {
+ for (int i = 0; i < strlen(s2); i++) {
+ string_push(s1, s2[i]);
+ }
+}
+
+void string_concat(string_t *s1, string_t *s2) {
+ for (int i = 0; i < s2->len; i++) {
+ string_push(s1, s2->buf[i]);
+ }
+}
+
+void string_free(void *x) {
+ string_t *s = x;
+ free(s->buf);
+ free(s);
+}
diff --git a/src/common/hash_table.c b/src/common/hash_table.c
new file mode 100644
index 0000000..2f66d45
--- /dev/null
+++ b/src/common/hash_table.c
@@ -0,0 +1,12 @@
+#include "../include/hash_table.h"
+#include "../include/helpers.h"
+
+#include <stdlib.h>
+
+ht_t *init_ht(size_t size) {
+ ht_t *ht = safe_calloc(1, sizeof(size));
+ size_t realsize = size == 0 ? DEFAULT_HT_SIZE : size;
+ ht->buckets = safe_calloc(realsize, sizeof(sll_t *));
+ ht->size = realsize;
+ return ht;
+}
diff --git a/src/common/helpers.c b/src/common/helpers.c
new file mode 100644
index 0000000..4bf7301
--- /dev/null
+++ b/src/common/helpers.c
@@ -0,0 +1,36 @@
+#include "../include/helpers.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void die_lz(int code, const char *msg) {
+ if (code < 0) {
+ die(msg);
+ }
+}
+
+void die(const char *msg) {
+ fprintf(stderr, "panic: ");
+ perror(msg);
+ exit(EXIT_FAILURE);
+}
+
+void *safe_calloc(unsigned int i, size_t size) {
+ void *x = calloc(i, size);
+ if (x == NULL) {
+ die("abort: calloc()");
+ }
+ return x;
+}
+
+void *safe_realloc(void *x, size_t size) {
+ void *p = realloc(x, size);
+ if (x == NULL) {
+ die("abort: realloc()");
+ }
+ return p;
+}
+
+void alloc_zero(void *ptr, size_t size) { memset(ptr, 0, size); }
+
+void nothing(void *_) {}
diff --git a/src/common/opcodes.c b/src/common/opcodes.c
new file mode 100644
index 0000000..a489630
--- /dev/null
+++ b/src/common/opcodes.c
@@ -0,0 +1,20 @@
+#include <stdlib.h>
+#include "../include/opcodes.h"
+#include "../include/helpers.h"
+
+
+char *decode_client_opcode(int op) {
+ return "implement me";
+}
+
+char *decode_server_opcode(int op) {
+ return "implement me";
+}
+
+int encode_client_opcode(char *c) {
+ return -1;
+}
+
+int encode_server_opcode(char *c) {
+ return -1;
+}
diff --git a/src/common/tsv.c b/src/common/tsv.c
new file mode 100644
index 0000000..c06163b
--- /dev/null
+++ b/src/common/tsv.c
@@ -0,0 +1,32 @@
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "../include/tsv.h"
+#include "../include/helpers.h"
+#include "../include/better_string.h"
+
+tsv_t *init_tsv(char *source) {
+ tsv_t *tsv = safe_calloc(1, sizeof(tsv_t *));
+ tsv->source = source;
+ tsv->i = 0;
+ tsv->c = tsv->source[tsv->i];
+ return tsv;
+}
+
+void tsv_move(tsv_t *tsv) {
+ if (tsv->c != '\0') {
+ tsv->i++;
+ tsv->c = tsv->source[tsv->i];
+ }
+}
+
+string_t *tsv_next(tsv_t *tsv) {
+ string_t *s = init_string(NULL);
+ bool escape = false;
+ while (tsv->c != '\t' && !escape) {
+ if (tsv->c == '\0') break;
+ string_push(s, tsv->c);
+ tsv_move(tsv);
+ }
+ return s;
+}
diff --git a/src/include/array.h b/src/include/array.h
new file mode 100644
index 0000000..d3004e3
--- /dev/null
+++ b/src/include/array.h
@@ -0,0 +1,24 @@
+#ifndef ARRAY_H
+#define ARRAY_H
+
+#include <stdlib.h>
+#define DEFAULT_ARR_LEN 10
+
+typedef struct {
+ void **items;
+ size_t size;
+ size_t capacity;
+} array_t;
+
+array_t *init_array();
+
+void array_push(array_t *a, void *item);
+
+void *array_pop(array_t *a);
+
+void *array_del(array_t *a, unsigned int ind);
+
+void array_free(void *a, void (*freefunc)(void *));
+
+array_t *array_reverse(array_t *a);
+#endif
diff --git a/src/include/better_string.h b/src/include/better_string.h
new file mode 100644
index 0000000..41c0cfd
--- /dev/null
+++ b/src/include/better_string.h
@@ -0,0 +1,24 @@
+#ifndef STRING_H
+#define STRING_H
+
+#include <stdlib.h>
+#define DEFAULT_STR_SIZE 10
+
+typedef struct {
+ char *buf;
+ size_t len;
+ size_t size;
+} string_t;
+
+string_t *init_string(const char *source);
+
+void string_push(string_t *s, char c);
+
+void string_concat(string_t *s1, string_t *s2);
+
+void string_concat_const(string_t *s, const char *src);
+
+char string_pop(string_t *s);
+
+void string_free(void *s);
+#endif
diff --git a/src/include/hash_table.h b/src/include/hash_table.h
new file mode 100644
index 0000000..ea21e37
--- /dev/null
+++ b/src/include/hash_table.h
@@ -0,0 +1,43 @@
+#ifndef HASH_TABLE_H
+#define HASH_TABLE_H
+
+#include <stdlib.h>
+#define DEFAULT_HT_SIZE 500
+
+typedef struct PAIR_STRUCT {
+ char *key;
+ void *v;
+} pair_t;
+
+typedef struct NODE_STRUCT {
+ char *key;
+ void *v;
+ struct NODE_STRUCT *next;
+} node_t;
+
+typedef struct {
+ node_t *head;
+ node_t *tail;
+} sll_t;
+
+typedef struct {
+ sll_t **buckets;
+ size_t size;
+} ht_t;
+
+node_t *init_node(char *key, void *v);
+
+void sll_push(sll_t *sll, char *key, void *v);
+
+void sll_delete(sll_t *sll, char *key);
+
+sll_t *sll_free(void *x, void (*freefunc)(void *));
+
+void ht_insert(ht_t *ht, char *key, void *value);
+
+void ht_delete(ht_t *ht, char *key);
+
+void *ht_get(ht_t *ht, char *key);
+
+ht_t *init_ht(size_t size);
+#endif
diff --git a/src/include/helpers.h b/src/include/helpers.h
new file mode 100644
index 0000000..5d46909
--- /dev/null
+++ b/src/include/helpers.h
@@ -0,0 +1,17 @@
+#ifndef HELPERS_H
+#define HELPERS_H
+
+#include <stdlib.h>
+
+void die_lz(int code, const char *msg);
+
+void die(const char *msg);
+
+void *safe_calloc(unsigned int i, size_t size);
+
+void *safe_realloc(void *x, size_t size);
+
+void alloc_zero(void *ptr, size_t size);
+
+void nothing(void *);
+#endif
diff --git a/src/include/opcodes.h b/src/include/opcodes.h
new file mode 100644
index 0000000..ff8400f
--- /dev/null
+++ b/src/include/opcodes.h
@@ -0,0 +1,47 @@
+#ifndef OPCODES_H
+#define OPCODES_H
+
+typedef enum {
+ CO_NOP,
+ CO_JN, /* join */
+ CO_DM,
+ CO_PST, /* post */
+ CO_MSG,
+ CO_REG,
+ CO_NCK, /* nick */
+ CO_PNG, /* pong */
+ CO_LVE, /* leave */
+ CO_QT, /* quit*/
+
+ CO_CLM, /* claim channel */
+ CO_DESC, /* change description */
+ CO_TRSFR, /* ownership transfer of admin */
+ CO_KCK, /* kick */
+ CO_BAN,
+ CO_KNGT, /* knight */
+ CO_DMT, /* demote */
+
+ CO_LOGS, /* allows users to download log file from date specified in unix time */
+
+ CO_UNRECOGNIZED
+} copcode_t;
+
+typedef enum {
+ SO_SUCCESS,
+ SO_FAIL_PARSE,
+ SO_FAIL_NOPERM,
+ SO_FAIL_USER_TAKEN,
+ SO_FAIL_RATE, /* rate limit */
+ SO_PNG, /* ping */
+ SO_BYE,
+} sopcode_t;
+
+char *decode_client_opcode(int op);
+
+char *decode_server_opcode(int op);
+
+int encode_client_opcode(char *c);
+
+int encode_server_opcode(char *c);
+
+#endif
diff --git a/src/include/protocol.h b/src/include/protocol.h
new file mode 100644
index 0000000..204a507
--- /dev/null
+++ b/src/include/protocol.h
@@ -0,0 +1,68 @@
+#ifndef PROTOCOL_H
+#define PROTOCOL_H
+
+#include <time.h>
+#include <stdbool.h>
+
+#include "array.h"
+#include "better_string.h"
+#include "hash_table.h"
+#include <openssl/sha.h>
+
+#define MAX_OP_LEN 10
+#define MAX_ARG_LEN 50
+#define MAX_ARGS 5
+#define MAX_BUFSIZE 4096
+#define DEFAULT_PORT 11111
+#define MAX_CONNECTIONS 32768
+#define DEFAULT_TIMEOUT 6000
+#define USERNAME_SIZE 30
+#define KEYLEN 512
+
+typedef struct {
+ string_t *nick;
+ bool is_guest;
+ int fd;
+
+ /* list of channels where user is in */
+ array_t *channels;
+ array_t *dms;
+ array_t *autojoin;
+ unsigned char passhash[SHA256_DIGEST_LENGTH];
+} user_t;
+
+typedef struct {
+ string_t *nick;
+ string_t *msg;
+ time_t time;
+} message_t;
+
+typedef struct {
+ array_t *messages;
+
+ user_t *admin;
+ array_t *mods;
+
+ bool registered_only;
+
+ bool invite_only;
+ array_t *allowed_users;
+
+ array_t *users;
+
+ string_t *chan_name;
+ string_t *desc;
+} channel_t;
+
+typedef struct {
+ user_t *user1;
+ user_t *user2;
+
+ array_t *messages;
+} dm_t;
+
+string_t *encode_chanstate(ht_t *chans);
+
+string_t *encode_usersstate(ht_t *u);
+
+#endif
diff --git a/src/include/tsv.h b/src/include/tsv.h
new file mode 100644
index 0000000..57bb70a
--- /dev/null
+++ b/src/include/tsv.h
@@ -0,0 +1,16 @@
+#ifndef TSV_H
+#define TSV_H
+
+#include "better_string.h"
+
+typedef struct {
+ char *source;
+ unsigned int i;
+ char c;
+} tsv_t;
+
+tsv_t *init_tsv(char *source);
+
+string_t *tsv_next(tsv_t *tsv);
+
+#endif
diff --git a/src/msg/main.c b/src/msg/main.c
new file mode 100644
index 0000000..c13422d
--- /dev/null
+++ b/src/msg/main.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main(int argc, char **argv) {
+ printf("hello world!\n");
+ return 0;
+}
diff --git a/src/ramen/main.c b/src/ramen/main.c
new file mode 100644
index 0000000..e98b452
--- /dev/null
+++ b/src/ramen/main.c
@@ -0,0 +1,201 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "../include/tsv.h"
+#include "../include/array.h"
+#include "../include/better_string.h"
+#include "../include/hash_table.h"
+#include "../include/helpers.h"
+#include "../include/opcodes.h"
+#include "../include/protocol.h"
+
+int PORT = DEFAULT_PORT;
+int nfds = 1;
+struct pollfd fds[MAX_CONNECTIONS * 2];
+
+ht_t *USERS;
+ht_t *CHAN;
+
+void handle_sigint(int sig) {
+ for (int i = 0; i < nfds; i++) {
+ if (fds[i].fd >= 0) {
+ close(fds[i].fd);
+ }
+ }
+
+ exit(0);
+}
+
+array_t *parse_args(char *buf) {
+ tsv_t *tsv = init_tsv(buf);
+ string_t *s = tsv_next(tsv);
+ array_t *a = init_array();
+ while (s) {
+ array_push(a, s);
+ s = tsv_next(tsv);
+ }
+
+ a = array_reverse(a);
+ return a;
+}
+
+void set_non_blocking(int sock) {
+ int flags = fcntl(sock, F_GETFL, 0);
+ int code = fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+ die_lz(code, "fcntl()");
+}
+
+int main(int argc, char **argv) {
+ char buffer[MAX_BUFSIZE];
+ char res_buffer[MAX_BUFSIZE];
+ struct pollfd *local_fds1 = fds;
+ struct pollfd *local_fds2 = fds + MAX_CONNECTIONS;
+ struct pollfd *local_fds = local_fds1;
+
+ /* We start by initializing our net-related structs */
+ signal(SIGINT, handle_sigint);
+
+ int listen_sd = socket(AF_INET6, SOCK_STREAM, 0);
+ int optval = 1;
+ die_lz(listen_sd, "socket()");
+
+ int reuse = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval,
+ sizeof(optval));
+ die_lz(reuse, "setsockopt()");
+
+ int nonblock = ioctl(listen_sd, FIONBIO, (char *)&optval);
+ die_lz(nonblock, "ioctl()");
+
+ set_non_blocking(listen_sd);
+
+ /* Make new address */
+ struct sockaddr_in6 addr;
+ alloc_zero(&addr, sizeof(addr));
+
+ addr.sin6_family = AF_INET6;
+ memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
+ addr.sin6_port = htons(DEFAULT_PORT);
+
+ int sock_bind = bind(listen_sd, (struct sockaddr *)&addr, sizeof(addr));
+ die_lz(sock_bind, "bind()");
+
+ int sock_listen = listen(listen_sd, 32);
+ die_lz(sock_listen, "listen()");
+
+ /*
+ The first fd entry is the listening socket for new connections;
+ all the rest are sockets we read from and write to. Whenever a client
+ connects, we know from the listening socket.
+ */
+
+ alloc_zero(fds, sizeof(fds));
+ fds[0].fd = listen_sd;
+ fds[0].events = POLLIN;
+
+ int timeout = 6000;
+ int sock_poll;
+ bool end_server = false;
+
+ /* mainloop */
+ do {
+ bool compress_array = false;
+ /*
+ if an fd loses connection, we want to remove all -1's from the fds array
+ */
+
+ sock_poll = poll(local_fds, nfds, timeout);
+ die_lz(sock_poll, "poll()");
+
+ for (int i = 0; i < nfds; i++) {
+ if (local_fds[i].revents == 0)
+ continue;
+
+ if (local_fds[i].revents != POLLIN) {
+ end_server = true;
+ break;
+ }
+
+ if (local_fds[i].fd == listen_sd) {
+ printf("socket is readable\n");
+ int new_sd;
+
+ do {
+ new_sd = accept(listen_sd, NULL, NULL);
+
+ if (new_sd < 0 && errno != EWOULDBLOCK) {
+ perror("accept() failed");
+ end_server = true;
+ break;
+ }
+
+ local_fds[nfds].fd = new_sd;
+ local_fds[nfds].events = POLLIN;
+ nfds++;
+ } while (new_sd >= 0);
+ } else {
+ bool close_conn = false;
+ int fd_recv;
+ int fd_send;
+ fd_recv = recv(local_fds[i].fd, buffer, sizeof(buffer), 0);
+
+ if (fd_recv < 0 && errno != EWOULDBLOCK) {
+ perror("recv() failed");
+ close_conn = true;
+ } else if (fd_recv == 0) {
+ printf("Connection closed\n");
+ close_conn = true;
+ } else {
+ /* echo server -- replace this with buffer parsing */
+ /* TODO: reply to client based on user input */
+ fd_send = send(local_fds[i].fd, buffer, fd_recv, 0);
+ if (fd_send < 0) {
+ perror("send()");
+ close_conn = true;
+ }
+ }
+
+ if (close_conn) {
+ close(local_fds[i].fd);
+ local_fds[i].fd = 0;
+ compress_array = true;
+ }
+ }
+ }
+
+ if (compress_array) {
+ printf("switching...\n");
+ int cur_nfds = nfds;
+ nfds = 0;
+ for (int i = 0; i < cur_nfds; i++) {
+ if (local_fds[i].fd != 0) {
+ local_fds2[nfds] = local_fds[i];
+ nfds ++;
+ }
+ }
+
+ local_fds1 = local_fds2;
+ local_fds2 = local_fds;
+ local_fds = local_fds1;
+ alloc_zero(local_fds2, MAX_CONNECTIONS);
+ }
+ } while (!end_server);
+
+ for (int i = 0; i < nfds; i++) {
+ if (fds[i].fd >= 0) {
+ close(fds[i].fd);
+ }
+ }
+
+ return 0;
+}