aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2015-12-25 14:25:16 -0500
committerFranklin Wei <git@fwei.tk>2015-12-25 14:25:16 -0500
commit2a81620aa5b740d7f77aff8177a983b7492b8ea0 (patch)
tree98c132a338ec9aebfc43b365ea31974463f19703
parent53c15b0461ee39a4c32e61ff484389efb1e91d84 (diff)
downloadnetcosm-2a81620aa5b740d7f77aff8177a983b7492b8ea0.zip
netcosm-2a81620aa5b740d7f77aff8177a983b7492b8ea0.tar.gz
netcosm-2a81620aa5b740d7f77aff8177a983b7492b8ea0.tar.bz2
netcosm-2a81620aa5b740d7f77aff8177a983b7492b8ea0.tar.xz
tons of stuff
-rw-r--r--.gitignore1
-rw-r--r--Makefile24
-rw-r--r--src/auth.c12
-rw-r--r--src/client.c38
-rw-r--r--src/hash.c23
-rw-r--r--src/hash.h26
-rw-r--r--src/netcosm.h101
-rw-r--r--src/room.c192
-rw-r--r--src/server.c95
-rw-r--r--worlds/test.c17
10 files changed, 403 insertions, 126 deletions
diff --git a/.gitignore b/.gitignore
index e0cceb0..0198daa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
users.dat
+world.dat
a.out
*.bin
*.o
diff --git a/Makefile b/Makefile
index 17b4786..b2a693a 100644
--- a/Makefile
+++ b/Makefile
@@ -4,18 +4,26 @@ PLATFORM = unix
NETCOSM_OBJ = src/server.o src/client.o src/auth.o src/telnet.o src/util.o src/room.o worlds/test.o src/hash.o
-CFLAGS = -Og -g -I src/ -I target/$(PLATFORM) -Wall -Wextra -Wshadow -Wpedantic
+CFLAGS = -Og -g -I src/ -I target/$(PLATFORM) -Wall -Wextra -Wshadow -std=gnu99
LDFLAGS = -lgcrypt
-all: $(OUT)/$(PLATFORM).bin Makefile
+HEADERS = src/netcosm.h src/hash.h src/telnet.h
-$(OUT)/$(PLATFORM).bin: $(NETCOSM_OBJ) Makefile
- mkdir -p $(OUT)
- $(CC) $(NETCOSM_OBJ) $(CFLAGS) $(LDFLAGS) -o $(OUT)/$(PLATFORM).bin
+all: $(OUT)/$(PLATFORM).bin Makefile $(HEADERS)
+
+$(OUT)/$(PLATFORM).bin: $(NETCOSM_OBJ) $(HEADERS) Makefile
+ @mkdir -p $(OUT)
+ @echo "LD $<"
+ @$(CC) $(NETCOSM_OBJ) $(CFLAGS) $(LDFLAGS) -o $(OUT)/$(PLATFORM).bin
install: $(OUT)/$(PLATFORM).bin
- install $(OUT)/$(PLATFORM).bin /bin/netcosm
+ @install $(OUT)/$(PLATFORM).bin /bin/netcosm
clean:
- rm -f $(OUT)/$(PLATFORM).bin
- rm -f $(NETCOSM_OBJ)
+ @echo "Cleaning build directory..."
+ @rm -f $(OUT)/$(PLATFORM).bin
+ @rm -f $(NETCOSM_OBJ)
+
+%.o: %.c Makefile $(HEADERS)
+ @echo "CC $<"
+ @$(CC) $(CFLAGS) $(OPTFLAGS) -c $< -o $@
diff --git a/src/auth.c b/src/auth.c
index 03f0ad3..c771747 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -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
diff --git a/src/hash.c b/src/hash.c
index 2ca757c..52a5b93 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -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;
+ }
+}
diff --git a/src/hash.h b/src/hash.h
index 7713885..ae86b26 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -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*);
diff --git a/src/room.c b/src/room.c
index e459ac8..fb8d138 100644
--- a/src/room.c
+++ b/src/room.c
@@ -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;
diff --git a/worlds/test.c b/worlds/test.c
index ee39bd5..35ad50d 100644
--- a/worlds/test.c
+++ b/worlds/test.c
@@ -5,7 +5,7 @@ const struct roomdata_t netcosm_world[] = {
"starting_room",
"Starting Room",
"You are in the starting room.\nThere are exits to the west and the east.",
- { NONE_N, NONE_NE, "east_room", NONE_SE, NONE_S, NONE_SW, "west_room", NONE_NW, NONE_UP, NONE_DN },
+ { NONE_N, NONE_NE, "east_room", NONE_SE, NONE_S, NONE_SW, "west_room", NONE_NW, NONE_UP, NONE_DN, NONE_IN, NONE_OT },
NULL,
NULL,
NULL,
@@ -16,7 +16,7 @@ const struct roomdata_t netcosm_world[] = {
"west_room",
"West Room",
"You are in the west room.\nThere is an exit to the east.",
- { NONE_N, NONE_NE, "starting_room", NONE_SE, NONE_S, NONE_SW, NONE_W, NONE_NW, NONE_UP, NONE_DN },
+ { NONE_N, NONE_NE, "starting_room", NONE_SE, NONE_S, NONE_SW, NONE_W, NONE_NW, NONE_UP, NONE_DN, NONE_IN, NONE_OT },
NULL,
NULL,
NULL,
@@ -27,13 +27,24 @@ const struct roomdata_t netcosm_world[] = {
"east_room",
"East Room",
"You are in the east room.\nThere is an exit to the west.",
- { NONE_N, NONE_NE, NONE_E, NONE_SE, NONE_S, NONE_SW, "starting_room", NONE_NW, NONE_UP, NONE_DN },
+ { NONE_N, NONE_NE, NONE_E, NONE_SE, NONE_S, NONE_SW, "starting_room", NONE_NW, NONE_UP, NONE_DN, NONE_IN, NONE_OT },
NULL,
NULL,
NULL,
NULL,
},
+ {
+ "test",
+ "blah",
+ "blah",
+ { "starting_room", NONE_NE, NONE_E, NONE_SE, NONE_S, NONE_SW, "starting_room", NONE_NW, NONE_UP, NONE_DN, NONE_IN, NONE_OT },
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ },
+
};
const size_t netcosm_world_sz = ARRAYLEN(netcosm_world);