diff options
author | Preston Pan <ret2pop@gmail.com> | 2025-01-30 21:02:42 -0800 |
---|---|---|
committer | Preston Pan <ret2pop@gmail.com> | 2025-01-30 21:02:42 -0800 |
commit | 3780f207f924f14734cb839fd015bd883fe52ff1 (patch) | |
tree | de13568dbf97ffe477943854bcb3ea6001b46cf8 | |
parent | ef9ab1fd141f4057d41f2d6ed8ab8d67c44894d5 (diff) |
-rw-r--r-- | src/common/better_string.c | 15 | ||||
-rw-r--r-- | src/common/bsv.c | 33 | ||||
-rw-r--r-- | src/common/hash_table.c | 19 | ||||
-rw-r--r-- | src/common/protocol.c | 20 | ||||
-rw-r--r-- | src/common/stdobj.c | 12 | ||||
-rw-r--r-- | src/common/tsv.c | 33 | ||||
-rw-r--r-- | src/include/better_string.h | 7 | ||||
-rw-r--r-- | src/include/bsv.h | 21 | ||||
-rw-r--r-- | src/include/hash_table.h | 31 | ||||
-rw-r--r-- | src/include/list.h | 1 | ||||
-rw-r--r-- | src/include/protocol.h | 98 | ||||
-rw-r--r-- | src/include/stdobj.h | 8 | ||||
-rw-r--r-- | src/include/tsv.h | 16 | ||||
-rw-r--r-- | src/ramen/main.c | 102 | ||||
-rw-r--r-- | src/ramen/protocol.c | 49 |
15 files changed, 321 insertions, 144 deletions
diff --git a/src/common/better_string.c b/src/common/better_string.c index 7863da0..0788aab 100644 --- a/src/common/better_string.c +++ b/src/common/better_string.c @@ -1,6 +1,7 @@ #include "../include/better_string.h" #include "../include/helpers.h" #include <stdlib.h> +#include <stdbool.h> #include <string.h> string_t *init_string(const char *src) { @@ -17,6 +18,16 @@ string_t *init_string(const char *src) { return s; } +string_t *string_copy(string_t *s) { + return init_string(s->buf); +} + +char *string_copy_raw(string_t *s) { + char *raw = calloc(s->len + 1, sizeof(char)); + strncpy(raw, s->buf, s->len); + return raw; +} + void string_push(string_t *s, char c) { if (s->len >= s->size - 3) { s->size *= 2; @@ -44,6 +55,10 @@ void string_concat(string_t *s1, string_t *s2) { } } +bool string_cmp(string_t *s1, string_t *s2) { + return strcmp(s1->buf, s2->buf) == 0; +} + void string_free(void *x) { string_t *s = x; diff --git a/src/common/bsv.c b/src/common/bsv.c new file mode 100644 index 0000000..4a3d000 --- /dev/null +++ b/src/common/bsv.c @@ -0,0 +1,33 @@ +#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, char delim) { + tsv_t *tsv = safe_calloc(1, sizeof(tsv_t *)); + tsv->source = source; + tsv->i = 0; + tsv->c = tsv->source[tsv->i]; + tsv->delim = delim; + 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 != tsv->delim && !escape) { + if (tsv->c == '\0') break; + string_push(s, tsv->c); + tsv_move(tsv); + } + return s; +} diff --git a/src/common/hash_table.c b/src/common/hash_table.c index 6b4c014..caefae6 100644 --- a/src/common/hash_table.c +++ b/src/common/hash_table.c @@ -111,6 +111,17 @@ void ht_insert(ht_t *ht, char *key, void *value) { list_push_back(bucket, init_pair(key, value)); } +void *ht_modify(ht_t *ht, char *key, void *newval) { + void *oldval = ht_pop(ht, key); + ht_insert(ht, key, newval); + return oldval; +} + +void ht_overwrite(ht_t *ht, char *key, void *newval, void (*freefunc)(void *)) { + void *oldval = ht_modify(ht, key, newval); + freefunc(oldval); +} + void *ht_pop(ht_t *ht, char *key) { unsigned long bn = hash(key) % ht->size; list_t *bucket = ht->buckets[bn]; @@ -136,6 +147,14 @@ void ht_free(void *x, void (*freefunc)(void *)) { free(ht); } +ht_t *init_map(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(list_t *)); + ht->is_map = true; + return ht; +} + /* DJB2 hash function */ unsigned long hash(char *str) { unsigned long hash = 5381; diff --git a/src/common/protocol.c b/src/common/protocol.c deleted file mode 100644 index 9be3bcf..0000000 --- a/src/common/protocol.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "../include/protocol.h" -#include "../include/better_string.h" - -#include <stdlib.h> -#include <stdbool.h> -#include <time.h> - -string_t *date_str() { - char dateStr[11]; - time_t t = time(NULL); - struct tm *tm_info = localtime(&t); - - strftime(dateStr, sizeof(dateStr), "%d-%m-%Y", tm_info); - return init_string(dateStr); -} - -bool same_day(struct tm *date1, struct tm *date2) { - return (date1->tm_year == date2->tm_year && date1->tm_mon == date2->tm_mon && - date1->tm_mday == date2->tm_mday); -} diff --git a/src/common/stdobj.c b/src/common/stdobj.c new file mode 100644 index 0000000..c7657ed --- /dev/null +++ b/src/common/stdobj.c @@ -0,0 +1,12 @@ +#include "../include/stdobj.h" +#include "../include/better_string.h" +#include <stdbool.h> +#include <stdlib.h> + +bool array_in(array_t *a, string_t *s) { + for (int i = 0; i < a->size; i++) { + if (string_cmp(a->items[i], s)) + return true; + } + return false; +} diff --git a/src/common/tsv.c b/src/common/tsv.c index c06163b..290dc43 100644 --- a/src/common/tsv.c +++ b/src/common/tsv.c @@ -1,32 +1,33 @@ #include <stdlib.h> #include <stdbool.h> -#include "../include/tsv.h" +#include "../include/bsv.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; +bsv_t *init_bsv(char *source, char delim) { + bsv_t *bsv = safe_calloc(1, sizeof(bsv_t *)); + bsv->source = source; + bsv->i = 0; + bsv->c = bsv->source[bsv->i]; + bsv->delim = delim; + return bsv; } -void tsv_move(tsv_t *tsv) { - if (tsv->c != '\0') { - tsv->i++; - tsv->c = tsv->source[tsv->i]; +void bsv_move(bsv_t *bsv) { + if (bsv->c != '\0') { + bsv->i++; + bsv->c = bsv->source[bsv->i]; } } -string_t *tsv_next(tsv_t *tsv) { +string_t *bsv_next(bsv_t *bsv) { 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); + while (bsv->c != bsv->delim && !escape) { + if (bsv->c == '\0') break; + string_push(s, bsv->c); + bsv_move(bsv); } return s; } diff --git a/src/include/better_string.h b/src/include/better_string.h index 0fdc8bd..4fc4315 100644 --- a/src/include/better_string.h +++ b/src/include/better_string.h @@ -2,6 +2,7 @@ #define STRING_H #include <stdlib.h> +#include <stdbool.h> #define DEFAULT_STR_SIZE 10 typedef struct { @@ -12,6 +13,10 @@ typedef struct { string_t *init_string(const char *source); +string_t *string_copy(string_t *s); + +char *string_copy_raw(string_t *s); + void string_push(string_t *s, char c); void string_concat(string_t *s1, string_t *s2); @@ -20,6 +25,8 @@ void string_concat_const(string_t *s, const char *src); char string_pop(string_t *s); +bool string_cmp(string_t *s1, string_t *s2); + void string_free(void *s); #endif diff --git a/src/include/bsv.h b/src/include/bsv.h new file mode 100644 index 0000000..dd8206d --- /dev/null +++ b/src/include/bsv.h @@ -0,0 +1,21 @@ +#ifndef BSV_H +#define BSV_H + +#include "better_string.h" + +/*! @brief State for byte delimited values */ +typedef struct BSV_STRUCT { + /*! @brief the source bsv separated list */ + char *source; + /*! @brief current index */ + unsigned int i; + char c; + char delim; +} bsv_t; + +/*! @brief Initializes memory for new bsv struct */ +bsv_t *init_bsv(char *source, char delim); + +/*! @brief get the next byte delimited token */ +string_t *bsv_next(bsv_t *bsv); +#endif diff --git a/src/include/hash_table.h b/src/include/hash_table.h index 8f19635..55136ba 100644 --- a/src/include/hash_table.h +++ b/src/include/hash_table.h @@ -2,16 +2,21 @@ #define HASH_TABLE_H #include "list.h" #include <stdlib.h> + #define DEFAULT_HT_SIZE 500 typedef struct PAIR_STRUCT { - char *key; + union { + char *key; + int ikey; + }; void *v; } pair_t; typedef struct { list_t **buckets; size_t size; + bool is_map; } ht_t; pair_t *init_pair(char *key, void *value); @@ -22,10 +27,34 @@ void *bucket_pop(list_t *b, char *key); void bucket_free(void *x, void (*freefunc)(void *)); +pair_t *init_long_pair(unsigned long key, void *value); + +void *bucket_get_by_long(list_t *b, unsigned long key); + +void *bucket_pop_by_long(list_t *b, unsigned long key); + +void bucket_free_with_long(void *x, void (*freefunc)(void *)); + ht_t *init_ht(size_t size); +ht_t *init_map(size_t size); + +void map_insert(ht_t *ht, unsigned long key, void *value); + +void *map_pop(ht_t *ht, unsigned long key); + +void *map_get(ht_t *ht, unsigned long key); + +void map_free(void *x); + void ht_insert(ht_t *ht, char *key, void *value); +/*! @brief returns the old value, mutates ht state with new value */ +void *ht_modify(ht_t *ht, char *key, void *newval); + +/*! @brief overwrites old value with new value while freeing the old */ +void ht_overwrite(ht_t *ht, char *key, void *newval, void (*freefunc)(void *)); + void *ht_pop(ht_t *ht, char *key); void *ht_get(ht_t *ht, char *key); diff --git a/src/include/list.h b/src/include/list.h index 055106a..a9d1539 100644 --- a/src/include/list.h +++ b/src/include/list.h @@ -13,6 +13,7 @@ typedef struct { size_t size; node_t *head; node_t *tail; + bool type; } list_t; node_t *init_node(void *item); diff --git a/src/include/protocol.h b/src/include/protocol.h index 31138c2..958ba26 100644 --- a/src/include/protocol.h +++ b/src/include/protocol.h @@ -1,9 +1,8 @@ #ifndef PROTOCOL_H #define PROTOCOL_H - -#include <time.h> -#include <stdio.h> #include <stdbool.h> +#include <stdio.h> +#include <time.h> #include "array.h" #include "better_string.h" @@ -21,48 +20,80 @@ #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 *friends; + /* if NULL then guest */ + unsigned char *passhash; array_t *autojoin; - unsigned char passhash[SHA256_DIGEST_LENGTH]; -} user_t; + array_t *dms; + string_t *name; +} account_t; typedef struct { + /*! @brief nick who sent the message */ string_t *nick; + /*! @brief message content */ string_t *msg; + /*! @brief Unix time */ time_t time; } message_t; -typedef struct { - FILE *messages; - - user_t *admin; +/*! @brief describes multiple user chats */ +typedef struct CHANNEL_STRUCT { + account_t *admin; + /*! @brief account_t array */ array_t *mods; - + /*! @brief No guests */ bool registered_only; - - bool invite_only; + /*! @brief account_t array + * if set, allowed_users creates a private conversation with only + * these users + */ array_t *allowed_users; - + /*! @brief Explicitly banned users, account_t array */ + array_t *banned_users; + /*! @brief account_t array */ array_t *users; - - string_t *chan_name; + /*! @brief Description of channel can be set after creation */ string_t *desc; + /*! @brief message logs */ + array_t *msgs; } channel_t; -typedef struct { - user_t *user1; - user_t *user2; - - struct tm *date; - FILE *msgs; +/*! @brief struct that contains DM */ +typedef struct DM_STRUCT { + account_t *src; + array_t *msgs; } dm_t; +typedef struct SERVER_STRUCT server_t; + +/*! @brief wrapper for server handler that conforms to C spec */ +typedef struct SFUNC_STRUCT { + /*! @brief In C spec, function pointers are not the same size as regular pointers */ + void (*f)(server_t *, list_t *); +} sfunc_t; + +/*! @brief Server state encapsulation */ +struct SERVER_STRUCT { + /*! @brief account name => user_t */ + ht_t *accmap; + /*! @brief username => user_t */ + ht_t *usermap; + /*! @brief account name => friends */ + ht_t *friendmap; + /*! @brief fd (int) => string_t */ + ht_t *fdmap; + /*! @brief channel name => channel_t */ + ht_t *chanmap; + + /*! @brief op name => sfunc_t */ + ht_t *opmap; + + struct pollfd *fds; + int nfds; + size_t fd_capacity; +}; + string_t *date_str(); bool same_day(struct tm *date1, struct tm *date2); @@ -71,4 +102,15 @@ string_t *encode_chanstate(ht_t *chans); string_t *encode_usersstate(ht_t *u); +message_t *init_message(string_t *nick, string_t *msg, time_t time); + +void cop_ok(server_t *s, list_t *args); + +void cop_nop(server_t *s, list_t *args); + +server_t *init_server(size_t size); + +void server_addop(server_t *s, void (*sfunc)(server_t *s, list_t *args)); + +void server_execop(server_t *s, list_t *stk); #endif diff --git a/src/include/stdobj.h b/src/include/stdobj.h new file mode 100644 index 0000000..d755637 --- /dev/null +++ b/src/include/stdobj.h @@ -0,0 +1,8 @@ +#ifndef STDOBJ_H +#define STDOBJ_H +#include <stdbool.h> +#include "array.h" +#include "better_string.h" + +bool array_in(array_t *a, string_t *s); +#endif diff --git a/src/include/tsv.h b/src/include/tsv.h deleted file mode 100644 index 57bb70a..0000000 --- a/src/include/tsv.h +++ /dev/null @@ -1,16 +0,0 @@ -#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/ramen/main.c b/src/ramen/main.c index 799a5b2..86a4d2c 100644 --- a/src/ramen/main.c +++ b/src/ramen/main.c @@ -12,39 +12,32 @@ #include <sys/time.h> #include <unistd.h> +#include "../include/stdobj.h" #include "../include/better_string.h" #include "../include/hash_table.h" #include "../include/helpers.h" #include "../include/list.h" #include "../include/opcodes.h" #include "../include/protocol.h" -#include "../include/tsv.h" +#include "../include/bsv.h" #include "../include/opcodes.h" int PORT = DEFAULT_PORT; -int nfds = 1; -struct pollfd fds[MAX_CONNECTIONS * 2]; -ht_t *CHAN; -ht_t *USERS; +server_t *STATE; void handle_sigint(int sig) { - for (int i = 0; i < nfds; i++) { - if (fds[i].fd >= 0) { - close(fds[i].fd); - } - } exit(0); } list_t *tokenize_buf(char *buf) { - tsv_t *tsv = init_tsv(buf); - string_t *s = tsv_next(tsv); + bsv_t *bsv = init_bsv(buf, '\t'); + string_t *s = bsv_next(bsv); list_t *a = init_list(); while (s) { list_push_back(a, s); - s = tsv_next(tsv); + s = bsv_next(bsv); } return a; @@ -59,9 +52,9 @@ void set_non_blocking(int sock) { 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; + STATE = init_server(1000); + struct pollfd *local_fds1 = STATE->fds; + struct pollfd *local_fds2 = STATE->fds + MAX_CONNECTIONS; /* We start by initializing our net-related structs */ signal(SIGINT, handle_sigint); @@ -99,9 +92,9 @@ int main(int argc, char **argv) { connects, we know from the listening socket. */ - alloc_zero(fds, sizeof(fds)); - fds[0].fd = listen_sd; - fds[0].events = POLLIN; + alloc_zero(STATE->fds, 2 * MAX_BUFSIZE * sizeof(struct pollfd)); + STATE->fds[0].fd = listen_sd; + STATE->fds[0].events = POLLIN; int timeout = 6000; int sock_poll; @@ -114,19 +107,19 @@ int main(int argc, char **argv) { if an fd loses connection, we want to remove all -1's from the fds array */ - sock_poll = poll(local_fds, nfds, timeout); + sock_poll = poll(STATE->fds, STATE->nfds, timeout); die_lz(sock_poll, "poll()"); - for (int i = 0; i < nfds; i++) { - if (local_fds[i].revents == 0) + for (int i = 0; i < STATE->nfds; i++) { + if (STATE->fds[i].revents == 0) continue; - if (local_fds[i].revents != POLLIN) { + if (STATE->fds[i].revents != POLLIN) { end_server = true; break; } - if (local_fds[i].fd == listen_sd) { + if (STATE->fds[i].fd == listen_sd) { printf("socket is readable\n"); int new_sd; @@ -139,15 +132,18 @@ int main(int argc, char **argv) { break; } - local_fds[nfds].fd = new_sd; - local_fds[nfds].events = POLLIN; - nfds++; + STATE->fds[STATE->nfds].fd = new_sd; + STATE->fds[STATE->nfds].events = POLLIN; + STATE->nfds++; + /* TODO: Create new user */ + + /* TODO: add new user to maps */ } 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); + fd_recv = recv(STATE->fds[i].fd, buffer, sizeof(buffer), 0); if (fd_recv < 0 && errno != EWOULDBLOCK) { perror("recv() failed"); @@ -157,29 +153,9 @@ int main(int argc, char **argv) { close_conn = true; } else { list_t *tokens = tokenize_buf(buffer); - string_t *opcode = list_pop_front(tokens); - int op = encode_server_opcode(opcode->buf); - - switch (op) { - case CO_NCK: - break; - case CO_JN: - break; - case CO_NOP: - break; - case CO_PST: - break; - case CO_DM: - break; - case CO_QT: - break; - case CO_LVE: - break; - default: - break; - } - - fd_send = send(local_fds[i].fd, buffer, fd_recv, 0); + server_execop(STATE, tokens); + /* TODO: correct reciept */ + fd_send = send(STATE->fds[i].fd, buffer, fd_recv, 0); if (fd_send < 0) { perror("send()"); close_conn = true; @@ -187,33 +163,33 @@ int main(int argc, char **argv) { } if (close_conn) { - close(local_fds[i].fd); - local_fds[i].fd = 0; + close(STATE->fds[i].fd); + STATE->fds[i].fd = 0; compress_array = true; } } } if (compress_array) { - int cur_nfds = nfds; - nfds = 0; + int cur_nfds = STATE->nfds; + STATE->nfds = 0; for (int i = 0; i < cur_nfds; i++) { - if (local_fds[i].fd != 0) { - local_fds2[nfds] = local_fds[i]; - nfds++; + if (STATE->fds[i].fd != 0) { + local_fds2[STATE->nfds] = STATE->fds[i]; + STATE->nfds++; } } local_fds1 = local_fds2; - local_fds2 = local_fds; - local_fds = local_fds1; + local_fds2 = STATE->fds; + STATE->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); + for (int i = 0; i < STATE->nfds; i++) { + if (STATE->fds[i].fd >= 0) { + close(STATE->fds[i].fd); } } diff --git a/src/ramen/protocol.c b/src/ramen/protocol.c new file mode 100644 index 0000000..eea5da2 --- /dev/null +++ b/src/ramen/protocol.c @@ -0,0 +1,49 @@ +#include "../include/protocol.h" +#include "../include/better_string.h" +#include "../include/helpers.h" + +#include <stdbool.h> +#include <stdlib.h> +#include <time.h> + +extern int GUESTS; + +string_t *date_str() { + char dateStr[11]; + time_t t = time(NULL); + struct tm *tm_info = localtime(&t); + + strftime(dateStr, sizeof(dateStr), "%d-%m-%Y", tm_info); + return init_string(dateStr); +} + +bool same_day(struct tm *date1, struct tm *date2) { + return (date1->tm_year == date2->tm_year && date1->tm_mon == date2->tm_mon && + date1->tm_mday == date2->tm_mday); +} + +user_t *init_user(int fd) { + char buf[20]; + user_t *user = safe_calloc(1, sizeof(user_t)); + string_t *nick = init_string("guest"); + GUESTS++; + snprintf(buf, 20, "%d", GUESTS); + string_concat_const(nick, buf); + user->is_guest = true; + user->autojoin = NULL; + user->dms = NULL; + return user; +} + +server_t *init_server(size_t size) { + server_t *s = safe_calloc(1, sizeof(server_t)); + s->accmap = init_ht(size); + s->chanmap = init_ht(size); + s->fdmap = init_ht(size); + s->friendmap = init_ht(size); + s->opmap = init_ht(size); + s->usermap = init_ht(size); + s->fds = NULL; + s->nfds = 4096; + return s; +} |