diff options
| author | Franklin Wei <git@fwei.tk> | 2016-01-13 18:08:52 -0500 |
|---|---|---|
| committer | Franklin Wei <git@fwei.tk> | 2016-01-13 18:08:52 -0500 |
| commit | cc9c177672edcc65933b15ba91831bf09bbec023 (patch) | |
| tree | 1f717027c56e92acaecf2ccf581c83d979b9a461 | |
| parent | 06880048df2202b1828e5367b1697aee305a2358 (diff) | |
| download | netcosm-0.2.zip netcosm-0.2.tar.gz netcosm-0.2.tar.bz2 netcosm-0.2.tar.xz | |
rewrite everything to use libev0.2
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | src/auth.c | 3 | ||||
| -rw-r--r-- | src/auth.h | 5 | ||||
| -rw-r--r-- | src/child_reqs.h | 12 | ||||
| -rw-r--r-- | src/client.c | 18 | ||||
| -rw-r--r-- | src/hash.c | 16 | ||||
| -rw-r--r-- | src/hash.h | 16 | ||||
| -rw-r--r-- | src/netcosm.h | 51 | ||||
| -rw-r--r-- | src/room.c | 2 | ||||
| -rw-r--r-- | src/server.c | 264 | ||||
| -rw-r--r-- | src/server_reqs.c | 21 | ||||
| -rw-r--r-- | src/telnet.c | 6 | ||||
| -rw-r--r-- | src/telnet.h | 10 | ||||
| -rw-r--r-- | src/userdb.c | 58 | ||||
| -rw-r--r-- | src/userdb.h | 16 | ||||
| -rw-r--r-- | src/util.c | 28 |
16 files changed, 302 insertions, 228 deletions
@@ -5,8 +5,8 @@ PLATFORM = unix NETCOSM_SRC = $(shell cat SOURCES) NETCOSM_OBJ := $(NETCOSM_SRC:.c=.o) -CFLAGS = -Og -g -I src/ -I target/$(PLATFORM) -Wall -Wextra -Wshadow -LDFLAGS = -lgcrypt +CFLAGS = -O3 -g -I src/ -I target/$(PLATFORM) -Wall -Wextra -Wshadow -std=gnu99 +LDFLAGS = -lgcrypt -lev HEADERS = src/netcosm.h src/hash.h src/telnet.h src/userdb.h @@ -183,6 +183,9 @@ struct userdata_t *auth_check(const char *name2, const char *pass2) /* find it in the user list */ struct userdata_t *data = userdb_request_lookup(name); + + free(name); + char *salt = data->salt, *hash = data->passhash; if(data) @@ -16,8 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _AUTH_H_ -#define _AUTH_H_ +#pragma once #define SALT_LEN 12 #define ALGO GCRY_MD_SHA512 @@ -42,5 +41,3 @@ bool auth_user_del(const char *user); /* lists users through out() */ void auth_user_list(void); - -#endif diff --git a/src/child_reqs.h b/src/child_reqs.h deleted file mode 100644 index db3257a..0000000 --- a/src/child_reqs.h +++ /dev/null @@ -1,12 +0,0 @@ -/* functions allowing a child process to send its master requests */ - -extern struct userdata_t sent_userdata; -extern bool child_req_success; - -void client_change_room(room_id id); -void client_change_state(int state); -void client_change_user(const char *user); -void client_move(const char *dir); -void client_look(void); - -void send_master(unsigned char cmd, const void *data, size_t sz); diff --git a/src/client.c b/src/client.c index 330187d..77072e2 100644 --- a/src/client.c +++ b/src/client.c @@ -102,6 +102,8 @@ void send_master(unsigned char cmd, const void *data, size_t sz) sigprocmask(SIG_SETMASK, &old, NULL); while(!request_complete) usleep(1); + + free(req); } #define BUFSZ 128 @@ -119,9 +121,11 @@ tryagain: buf[BUFSZ - 1] = '\0'; if(buf[0] & 0x80) { - telnet_handle_command((unsigned char*)buf); + int ret = telnet_handle_command((unsigned char*)buf); free(buf); + if(ret == TELNET_EXIT) + exit(0); goto tryagain; } @@ -140,15 +144,6 @@ char *client_read_password(void) return ret; } -void all_upper(char *s) -{ - while(*s) - { - *s = toupper(*s); - s++; - } -} - static void print_all(int fd) { unsigned char buf[MSG_MAX + 1]; @@ -161,9 +156,6 @@ static void print_all(int fd) } while(1); } -struct userdata_t sent_userdata; -bool child_req_success; - enum reqdata_typespec reqdata_type = TYPE_NONE; union reqdata_t returned_reqdata; @@ -16,7 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "hash.h" +#include "netcosm.h" #include <stdlib.h> #include <string.h> @@ -34,6 +34,7 @@ struct hash_map { size_t table_sz; void (*free_key)(void *key); void (*free_data)(void *data); + size_t n_entries; }; unsigned hash_djb(const void *ptr) @@ -63,6 +64,7 @@ void *hash_init(size_t sz, unsigned (*hash_fn)(const void*), ret->table_sz = sz; ret->hash = hash_fn; ret->compare = compare_keys; + ret->n_entries = 0; return ret; } @@ -81,6 +83,7 @@ void hash_setfreedata_cb(void *ptr, void (*cb)(void *data)) void hash_free(void *ptr) { + sig_debugf("freeing map\n"); if(ptr) { struct hash_map *map = ptr; @@ -92,7 +95,10 @@ void hash_free(void *ptr) struct hash_node *next = node->next; if(map->free_data) + { + debugf("freeing data\n"); map->free_data((void*)node->data); + } if(map->free_key) map->free_key((void*)node->key); free(node); @@ -172,6 +178,7 @@ void *hash_insert(void *ptr, const void *key, const void *data) map->table[hash] = new; else last->next = new; + ++map->n_entries; return NULL; } @@ -223,6 +230,7 @@ bool hash_remove(void *ptr, const void *key) map->free_key((void*)iter->key); if(map->free_data) map->free_data((void*)iter->data); + --map->n_entries; free(iter); return true; } @@ -248,3 +256,9 @@ void *hash_getkeyptr(void *ptr, const void *key) } return NULL; } + +size_t hash_size(void *ptr) +{ + struct hash_map *map = ptr; + return map->n_entries; +} @@ -19,6 +19,8 @@ #include <stdbool.h> #include <stddef.h> +#pragma once + /* simple, generic chained hash map implementation */ unsigned hash_djb(const void*); @@ -63,7 +65,7 @@ void *hash_iterate(void *map, void **saved, void **keyptr); struct hash_pair { void *key; unsigned char value[0]; -}; +} __attribute__((packed)); /* insert n key->pair members of size pairsize */ void hash_insert_pairs(void*, const struct hash_pair*, size_t pairsize, size_t n); @@ -71,14 +73,16 @@ void hash_insert_pairs(void*, const struct hash_pair*, size_t pairsize, size_t n /* gets the original pointer used to store the tuple */ void *hash_getkeyptr(void*, const void *key); -#define SIMP_HASH(TYPE, NAME) \ - unsigned NAME (const void *key) \ - { \ - return *((TYPE*)key); \ +#define SIMP_HASH(TYPE, NAME) \ + unsigned NAME (const void *key) \ + { \ + return (unsigned)*((const TYPE*)key); \ } #define SIMP_EQUAL(TYPE, NAME) \ int NAME (const void *a, const void *b) \ { \ - return !(*((TYPE*)a) == *((TYPE*)b)); \ + return !(*((const TYPE*)a) == *((const TYPE*)b)); \ } + +size_t hash_size(void*); diff --git a/src/netcosm.h b/src/netcosm.h index c5801a6..34e2f3d 100644 --- a/src/netcosm.h +++ b/src/netcosm.h @@ -16,16 +16,18 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _NC_H_ -#define _NC_H_ +/* You should use #pragma once everywhere. */ +#pragma once -#define _GNU_SOURCE /* for pipe2() */ +#define _GNU_SOURCE + +#include <ev.h> +#include <gcrypt.h> #include <arpa/inet.h> #include <ctype.h> #include <errno.h> #include <fcntl.h> -#include <gcrypt.h> #include <netdb.h> #include <netinet/in.h> #include <poll.h> @@ -48,9 +50,9 @@ #define WORLDFILE "world.dat" #define WORLD_MAGIC 0xff467777 #define MAX_FAILURES 3 -#define NETCOSM_VERSION "v0.1" +#define NETCOSM_VERSION "0.2" -#define MAX_NAME_LEN 20 +#define MAX_NAME_LEN 32 #define PRIV_NONE -1 #define PRIV_USER 0 @@ -70,6 +72,7 @@ #define NONE_IN NULL #define NONE_OT NULL +/* needs to be less than PIPE_BUF, which is 4096 */ #define MSG_MAX 2048 #define ARRAYLEN(x) (sizeof(x)/sizeof(x[0])) @@ -77,7 +80,7 @@ #define MIN(a,b) ((a<b)?(a):(b)) #ifndef NDEBUG -#define debugf(fmt,...) debugf_real(fmt, ##__VA_ARGS__) +#define debugf(fmt,...) debugf_real(__func__, __LINE__, __FILE__, fmt, ##__VA_ARGS__) #define sig_debugf debugf #else #define debugf(fmt,...) @@ -152,22 +155,35 @@ struct child_data { room_id room; char *user; + ev_io *io_watcher; + ev_child *sigchld_watcher; + struct ev_loop *loop; + struct in_addr addr; }; -extern const struct roomdata_t netcosm_world[]; -extern const size_t netcosm_world_sz; -extern const char *netcosm_world_name; - #include "auth.h" #include "hash.h" #include "server_reqs.h" #include "telnet.h" #include "userdb.h" +/* globals */ +extern const struct roomdata_t netcosm_world[]; +extern const size_t netcosm_world_sz; +extern const char *netcosm_world_name; + extern volatile int num_clients; extern void *child_map; +extern enum reqdata_typespec { TYPE_NONE = 0, TYPE_USERDATA, TYPE_BOOLEAN } reqdata_type; +extern union reqdata_t { + struct userdata_t userdata; + bool boolean; +} returned_reqdata; + +extern bool are_child; + /* called for every client */ void client_main(int sock, struct sockaddr_in *addr, int, int to_parent, int from_parent); @@ -187,17 +203,12 @@ void world_free(void); /* utility functions */ void __attribute__((noreturn,format(printf,1,2))) error(const char *fmt, ...); -void debugf_real(const char *fmt, ...); +void debugf_real(const char*, int, const char*, const char *fmt, ...); void remove_cruft(char*); - -extern enum reqdata_typespec { TYPE_NONE = 0, TYPE_USERDATA, TYPE_BOOLEAN } reqdata_type; -extern union reqdata_t { - struct userdata_t userdata; - bool boolean; -} returned_reqdata; - +void all_upper(char*); /* call from child process ONLY */ void send_master(unsigned char cmd, const void *data, size_t sz); -#endif +/* the master sends the child SIGRTMIN+0 */ +void sig_rt_0_handler(int s, siginfo_t *info, void *v); @@ -153,6 +153,8 @@ void world_free(void) { if(world) { + if(world_name) + free(world_name); for(unsigned i = 0; i < world_sz; ++i) { room_free(world + i); diff --git a/src/server.c b/src/server.c index 02e71b2..53d627e 100644 --- a/src/server.c +++ b/src/server.c @@ -21,6 +21,18 @@ #define PORT 1234 #define BACKLOG 16 +/* global data */ +bool are_child = false; +void *child_map = NULL; + +/* assume int is atomic */ +volatile int num_clients = 0; + +/* local data */ +static uint16_t port; + +static int server_socket; + void __attribute__((noreturn)) error(const char *fmt, ...) { char buf[128]; @@ -33,11 +45,6 @@ void __attribute__((noreturn)) error(const char *fmt, ...) exit(EXIT_FAILURE); } -/* assume int is atomic */ -volatile int num_clients = 0; -void *child_map = NULL; -static fd_set read_fds, active_fds; - static void free_child_data(void *ptr) { struct child_data *child = ptr; @@ -46,12 +53,8 @@ static void free_child_data(void *ptr) free(ptr); } -static void sigchld_handler(int s, siginfo_t *info, void *vp) +static void handle_disconnects(void) { - (void) s; - (void) info; - (void) vp; - // waitpid() might overwrite errno, so we save and restore it: int saved_errno = errno; pid_t pid; @@ -59,7 +62,8 @@ static void sigchld_handler(int s, siginfo_t *info, void *vp) { sig_debugf("Client disconnect.\n"); struct child_data *child = hash_lookup(child_map, &pid); - FD_CLR(child->readpipe[0], &active_fds); + ev_io_stop(child->loop, child->io_watcher); + free(child->io_watcher); --num_clients; @@ -69,7 +73,11 @@ static void sigchld_handler(int s, siginfo_t *info, void *vp) errno = saved_errno; } -int port; +static void sigchld_handler(int s) +{ + (void) s; + handle_disconnects(); +} static void handle_client(int fd, struct sockaddr_in *addr, int nclients, int to, int from) @@ -77,9 +85,7 @@ static void handle_client(int fd, struct sockaddr_in *addr, client_main(fd, addr, nclients, to, from); } -int server_socket; - -static void serv_cleanup(void) +static void __attribute__((noreturn)) serv_cleanup(void) { sig_debugf("Shutdown server.\n"); @@ -93,26 +99,27 @@ static void serv_cleanup(void) hash_free(child_map); child_map = NULL; + ev_default_destroy(); userdb_shutdown(); _exit(0); } -static void sigint_handler(int s) +static void __attribute__((noreturn)) sigint_handler(int s) { (void) s; serv_cleanup(); } -void init_signals(void) +static void init_signals(void) { struct sigaction sa; sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGCHLD); - sa.sa_sigaction = sigchld_handler; // reap all dead processes - sa.sa_flags = SA_RESTART | SA_SIGINFO; + sa.sa_handler = sigchld_handler; + sa.sa_flags = SA_RESTART; if(sigaction(SIGCHLD, &sa, NULL) < 0) error("sigaction"); @@ -139,8 +146,6 @@ void init_signals(void) if(sigaction(SIGPIPE, &sa, NULL) < 0) error("sigaction"); - void sig_rt_0_handler(int s, siginfo_t *info, void *v); - /* we set this now so there's no race condition after a fork() */ sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGRTMIN); @@ -205,6 +210,105 @@ static int server_bind(void) static SIMP_HASH(pid_t, pid_hash); static SIMP_EQUAL(pid_t, pid_equal); +static void childreq_cb(EV_P_ ev_io *w, int revents) +{ + (void) EV_A; + (void) w; + (void) revents; + /* data from a child's pipe */ + if(!handle_child_req(w->fd)) + { + handle_disconnects(); + } +} + +static void new_connection_cb(EV_P_ ev_io *w, int revents) +{ + (void) EV_A; + (void) w; + (void) revents; + struct sockaddr_in client; + socklen_t client_len = sizeof(client); + int new_sock = accept(server_socket, (struct sockaddr*) &client, &client_len); + if(new_sock < 0) + error("accept"); + + ++num_clients; + + int readpipe[2]; /* child->parent */ + int outpipe [2]; /* parent->child */ + + if(pipe(readpipe) < 0) + error("pipe"); + if(pipe(outpipe) < 0) + error("pipe"); + + int flags = fcntl(outpipe[0], F_GETFL, 0); + if(fcntl(outpipe[0], F_SETFL, flags | O_NONBLOCK) < 0) + error("fcntl"); + + pid_t pid = fork(); + if(pid < 0) + error("fork"); + + if(!pid) + { + /* child */ + are_child = true; + close(readpipe[0]); + close(outpipe[1]); + close(server_socket); + + /* only the master process controls the world */ + world_free(); + reqmap_free(); + hash_free(child_map); + child_map = NULL; + + /* we don't need libev anymore */ + ev_default_destroy(); + + /* user DB requests go through the master */ + userdb_shutdown(); + + debugf("Child with PID %d spawned\n", getpid()); + + server_socket = new_sock; + + handle_client(new_sock, &client, num_clients, readpipe[1], outpipe[0]); + + exit(0); + } + else + { + /* parent */ + close(readpipe[1]); + close(outpipe[0]); + close(new_sock); + + /* add the child to the child map */ + struct child_data *new = calloc(1, sizeof(struct child_data)); + memcpy(new->outpipe, outpipe, sizeof(outpipe)); + memcpy(new->readpipe, readpipe, sizeof(readpipe)); + new->addr = client.sin_addr; + new->pid = pid; + new->state = STATE_INIT; + new->user = NULL; + + ev_io *new_io_watcher = calloc(1, sizeof(ev_io)); + ev_io_init(new_io_watcher, childreq_cb, new->readpipe[0], EV_READ); + ev_io_start(EV_A_ new_io_watcher); + new->io_watcher = new_io_watcher; + + new->loop = loop; + + pid_t *pidbuf = malloc(sizeof(pid_t)); + *pidbuf = pid; + + hash_insert(child_map, pidbuf, new); + } +} + int main(int argc, char *argv[]) { if(argc != 2) @@ -215,11 +319,6 @@ int main(int argc, char *argv[]) srand(time(0)); server_socket = server_bind(); - - /* set up signal handlers */ - /* SIGRTMIN+0 is used for broadcast signaling */ - init_signals(); - userdb_init(USERFILE); check_userfile(); @@ -229,110 +328,23 @@ int main(int argc, char *argv[]) reqmap_init(); /* this initial size very low to make iteration faster */ - child_map = hash_init(7, pid_hash, pid_equal); + child_map = hash_init(16, pid_hash, pid_equal); hash_setfreedata_cb(child_map, free_child_data); hash_setfreekey_cb(child_map, free); debugf("Listening on port %d\n", port); - FD_ZERO(&active_fds); - FD_SET(server_socket, &active_fds); + struct ev_loop *loop = ev_default_loop(0); - while(1) - { - read_fds = active_fds; - int num_events; - sigset_t all, old; - sigemptyset(&all); - sigaddset(&all, SIGPIPE); - sigprocmask(SIG_SETMASK, &all, &old); - do { - num_events = select(FD_SETSIZE, &read_fds, NULL, NULL, NULL); - } while (num_events < 0); - - sigprocmask(SIG_SETMASK, &old, NULL); - //if(num_events < 0) - // error("select"); - - for(int i = 0; i < FD_SETSIZE; ++i) - { - if(FD_ISSET(i, &read_fds)) - { - if(server_socket == i) - { - struct sockaddr_in client; - socklen_t client_len = sizeof(client); - int new_sock = accept(server_socket, (struct sockaddr*) &client, &client_len); - if(new_sock < 0) - error("accept"); - - ++num_clients; - - int readpipe[2]; /* child->parent */ - int outpipe [2]; /* parent->child */ - - if(pipe(readpipe) < 0) - error("pipe"); - if(pipe2(outpipe, O_NONBLOCK) < 0) - error("pipe"); - - pid_t pid = fork(); - if(pid < 0) - error("fork"); - - if(!pid) - { - /* child */ - close(readpipe[0]); - close(outpipe[1]); - close(server_socket); - - /* only the master process controls the world */ - world_free(); - reqmap_free(); - hash_free(child_map); - child_map = NULL; - - /* user DB requests go through the master */ - userdb_shutdown(); - - debugf("Child with PID %d spawned\n", getpid()); - - server_socket = new_sock; - - handle_client(new_sock, &client, num_clients, readpipe[1], outpipe[0]); - - exit(0); - } - else - { - /* parent */ - close(readpipe[1]); - close(outpipe[0]); - close(new_sock); - - /* add the child to the child map */ - struct child_data *new = calloc(1, sizeof(struct child_data)); - memcpy(new->outpipe, outpipe, sizeof(outpipe)); - memcpy(new->readpipe, readpipe, sizeof(readpipe)); - FD_SET(new->readpipe[0], &active_fds); - new->addr = client.sin_addr; - new->pid = pid; - new->state = STATE_INIT; - new->user = NULL; - - pid_t *pidbuf = malloc(sizeof(pid_t)); - *pidbuf = pid; - hash_insert(child_map, pidbuf, new); - } - } - else - { - /* data from a child's pipe */ - if(!handle_child_req(i)) - FD_CLR(i, &active_fds); - } - } - } - } + /* set up signal handlers AFTER creating the default loop, because it will grab SIGCHLD */ + init_signals(); + + ev_io server_watcher; + ev_io_init(&server_watcher, new_connection_cb, server_socket, EV_READ); + ev_io_start(EV_A_ &server_watcher); + + ev_loop(loop, 0); + + /* should never get here */ + error("unexpected termination"); } diff --git a/src/server_reqs.c b/src/server_reqs.c index ac53396..10f6ad3 100644 --- a/src/server_reqs.c +++ b/src/server_reqs.c @@ -46,9 +46,9 @@ static void req_send_clientinfo(unsigned char *data, size_t datalen, inet_ntoa(child->addr), child->pid, state[child->state]); if(sender->pid == child->pid) - strncat(buf, " [YOU]\n", sizeof(buf)); + strncat(buf, " [YOU]\n", sizeof(buf) - 1); else - strncat(buf, "\n", sizeof(buf)); + strncat(buf, "\n", sizeof(buf) - 1); write(sender->outpipe[1], buf, strlen(buf)); } @@ -167,13 +167,6 @@ static void req_move_room(unsigned char *data, size_t datalen, struct child_data write(sender->outpipe[1], &status, sizeof(status)); } -static void send_string(int fd, const char *s) -{ - size_t len = strlen(s); - write(fd, &len, sizeof(len)); - write(fd, s, len); -} - static void req_send_user(unsigned char *data, size_t datalen, struct child_data *sender) { if(datalen) @@ -417,9 +410,17 @@ finish: else sig_debugf("Unknown PID sent request.\n"); + /* 5 ms */ +#define ACK_TIMEOUT 5000 + + struct timespec timeout; + timeout.tv_sec = 0; + timeout.tv_nsec = ACK_TIMEOUT; + while(num_acks_recvd < MIN(num_clients,num_acks_wanted)) { - sigsuspend(&old); + if(sigtimedwait(&old, NULL, &timeout) < 0 && errno == EAGAIN) + break; } inc_acks = 0; diff --git a/src/telnet.c b/src/telnet.c index 173574b..038c54c 100644 --- a/src/telnet.c +++ b/src/telnet.c @@ -18,7 +18,7 @@ #include "netcosm.h" -void telnet_handle_command(const unsigned char *buf) +int telnet_handle_command(const unsigned char *buf) { bool cmd = false; @@ -58,7 +58,7 @@ void telnet_handle_command(const unsigned char *buf) switch(c) { case IP: - exit(0); + return TELNET_EXIT; default: break; } @@ -70,6 +70,8 @@ void telnet_handle_command(const unsigned char *buf) if(cmd) debugf("\n"); + + return TELNET_OK; } void telnet_echo_off(void) diff --git a/src/telnet.h b/src/telnet.h index c0725c4..673ad1c 100644 --- a/src/telnet.h +++ b/src/telnet.h @@ -16,6 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#pragma once + /* commands */ #define IAC 255 #define DONT 254 @@ -39,6 +41,12 @@ #define LINEMODE 34 void telnet_init(void); -void telnet_handle_command(const unsigned char*); + +#define TELNET_OK 0 +#define TELNET_EXIT 1 + +/* returns either 0 or TELNET_EXIT */ +int telnet_handle_command(const unsigned char*); + void telnet_echo_on(void); void telnet_echo_off(void); diff --git a/src/userdb.c b/src/userdb.c index c58771f..749115c 100644 --- a/src/userdb.c +++ b/src/userdb.c @@ -2,18 +2,16 @@ static void *map = NULL; static char *db_file = NULL; -static size_t entries = 0; /* * the user DB is stored on disk as an ASCII database * - * this is then loaded into variable-sized hash map at init + * this is then loaded into fixed-sized hash map at init * TODO: implement with B-tree */ void userdb_init(const char *file) { db_file = strdup(file); - entries = 0; /* FILE* for getline() */ FILE *f = fopen(file, "r"); @@ -21,7 +19,7 @@ void userdb_init(const char *file) hash_setfreedata_cb(map, free); char *format; - asprintf(&format, "%%%d[a-z0-9]:%%%d[A-Z]:%%%ds:%%d\n", + asprintf(&format, "%%%d[a-z0-9 ]:%%%d[A-Z]:%%%ds:%%d\n", MAX_NAME_LEN, SALT_LEN, AUTH_HASHLEN * 2); if(f) @@ -31,16 +29,18 @@ void userdb_init(const char *file) struct userdata_t *data = calloc(1, sizeof(*data)); int ret = fscanf(f, format, - &data->username, + data->username, data->salt, data->passhash, &data->priv); if(ret != 4) + { + free(data); break; + } hash_insert(map, data->username, data); - ++entries; } fclose(f); @@ -59,8 +59,8 @@ void userdb_write(const char *file) ptr = NULL; if(!user) break; - dprintf(fd, "%*s:%*s:%*s:%d\n", - MAX_NAME_LEN, user->username, + dprintf(fd, "%s:%*s:%*s:%d\n", + user->username, SALT_LEN, user->salt, AUTH_HASHLEN*2, user->passhash, user->priv); @@ -77,13 +77,13 @@ bool userdb_remove(const char *key) { if(hash_remove(map, key)) { - --entries; userdb_write(db_file); return true; } return false; } +/* should never fail, but returns NULL if something weird happens */ struct userdata_t *userdb_add(struct userdata_t *data) { struct userdata_t *new = calloc(1, sizeof(*new)); /* only in C! */ @@ -99,17 +99,16 @@ struct userdata_t *userdb_add(struct userdata_t *data) } userdb_write(db_file); - if(!ret) - ++entries; return ret; } void userdb_shutdown(void) { - debugf("shutting down userdb with %d entries\n", entries); + debugf("shutting down userdb with %d entries\n", hash_size(map)); if(map) { + debugf("shutting down userdb\n"); hash_free(map); map = NULL; } @@ -122,28 +121,43 @@ void userdb_shutdown(void) size_t userdb_size(void) { - return entries; + return hash_size(map); } /* child request wrappers */ +/* NOTE: also works from the master, but it's better to use the userdb_* funcs instead */ -/* loop until we can return a user data structure */ struct userdata_t *userdb_request_lookup(const char *name) { - send_master(REQ_GETUSERDATA, name, strlen(name) + 1); - if(reqdata_type == TYPE_USERDATA) - return &returned_reqdata.userdata; - return NULL; + if(are_child) + { + send_master(REQ_GETUSERDATA, name, strlen(name) + 1); + if(reqdata_type == TYPE_USERDATA) + return &returned_reqdata.userdata; + return NULL; + } + else + return userdb_lookup(name); } bool userdb_request_add(struct userdata_t *data) { - send_master(REQ_ADDUSERDATA, data, sizeof(*data)); - return returned_reqdata.boolean; + if(are_child) + { + send_master(REQ_ADDUSERDATA, data, sizeof(*data)); + return returned_reqdata.boolean; + } + else + return userdb_add(data); } bool userdb_request_remove(const char *name) { - send_master(REQ_DELUSERDATA, name, strlen(name) + 1); - return returned_reqdata.boolean; + if(are_child) + { + send_master(REQ_DELUSERDATA, name, strlen(name) + 1); + return returned_reqdata.boolean; + } + else + return userdb_remove(name); } diff --git a/src/userdb.h b/src/userdb.h index ac169b2..a941e9a 100644 --- a/src/userdb.h +++ b/src/userdb.h @@ -1,12 +1,8 @@ +#pragma once + #include "netcosm.h" #include "auth.h" -/* - * on-disk database for storing user data - * - * child processes MUST go through the master to use this - */ - struct userdata_t { char username[MAX_NAME_LEN + 1]; @@ -16,8 +12,11 @@ struct userdata_t { char passhash[AUTH_HASHLEN * 2 + 1]; int priv; + room_id room; }; +/*** functions for the master process ONLY ***/ + /* call before using anything else */ void userdb_init(const char *dbfile); @@ -42,3 +41,8 @@ void userdb_shutdown(void); /* save the DB to disk */ void userdb_write(const char*); + +/*** child-only functions ***/ +struct userdata_t *userdb_request_lookup(const char *name); +bool userdb_request_add(struct userdata_t *data); +bool userdb_request_remove(const char *name); @@ -28,15 +28,37 @@ void remove_cruft(char *str) * WARNING: not signal-safe * TODO: rewrite to avoid calling *printf() */ -void debugf_real(const char *fmt, ...) +void debugf_real(const char *func, int line, const char *file, const char *fmt, ...) { + (void) func; + (void) line; + (void) file; + int len; +#if 0 + char *prefix; + len = asprintf(&prefix, "%s:%s:%d: ", func, file, line); + write(STDOUT_FILENO, prefix, len); + free(prefix); +#endif + va_list ap; va_start(ap, fmt); - char buf[128]; - int len = vsnprintf(buf, sizeof(buf), fmt, ap); + char *buf; + len = vasprintf(&buf, fmt, ap); write(STDOUT_FILENO, buf, len); + free(buf); + va_end(ap); } + +void all_upper(char *s) +{ + while(*s) + { + *s = toupper(*s); + s++; + } +} |