From 1fd608288ee47c2c560817f12f14b21069fed2f6 Mon Sep 17 00:00:00 2001 From: Preston Pan Date: Sat, 28 Dec 2024 16:47:43 -0800 Subject: makefile and directory structure change completely to build client and server --- .gitignore | 2 + Makefile | 53 ++++++----- client/main.c | 6 -- flake.nix | 5 +- include/array.h | 23 ----- include/better_string.h | 23 ----- include/hash_table.h | 43 --------- include/helpers.h | 15 ---- include/opcodes.h | 47 ---------- include/protocol.h | 68 -------------- include/tsv.h | 16 ---- server/array.c | 37 -------- server/better_string.c | 51 ----------- server/hash_table.c | 11 --- server/helpers.c | 34 ------- server/main.c | 215 -------------------------------------------- server/opcodes.c | 20 ----- server/tsv.c | 32 ------- src/common/array.c | 47 ++++++++++ src/common/better_string.c | 51 +++++++++++ src/common/hash_table.c | 12 +++ src/common/helpers.c | 36 ++++++++ src/common/opcodes.c | 20 +++++ src/common/tsv.c | 32 +++++++ src/include/array.h | 24 +++++ src/include/better_string.h | 24 +++++ src/include/hash_table.h | 43 +++++++++ src/include/helpers.h | 17 ++++ src/include/opcodes.h | 47 ++++++++++ src/include/protocol.h | 68 ++++++++++++++ src/include/tsv.h | 16 ++++ src/msg/main.c | 6 ++ src/ramen/main.c | 201 +++++++++++++++++++++++++++++++++++++++++ 33 files changed, 680 insertions(+), 665 deletions(-) delete mode 100644 client/main.c delete mode 100644 include/array.h delete mode 100644 include/better_string.h delete mode 100644 include/hash_table.h delete mode 100644 include/helpers.h delete mode 100644 include/opcodes.h delete mode 100644 include/protocol.h delete mode 100644 include/tsv.h delete mode 100644 server/array.c delete mode 100644 server/better_string.c delete mode 100644 server/hash_table.c delete mode 100644 server/helpers.c delete mode 100644 server/main.c delete mode 100644 server/opcodes.c delete mode 100644 server/tsv.c create mode 100644 src/common/array.c create mode 100644 src/common/better_string.c create mode 100644 src/common/hash_table.c create mode 100644 src/common/helpers.c create mode 100644 src/common/opcodes.c create mode 100644 src/common/tsv.c create mode 100644 src/include/array.h create mode 100644 src/include/better_string.h create mode 100644 src/include/hash_table.h create mode 100644 src/include/helpers.h create mode 100644 src/include/opcodes.h create mode 100644 src/include/protocol.h create mode 100644 src/include/tsv.h create mode 100644 src/msg/main.c create mode 100644 src/ramen/main.c diff --git a/.gitignore b/.gitignore index 119911e..18c1494 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ obj/** +msg_obj/** +ramen_obj/** bin/** .cache/** result/** diff --git a/Makefile b/Makefile index 4b60314..287a5d8 100644 --- a/Makefile +++ b/Makefile @@ -1,43 +1,54 @@ -SERVER_DIR := server -CLIENT_DIR := client -OBJ_DIR := server_obj -CLIENT_OBJ_DIR := client_obj +SRC_DIR := src/common +OBJ_DIR := obj +RAMEN_OBJ_DIR := ramen_obj +MSG_OBJ_DIR := msg_obj BIN_DIR := bin -EXE := $(BIN_DIR)/umami -CLIENT_EXE = $(BIN_DIR)/client +RAMEN_DIR := src/ramen +MSG_DIR := src/msg -SRC := $(wildcard $(SERVER_DIR)/*.c) -OBJ := $(SRC:$(SERVER_DIR)/%.c=$(OBJ_DIR)/%.o) +RAMEN_EXE := $(BIN_DIR)/ramen +MSG_EXE := $(BIN_DIR)/msg -CLIENT_SRC := $(wildcard $(CLIENT_DIR/*.c)) -CLIENT_OBJ := $(CLIENT_SRC:$(CLIENT_DIR)/%.c=$(OBJ_DIR)/%.o) - -CFLAGS := -Wall -Iinclude -lcrypto -lssl -LDFLAGS := -Llib -LDLIBS := -lm +SRC := $(wildcard $(SRC_DIR)/*.c) +OBJ := $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o) +CFLAGS := -Wall -lcrypto -lssl CFLAGS += $(NIX_CFLAGS_COMPILE) + +RAMEN_SRC := $(wildcard $(RAMEN_DIR)/*.c) +RAMEN_OBJ := $(RAMEN_SRC:$(RAMEN_DIR)/%.c=$(RAMEN_OBJ_DIR)/%.o) + +MSG_SRC := $(wildcard $(MSG_DIR)/*.c) +MSG_OBJ := $(MSG_SRC:$(MSG_DIR)/%.c=$(MSG_OBJ_DIR)/%.o) + +LDFLAGS := +LDLIBS := +LDFLAGS += $(NIX_LDFLAGS_COMPILE) + .PHONY: all clean -all: $(EXE) $(CLIENT_EXE) +all: $(RAMEN_EXE) $(MSG_EXE) -$(EXE): $(OBJ) | $(BIN_DIR) +$(RAMEN_EXE): $(OBJ) $(RAMEN_OBJ) | $(BIN_DIR) $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ -$(CLIENT_EXE): $(CLIENT_OBJ) | $(BIN_DIR) +$(RAMEN_OBJ_DIR)/%.o: $(RAMEN_DIR)/%.c | $(RAMEN_OBJ_DIR) + $(CC) $(CFLAGS) -c $< -o $@ + +$(MSG_EXE): $(OBJ) $(MSG_OBJ) | $(BIN_DIR) $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ -$(OBJ_DIR)/%.o: $(SERVER_DIR)/%.c | $(OBJ_DIR) +$(MSG_OBJ_DIR)/%.o: $(MSG_DIR)/%.c | $(MSG_OBJ_DIR) $(CC) $(CFLAGS) -c $< -o $@ -$(CLIENT_OBJ_DIR)/%.o: $(CLIENT_DIR)/%.c | $(CLIENT_OBJ_DIR) +$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR) $(CC) $(CFLAGS) -c $< -o $@ -$(BIN_DIR) $(OBJ_DIR): +$(BIN_DIR) $(OBJ_DIR) $(MSG_OBJ_DIR) $(RAMEN_OBJ_DIR): mkdir -p $@ clean: - @$(RM) -rv $(BIN_DIR) $(OBJ_DIR) result + @$(RM) -rv $(BIN_DIR) $(OBJ_DIR) $(MSG_OBJ_DIR) $(RAMEN_OBJ_DIR) result -include $(OBJ:.o=.d) diff --git a/client/main.c b/client/main.c deleted file mode 100644 index 3587a00..0000000 --- a/client/main.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main(int argc, char **argv) { - printf("HELLO WORLD\n"); - return 0; -} diff --git a/flake.nix b/flake.nix index 356cd73..707e97f 100644 --- a/flake.nix +++ b/flake.nix @@ -23,9 +23,8 @@ buildPhase = "make"; installPhase = '' - mkdir -p $out/bin - cp ./bin/umami $out/bin/ - cp ./bin/client $out/bin/ + mkdir -p $out + cp -r bin/ $out/ ''; }; }; diff --git a/include/array.h b/include/array.h deleted file mode 100644 index 948dad2..0000000 --- a/include/array.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef ARRAY_H -#define ARRAY_H - -#include -#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 *)); - -#endif diff --git a/include/better_string.h b/include/better_string.h deleted file mode 100644 index a5f9954..0000000 --- a/include/better_string.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef STRING_H -#define STRING_H - -#include -#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/include/hash_table.h b/include/hash_table.h deleted file mode 100644 index 357e38a..0000000 --- a/include/hash_table.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef HASH_TABLE_H -#define HASH_TABLE_H -#include - -#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/include/helpers.h b/include/helpers.h deleted file mode 100644 index 276b590..0000000 --- a/include/helpers.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef HELPERS_H -#define HELPERS_H - -#include - -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); -#endif diff --git a/include/opcodes.h b/include/opcodes.h deleted file mode 100644 index ff8400f..0000000 --- a/include/opcodes.h +++ /dev/null @@ -1,47 +0,0 @@ -#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/include/protocol.h b/include/protocol.h deleted file mode 100644 index 16ba818..0000000 --- a/include/protocol.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef PROTOCOL_H -#define PROTOCOL_H - -#include -#include - -#include -#include -#include -#include - -#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/include/tsv.h b/include/tsv.h deleted file mode 100644 index 5f6a9f6..0000000 --- a/include/tsv.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef TSV_H -#define TSV_H - -#include - -typedef struct { - char *source; - unsigned int i; - char c; -} tsv_t; - -tsv_t *init_tsv(char *source); - -string_t *next_tsv(tsv_t *tsv); - -#endif diff --git a/server/array.c b/server/array.c deleted file mode 100644 index 84ed938..0000000 --- a/server/array.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include - -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; -} - -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/server/better_string.c b/server/better_string.c deleted file mode 100644 index 4413f77..0000000 --- a/server/better_string.c +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#include -#include - -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/server/hash_table.c b/server/hash_table.c deleted file mode 100644 index cced194..0000000 --- a/server/hash_table.c +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include -#include - -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/server/helpers.c b/server/helpers.c deleted file mode 100644 index 8485dc6..0000000 --- a/server/helpers.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include -#include - -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); } diff --git a/server/main.c b/server/main.c deleted file mode 100644 index 7a17966..0000000 --- a/server/main.c +++ /dev/null @@ -1,215 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -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); -} - -/* modifying function: modifies `in` to point to new location after opcode */ -int parse_op(char *in) { - char buf[MAX_OP_LEN]; - buf[0] = '\0'; - - char cur; - cur = in[0]; - - bool found = false; - for (int i = 0; i < 11; i++) { - if (cur == '\t') { - found = true; - in++; - break; - } else if (cur == '\0') { - break; - } - - buf[i] = in[0]; - in++; - cur = in[0]; - } - - return found ? encode_client_opcode(buf) : CO_UNRECOGNIZED; -} - -array_t *parse_args(char *buf) { return NULL; } - -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; -} diff --git a/server/opcodes.c b/server/opcodes.c deleted file mode 100644 index 8fc51f2..0000000 --- a/server/opcodes.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include -#include - - -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/server/tsv.c b/server/tsv.c deleted file mode 100644 index 9b1c2be..0000000 --- a/server/tsv.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -#include -#include -#include - -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/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 + +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 +#include + +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 + +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 +#include +#include + +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 +#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 +#include + +#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 +#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 +#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 +#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 + +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 +#include + +#include "array.h" +#include "better_string.h" +#include "hash_table.h" +#include + +#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 + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} -- cgit