diff options
| author | Franklin Wei <git@fwei.tk> | 2015-12-25 14:25:16 -0500 |
|---|---|---|
| committer | Franklin Wei <git@fwei.tk> | 2015-12-25 14:25:16 -0500 |
| commit | 2a81620aa5b740d7f77aff8177a983b7492b8ea0 (patch) | |
| tree | 98c132a338ec9aebfc43b365ea31974463f19703 /src | |
| parent | 53c15b0461ee39a4c32e61ff484389efb1e91d84 (diff) | |
| download | netcosm-2a81620aa5b740d7f77aff8177a983b7492b8ea0.zip netcosm-2a81620aa5b740d7f77aff8177a983b7492b8ea0.tar.gz netcosm-2a81620aa5b740d7f77aff8177a983b7492b8ea0.tar.bz2 netcosm-2a81620aa5b740d7f77aff8177a983b7492b8ea0.tar.xz | |
tons of stuff
Diffstat (limited to 'src')
| -rw-r--r-- | src/auth.c | 12 | ||||
| -rw-r--r-- | src/client.c | 38 | ||||
| -rw-r--r-- | src/hash.c | 23 | ||||
| -rw-r--r-- | src/hash.h | 26 | ||||
| -rw-r--r-- | src/netcosm.h | 101 | ||||
| -rw-r--r-- | src/room.c | 192 | ||||
| -rw-r--r-- | src/server.c | 95 |
7 files changed, 372 insertions, 115 deletions
@@ -118,7 +118,7 @@ static int remove_user_internal(const char *user, int *found, char **filename) return out_fd; } -bool auth_remove(const char *user2) +bool auth_user_del(const char *user2) { char *user = strdup(user2); remove_cruft(user); @@ -146,7 +146,7 @@ bool auth_remove(const char *user2) } } -bool add_change_user(const char *user2, const char *pass2, int level) +bool auth_user_add(const char *user2, const char *pass2, int level) { char *user = strdup(user2); remove_cruft(user); @@ -221,7 +221,7 @@ void first_run_setup(void) getline(&admin_pass, &len, stdin); remove_cruft(admin_pass); - if(!add_change_user(admin_name, admin_pass, PRIV_ADMIN)) + if(!auth_user_add(admin_name, admin_pass, PRIV_ADMIN)) error("Unknown error"); /* zero the memory */ @@ -277,9 +277,9 @@ struct authinfo_t auth_check(const char *name2, const char *pass2) unsigned int hash_len = gcry_md_get_algo_dlen(ALGO); if(strlen(hash) != hash_len * 2) - error("hash corrupt %d %d", strlen(hash), hash_len * 2); + error("hash corrupt (wrong length)"); if(strlen(salt) != SALT_LEN) - error("salt corrupt"); + error("salt corrupt (wrong length)"); char *hex = hash_pass_hex(pass, salt); @@ -314,7 +314,7 @@ bad: return ret; } -void auth_list_users(void) +void auth_user_list(void) { FILE *f = fopen(USERFILE, "r"); diff --git a/src/client.c b/src/client.c index ee40e5c..5930f48 100644 --- a/src/client.c +++ b/src/client.c @@ -203,21 +203,16 @@ static void client_move(const char *dir) { "NORTHWEST", DIR_NW }, { "U", DIR_UP }, { "UP", DIR_UP }, - { "D", DIR_DOWN }, - { "DOWN", DIR_DOWN }, + { "D", DIR_DN }, + { "DOWN", DIR_DN }, + { "IN", DIR_IN }, + { "OUT", DIR_OT }, }; static void *map = NULL; if(!map) { - map = hash_init(ARRAYLEN(dirs), hash_djb, strcmp); - for(unsigned i = 0; i < ARRAYLEN(dirs); ++i) - { - hash_insert(map, dirs[i].text, dirs + i); - - void *new = hash_lookup(map, dirs[i].text); - if(new != dirs + i) - error("weird %p %p", new, dirs + i); - } + map = hash_init(ARRAYLEN(dirs), hash_djb, compare_strings); + hash_insert_pairs(map, (struct hash_pair*)dirs, sizeof(struct dir_pair), ARRAYLEN(dirs)); } struct dir_pair *pair = hash_lookup(map, dir); @@ -352,7 +347,7 @@ auth: char *user = strtok_r(NULL, WSPACE, &save); if(user) { - if(strcmp(user, current_user) && auth_remove(user)) + if(strcmp(user, current_user) && auth_user_del(user)) out("Success.\n"); else out("Failure.\n"); @@ -401,7 +396,7 @@ auth: free(allow_admin); - if(add_change_user(user, pass, priv)) + if(auth_user_add(user, pass, priv)) out("Success.\n"); else out("Failure.\n"); @@ -413,7 +408,7 @@ auth: } else if(!strcmp(what, "LIST")) { - auth_list_users(); + auth_user_list(); } } else if(!strcmp(tok, "CLIENT")) @@ -438,13 +433,18 @@ auth: { /* weird pointer voodoo */ /* TODO: simplify */ - char buf[MSG_MAX]; + char pidbuf[MAX(sizeof(pid_t), MSG_MAX)]; pid_t pid = strtol(pid_s, NULL, 0); - *((pid_t*)buf) = pid; - int len = sizeof(pid_t) + snprintf(buf + sizeof(pid_t), - sizeof(buf) - sizeof(pid_t), + if(pid == getpid()) + { + out("You cannot kick yourself. Use EXIT instead.\n"); + goto next_cmd; + } + memcpy(pidbuf, &pid, sizeof(pid)); + int len = sizeof(pid_t) + snprintf(pidbuf + sizeof(pid_t), + sizeof(pidbuf) - sizeof(pid_t), "You were kicked.\n"); - send_master(REQ_KICK, buf, len); + send_master(REQ_KICK, pidbuf, len); printf("Success.\n"); } else @@ -1,4 +1,6 @@ #include "hash.h" +#include <stdlib.h> +#include <string.h> struct hash_node { const void *key; @@ -13,8 +15,9 @@ struct hash_map { size_t table_sz; }; -unsigned hash_djb(const char *str) +unsigned hash_djb(const void *ptr) { + const char *str = ptr; unsigned hash = 5381; char c; while((c = *str++)) @@ -25,6 +28,12 @@ unsigned hash_djb(const char *str) return hash; } +/* wrapper to supress warnings */ +int compare_strings(const void *a, const void *b) +{ + return strcmp(a,b); +} + void *hash_init(size_t sz, unsigned (*hash_fn)(const void*), int (*compare_keys)(const void*, const void*)) { @@ -98,3 +107,15 @@ void *hash_lookup(void *ptr, const void *key) } return NULL; } + +void hash_insert_pairs(void *ptr, const struct hash_pair *pairs, + size_t pairsize, size_t n) +{ + const char *iter = (const char*)pairs; + for(unsigned i = 0; i < n; ++i) + { + const struct hash_pair *pair = (const struct hash_pair*)iter; + hash_insert(ptr, pair->key, pair); + iter += pairsize; + } +} @@ -1,9 +1,9 @@ #include <stddef.h> -#include <stdlib.h> -/* simple, generic hash map implementation */ +/* simple, generic chained hash map implementation */ -unsigned hash_djb(const char*); +unsigned hash_djb(const void*); +int compare_strings(const void*, const void*); void *hash_init(size_t tabsz, unsigned (*hash_fn)(const void*), int (*compare_key)(const void*, const void*)); @@ -16,3 +16,23 @@ void *hash_insert(void*, const void *key, const void *data); /* returns NULL if not found */ void *hash_lookup(void*, const void *key); + +struct hash_pair { + void *key; + unsigned char value[0]; +}; + +/* insert n key->pair members of size pairsize */ +void hash_insert_pairs(void*, const struct hash_pair*, size_t pairsize, size_t n); + +#define SIMP_HASH(TYPE, NAME) \ + unsigned NAME (const void *key) \ + { \ + return *((TYPE*)key); \ + } + +#define SIMP_EQUAL(TYPE, NAME) \ + int NAME (const void *a, const void *b) \ + { \ + return !(*((TYPE*)a) == *((TYPE*)b)); \ + } diff --git a/src/netcosm.h b/src/netcosm.h index fb50600..94fa42f 100644 --- a/src/netcosm.h +++ b/src/netcosm.h @@ -24,6 +24,8 @@ #include "telnet.h" #define USERFILE "users.dat" +#define WORLDFILE "world.dat" +#define WORLD_MAGIC 0xff467777 #define MAX_FAILURES 3 #define NETCOSM_VERSION "v0.1" @@ -34,7 +36,6 @@ /* child<->master commands */ /* children might not implement all of these */ /* meanings might be different for the server and child, see comments */ - #define REQ_NOP 0 /* server, child: do nothing */ #define REQ_BCASTMSG 1 /* server: broadcast text; child: print following text */ #define REQ_LISTCLIENTS 2 /* server: list childs */ @@ -48,7 +49,7 @@ #define REQ_MOVE 10 /* server: move child based on direction; child: success or failure */ #define REQ_GETROOMNAME 11 /* server: send child's room name */ -/* child states */ +/* child states, sent as an int to the master */ #define STATE_INIT 0 /* initial state */ #define STATE_AUTH 1 /* at login screen */ #define STATE_CHECKING 2 /* checking password */ @@ -67,6 +68,17 @@ #define NONE_NW NULL #define NONE_UP NULL #define NONE_DN NULL +#define NONE_IN NULL +#define NONE_OT NULL + +#define MSG_MAX 512 + +#define ROOM_NONE -1 + +#define ARRAYLEN(x) (sizeof(x)/sizeof(x[0])) +#define MAX(a,b) ((a>b)?(a):(b)) + +typedef int room_id; struct authinfo_t { bool success; @@ -74,14 +86,15 @@ struct authinfo_t { int authlevel; }; -/* logged in users are identified by the PID of the process serving them */ +/* used by the room module to keep track of users in rooms */ struct user_t { - pid_t pid; + struct child_data *data; + struct user_t *next; }; -enum direction_t { DIR_N = 0, DIR_NE, DIR_E, DIR_SE, DIR_S, DIR_SW, DIR_W, DIR_NW, DIR_UP, DIR_DOWN, NUM_DIRECTIONS }; +enum direction_t { DIR_N = 0, DIR_NE, DIR_E, DIR_SE, DIR_S, DIR_SW, DIR_W, DIR_NW, DIR_UP, DIR_DN, DIR_IN, DIR_OT, NUM_DIRECTIONS }; -struct item_t { +struct object_t { const char *class; }; @@ -93,22 +106,34 @@ struct verb_t { void (*execute)(const char *toks); }; -typedef int room_id; +struct child_data { + pid_t pid; + int readpipe[2]; + int outpipe[2]; -#define ROOM_NONE -1 + int state; + room_id room; + char *user; + + struct in_addr addr; + + /* a linked list works well for this because no random-access is needed */ + struct child_data *next; +}; /* the data we get from a world module */ struct roomdata_t { - const char *uniq_id; + /* the non-const pointers can be modified by the world module */ + const char * const uniq_id; const char *name; const char *desc; - const char *adjacent[NUM_DIRECTIONS]; + const char * const adjacent[NUM_DIRECTIONS]; - void (*hook_init)(room_id id); - void (*hook_enter)(room_id room, pid_t player); - void (*hook_say)(room_id room, pid_t player, const char *msg); - void (*hook_leave)(room_id room, pid_t player); + void (* const hook_init)(room_id id); + void (* const hook_enter)(room_id room, pid_t player); + void (* const hook_say)(room_id room, pid_t player, const char *msg); + void (* const hook_leave)(room_id room, pid_t player); }; struct room_t { @@ -118,42 +143,48 @@ struct room_t { room_id adjacent[NUM_DIRECTIONS]; /* arrays instead of linked lists because insertion should be rare for these */ - struct item_t *items; - size_t items_sz; + size_t objects_sz; + struct object_t *objects; - struct verb_t *verbs; size_t verbs_sz; -}; + struct verb_t *verbs; -extern const struct roomdata_t netcosm_world[]; -extern const size_t netcosm_world_sz; + /* linked list for users, random access is rare */ + struct user_t *users; +}; +/* called for every client */ void client_main(int sock, struct sockaddr_in *addr, int, int to_parent, int from_parent); -void __attribute__((noreturn)) error(const char *fmt, ...); -void first_run_setup(void); -struct authinfo_t auth_check(const char*, const char*); -/* add or change a user, NOT reentrant */ -bool add_change_user(const char *user2, const char *pass2, int level); -bool auth_remove(const char*); +void first_run_setup(void); -void telnet_handle_command(const unsigned char*); +/* authorization */ +struct authinfo_t auth_check(const char *user, const char *pass); -#define ARRAYLEN(x) (sizeof(x)/sizeof(x[0])) +/* add or change a user, NOT reentrant */ +bool auth_user_add(const char *user, const char *pass, int authlevel); +bool auth_user_del(const char *user); +void auth_user_list(void); void out(const char *fmt, ...) __attribute__((format(printf,1,2))); void out_raw(const unsigned char*, size_t); + void telnet_init(void); +void telnet_handle_command(const unsigned char*); void telnet_echo_on(void); void telnet_echo_off(void); -#define MSG_MAX 512 -void remove_cruft(char*); - -void auth_list_users(void); void world_init(const struct roomdata_t *data, size_t sz); -void sig_printf(const char *fmt, ...); -void world_free(void); +bool world_load(const char *fname, const struct roomdata_t *data, size_t data_sz); +void world_save(const char *fname); -/* only the master calls this */ struct room_t *room_get(room_id id); +bool room_user_add(room_id id, struct child_data *child); +bool room_user_del(room_id id, struct child_data *child); + +void world_free(void); + +/* utility functions */ +void __attribute__((noreturn,format(printf,1,2))) error(const char *fmt, ...); +void sig_printf(const char *fmt, ...); +void remove_cruft(char*); @@ -1,19 +1,9 @@ #include "netcosm.h" +/* processed world data */ static struct room_t *world; static size_t world_sz; -static struct room_t *room_linear_search(const char *id) -{ - printf("Looking for room with id '%s'\n", id); - for(size_t i = 0; i < world_sz; ++i) - if(!strcmp(world[i].data.uniq_id, id)) - return world + i; - else - printf("Iterating over room '%s'\n", world[i].data.uniq_id); - return NULL; -} - struct room_t *room_get(room_id id) { return world + id; @@ -24,6 +14,139 @@ void world_free(void) free(world); } +bool room_user_add(room_id id, struct child_data *child) +{ + struct room_t *room = room_get(id); + /* make sure there are no duplicates */ + + struct user_t *iter = room->users, *last = NULL; + while(iter) + { + if(iter->data->pid == child->pid) + return false; + last = iter; + iter = iter->next; + } + + struct user_t *new = calloc(sizeof(struct user_t), 1); + + new->data = child; + new->next = NULL; + + if(last) + last->next = new; + else + room->users = new; + return true; +} + +bool room_user_del(room_id id, struct child_data *child) +{ + struct room_t *room = room_get(id); + + struct user_t *iter = room->users, *last = NULL; + while(iter) + { + if(iter->data->pid == child->pid) + { + if(last) + last->next = iter->next; + else + room->users = iter->next; + free(iter); + return true; + } + last = iter; + iter = iter->next; + } + return false; +} + +void write_roomid(int fd, room_id *id) +{ + write(fd, id, sizeof(*id)); +} + +void write_string(int fd, const char *str) +{ + size_t len = strlen(str); + write(fd, &len, sizeof(len)); + write(fd, str, len); +} + +room_id read_roomid(int fd) +{ + room_id ret; + if(read(fd, &ret, sizeof(ret)) < 0) + return ROOM_NONE; + return ret; +} + +const char *read_string(int fd) +{ + size_t sz; + read(fd, &sz, sizeof(sz)); + char *ret = malloc(sz + 1); + if(read(fd, ret, sz) < 0) + return NULL; + ret[sz] = '\0'; + return ret; +} + +void world_save(const char *fname) +{ + int fd = open(fname, O_CREAT | O_WRONLY, 0644); + uint32_t magic = WORLD_MAGIC; + write(fd, &magic, sizeof(magic)); + write(fd, &world_sz, sizeof(world_sz)); + for(unsigned i = 0; i < world_sz; ++i) + { + write_roomid(fd, &world[i].id); + /* unique ID never changes */ + //write_string(fd, world[i].data.uniq_id); + write_string(fd, world[i].data.name); + write_string(fd, world[i].data.desc); + /* adjacency strings are only used when loading the world for the 1st time */ + + /* callbacks are static, so are not serialized */ + + write(fd, world[i].adjacent, sizeof(world[i].adjacent)); + } + close(fd); +} + +bool world_load(const char *fname, const struct roomdata_t *data, size_t data_sz) +{ + int fd = open(fname, O_RDONLY); + if(fd < 0) + return false; + uint32_t magic; + read(fd, &magic, sizeof(magic)); + if(magic != WORLD_MAGIC) + return false; + read(fd, &world_sz, sizeof(world_sz)); + if(world) + free(world); + if(world_sz != data_sz) + return false; + world = calloc(world_sz, sizeof(struct room_t)); + for(unsigned i = 0; i < world_sz; ++i) + { + world[i].id = read_roomid(fd); + memcpy(&world[i].data, data + i, sizeof(struct roomdata_t)); + world[i].data.name = read_string(fd); + world[i].data.desc = read_string(fd); + if(read(fd, world[i].adjacent, sizeof(world[i].adjacent)) < 0) + return false; + } + + close(fd); + return true; +} + +static SIMP_HASH(enum direction_t, dir_hash); +static SIMP_EQUAL(enum direction_t, dir_equal); + /* loads room data (supplied by the world module) into our internal format */ void world_init(const struct roomdata_t *data, size_t sz) { @@ -31,7 +154,7 @@ void world_init(const struct roomdata_t *data, size_t sz) world = calloc(sz, sizeof(struct room_t)); world_sz = 0; - void *map = hash_init(1, hash_djb, strcmp); + void *map = hash_init(1, hash_djb, compare_strings); for(size_t i = 0; i < sz; ++i) { @@ -64,7 +187,7 @@ void world_init(const struct roomdata_t *data, size_t sz) const char *adjacent_room = world[i].data.adjacent[dir]; if(adjacent_room) { - struct room_t *room = room_linear_search(adjacent_room); + struct room_t *room = hash_lookup(map, adjacent_room); if(room) world[i].adjacent[dir] = room->id; else @@ -75,10 +198,49 @@ void world_init(const struct roomdata_t *data, size_t sz) } } - /* third pass to call all the init handlers */ - for(size_t i = 0; i < world_sz; ++i) + struct direction_pair { + enum direction_t dir, opp; + } pairs[] = { + { DIR_N, DIR_S }, + { DIR_NE, DIR_SW }, + { DIR_E, DIR_W }, + { DIR_SE, DIR_NW }, + { DIR_UP, DIR_DN }, + { DIR_IN, DIR_OT }, + }; + + void *dir_map = hash_init(ARRAYLEN(pairs) * 2, dir_hash, dir_equal); + for(int n = 0; n < 2; ++n) + { + for(unsigned i = 0; i < ARRAYLEN(pairs); ++i) + { + if(!n) + hash_insert(dir_map, &pairs[i].dir, &pairs[i].opp); + else + hash_insert(dir_map, &pairs[i].opp, &pairs[i].dir); + } + } + + /* third pass to call all the init handlers and check accessibility */ + for(room_id i = 0; i < (int)world_sz; ++i) + { if(world[i].data.hook_init) world[i].data.hook_init(world[i].id); + /* check that all rooms are accessible */ + for(enum direction_t j = 0; j < NUM_DIRECTIONS; ++j) + { + if(world[i].adjacent[j] != ROOM_NONE) + { + enum direction_t *opp = hash_lookup(dir_map, &j); + struct room_t *adj = room_get(world[i].adjacent[j]); + if(adj->adjacent[*opp] != i) + printf("WARNING: Rooms '%s' and '%s' are not connected correctly.\n", + world[i].data.uniq_id, adj->data.uniq_id); + } + } + } + + hash_free(dir_map); hash_free(map); } diff --git a/src/server.c b/src/server.c index a276a02..3476f38 100644 --- a/src/server.c +++ b/src/server.c @@ -35,21 +35,7 @@ void __attribute__((noreturn)) error(const char *fmt, ...) /* assume int is atomic */ volatile int num_clients = 0; - -static struct child_data { - pid_t pid; - int readpipe[2]; - int outpipe[2]; - - int state; - room_id room; - char *user; - - struct in_addr addr; - - /* a linked list works well for this because no random-access is needed */ - struct child_data *next; -} *child_data; +struct child_data *child_data; static void sigchld_handler(int s, siginfo_t *info, void *vp) { @@ -153,7 +139,7 @@ static void req_send_clientinfo(unsigned char *data, size_t datalen, static void req_change_state(unsigned char *data, size_t datalen, struct child_data *sender, struct child_data *child) { - (void) child; + (void) data; (void) datalen; (void) child; (void) sender; if(datalen == sizeof(sender->state)) { sender->state = *((int*)data); @@ -170,9 +156,7 @@ static void req_change_state(unsigned char *data, size_t datalen, static void req_change_user(unsigned char *data, size_t datalen, struct child_data *sender, struct child_data *child) { - (void) data; - (void) datalen; - (void) child; + (void) data; (void) datalen; (void) child; (void) sender; if(sender->user) free(sender->user); sender->user = strdup((char*)data); @@ -187,7 +171,7 @@ static void req_change_user(unsigned char *data, size_t datalen, static void req_kick_client(unsigned char *data, size_t datalen, struct child_data *sender, struct child_data *child) { - (void) sender; + (void) data; (void) datalen; (void) child; (void) sender; if(datalen >= sizeof(pid_t)) { pid_t kicked_pid = *((pid_t*)data); @@ -201,13 +185,15 @@ static void req_kick_client(unsigned char *data, size_t datalen, } } -static void req_wait(unsigned char *data, size_t len, struct child_data *sender) +static void req_wait(unsigned char *data, size_t datalen, struct child_data *sender) { + (void) data; (void) datalen; (void) sender; sleep(10); } -static void req_send_desc(unsigned char *data, size_t len, struct child_data *sender) +static void req_send_desc(unsigned char *data, size_t datalen, struct child_data *sender) { + (void) data; (void) datalen; (void) sender; struct room_t *room = room_get(sender->room); write(sender->outpipe[1], room->data.desc, strlen(room->data.desc) + 1); @@ -215,8 +201,9 @@ static void req_send_desc(unsigned char *data, size_t len, struct child_data *se write(sender->outpipe[1], &newline, 1); } -static void req_send_roomname(unsigned char *data, size_t len, struct child_data *sender) +static void req_send_roomname(unsigned char *data, size_t datalen, struct child_data *sender) { + (void) data; (void) datalen; (void) sender; struct room_t *room = room_get(sender->room); write(sender->outpipe[1], room->data.name, strlen(room->data.name) + 1); @@ -224,25 +211,35 @@ static void req_send_roomname(unsigned char *data, size_t len, struct child_data write(sender->outpipe[1], &newline, 1); } -static void req_set_room(unsigned char *data, size_t len, struct child_data *sender) +static void child_set_room(struct child_data *child, room_id id) +{ + child->room = id; + room_user_add(id, child); +} + +static void req_set_room(unsigned char *data, size_t datalen, struct child_data *sender) { + (void) data; (void) datalen; (void) sender; room_id id = *((room_id*)data); - sender->room = id; + child_set_room(sender, id); } -static void req_move_room(unsigned char *data, size_t len, struct child_data *sender) +static void req_move_room(unsigned char *data, size_t datalen, struct child_data *sender) { + (void) data; (void) datalen; (void) sender; enum direction_t dir = *((enum direction_t*)data); struct room_t *current = room_get(sender->room); + room_user_del(sender->room, sender); + /* TODO: checking */ sig_printf("Moving in direction %d\n", dir); room_id new = current->adjacent[dir]; int status; if(new != ROOM_NONE) { - sender->room = new; + child_set_room(sender, new); status = 1; } else @@ -280,8 +277,21 @@ static const struct child_request { { REQ_GETROOMNAME, false, CHILD_NONE, NULL, req_send_roomname, REQ_BCASTMSG }, { REQ_SETROOM, true, CHILD_NONE, NULL, req_set_room, REQ_NOP }, { REQ_MOVE, true, CHILD_NONE, NULL, req_move_room, REQ_MOVE }, + //{ REQ_ROOMMSG, true, CHILD_ALL, req_send_room_msg, NULL, REQ_BCASTMSG }, }; +static void *request_map = NULL; + +static SIMP_HASH(unsigned char, uchar_hash); +static SIMP_EQUAL(unsigned char, uchar_equal); + +static void reqmap_init(void) +{ + request_map = hash_init(ARRAYLEN(requests), uchar_hash, uchar_equal); + for(unsigned i = 0; i < ARRAYLEN(requests); ++i) + hash_insert(request_map, &requests[i].code, requests + i); +} + void sig_printf(const char *fmt, ...) { va_list ap; @@ -322,14 +332,7 @@ static void sigusr1_handler(int s, siginfo_t *info, void *vp) { sender = iter; read(iter->readpipe[0], &cmd, 1); - for(unsigned int i = 0; i < ARRAYLEN(requests); ++i) - { - if(cmd == requests[i].code) - { - req = requests + i; - break; - } - } + req = hash_lookup(request_map, &cmd); if(!req) { sig_printf("Unknown request.\n"); @@ -439,6 +442,24 @@ static void check_userfile(void) error("cannot access "USERFILE); } +/* "raw" world data, provided by the world module */ +extern const struct roomdata_t netcosm_world[]; +extern const size_t netcosm_world_sz; + +static void load_worldfile(void) +{ + if(access(WORLDFILE, F_OK) < 0) + { + world_init(netcosm_world, netcosm_world_sz); + + world_save(WORLDFILE); + } + else if(access(WORLDFILE, R_OK | W_OK) < 0) + error("cannot access "WORLDFILE); + else + world_load(WORLDFILE, netcosm_world, netcosm_world_sz); +} + static int server_bind(void) { int sock = socket(AF_INET, SOCK_STREAM, 0); @@ -483,7 +504,9 @@ int main(int argc, char *argv[]) check_userfile(); - world_init(netcosm_world, netcosm_world_sz); + load_worldfile(); + + reqmap_init(); child_data = NULL; |