aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2016-01-24 16:58:59 -0500
committerFranklin Wei <git@fwei.tk>2016-01-24 16:58:59 -0500
commitb346e948cb167c18efc33f32f0e7cfb21050fc96 (patch)
tree2a6989023690021c15999ce8fc3fefdca3ab7d83 /src
parente2c2a9878a0fb55923fbd77db1f73085013aa36c (diff)
downloadnetcosm-b346e948cb167c18efc33f32f0e7cfb21050fc96.zip
netcosm-b346e948cb167c18efc33f32f0e7cfb21050fc96.tar.gz
netcosm-b346e948cb167c18efc33f32f0e7cfb21050fc96.tar.bz2
netcosm-b346e948cb167c18efc33f32f0e7cfb21050fc96.tar.xz
objects partially implemented, fixes some bugs
Diffstat (limited to 'src')
-rw-r--r--src/client.c18
-rw-r--r--src/globals.h23
-rw-r--r--src/hash.c2
-rw-r--r--src/room.c71
-rw-r--r--src/room.h14
-rw-r--r--src/server.c10
-rw-r--r--src/server_reqs.c43
-rw-r--r--src/telnet.c13
-rw-r--r--src/userdb.c1
-rw-r--r--src/util.h2
10 files changed, 137 insertions, 60 deletions
diff --git a/src/client.c b/src/client.c
index cbfe63b..fef7fab 100644
--- a/src/client.c
+++ b/src/client.c
@@ -71,7 +71,8 @@ void __attribute__((format(printf,1,2))) out(const char *fmt, ...)
/* do some line wrapping */
- int pos = 0, last_space = 0;
+ static int pos = 0;
+ int last_space = 0;
char *ptr = buf;
uint16_t line_width = telnet_get_width() + 1;
char *line_buf = malloc(line_width + 2);
@@ -168,8 +169,6 @@ void send_master(unsigned char cmd, const void *data, size_t sz)
while(!request_complete) poll_requests();
free(req);
-
- debugf("done with request\n");
}
#define BUFSZ 128
@@ -362,7 +361,7 @@ void client_change_room(room_id id)
void *dir_map = NULL;
-void client_move(const char *dir)
+bool client_move(const char *dir)
{
const struct dir_pair {
const char *text;
@@ -401,9 +400,16 @@ void client_move(const char *dir)
if(pair)
{
send_master(REQ_MOVE, &pair->val, sizeof(pair->val));
+ if(reqdata_type == TYPE_BOOLEAN && returned_reqdata.boolean)
+ return true;
+ else
+ return false;
}
else
+ {
out("Unknown direction.\n");
+ return false;
+ }
}
void client_look(void)
@@ -695,8 +701,8 @@ auth:
if(dir)
{
all_upper(dir);
- client_move(dir);
- client_look();
+ if(client_move(dir))
+ client_look();
}
else
out("Expected direction after GO.\n");
diff --git a/src/globals.h b/src/globals.h
index 1daac8e..9944996 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -28,6 +28,7 @@
#include <arpa/inet.h>
#include <arpa/telnet.h>
#include <assert.h>
+#include <bsd/stdlib.h> // for arc4random
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -46,6 +47,7 @@
#include <sys/ipc.h>
#include <sys/mman.h>
#include <sys/socket.h>
+#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
@@ -90,3 +92,24 @@
#else
#define debugf(fmt,...) /* nop */
#endif
+
+#if 0
+extern bool are_child;
+
+static void *logged_malloc(const char *func, int line, size_t sz)
+{
+ if(are_child)
+ debugf("%s:%d mallocs %d bytes\n", func, line, sz);
+ return malloc(sz);
+}
+
+static void *logged_calloc(const char *func, int line, size_t x, size_t y)
+{
+ if(are_child)
+ debugf("%s:%d callocs %dx%d bytes\n", func, line, x,y);
+ return calloc(x,y);
+}
+
+#define malloc(x) logged_malloc(__func__, __LINE__, x)
+#define calloc(x,y) logged_calloc(__func__, __LINE__, x,y)
+#endif
diff --git a/src/hash.c b/src/hash.c
index a45ab54..a34e530 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -60,6 +60,8 @@ void *hash_init(size_t sz, unsigned (*hash_fn)(const void*),
int (*compare_keys)(const void*, const void*))
{
struct hash_map *ret = calloc(sizeof(struct hash_map), 1);
+ if(!sz)
+ sz = 1;
ret->table = calloc(sz, sizeof(struct hash_node*));
ret->table_sz = sz;
ret->hash = hash_fn;
diff --git a/src/room.c b/src/room.c
index 82cf8db..eaa8cf1 100644
--- a/src/room.c
+++ b/src/room.c
@@ -42,17 +42,23 @@ bool room_user_add(room_id id, struct child_data *child)
if(!room)
error("unknown room %d", id);
- if(hash_insert(room->users, &child->pid, child))
- return false;
+ if(child->user)
+ {
+ /* hash_insert returns NULL on success */
+ return !hash_insert(room->users, child->user, child);
+ }
else
- return true;
+ return false;
}
bool room_user_del(room_id id, struct child_data *child)
{
struct room_t *room = room_get(id);
- return hash_remove(room->users, &child->pid);
+ if(child->user)
+ return hash_remove(room->users, child->user);
+ else
+ return false;
}
void write_roomid(int fd, room_id *id)
@@ -116,6 +122,8 @@ static void room_free(struct room_t *room)
{
hash_free(room->users);
room->users = NULL;
+ hash_free(room->objects);
+ room->objects = NULL;
free(room->data.name);
free(room->data.desc);
}
@@ -135,8 +143,52 @@ void world_free(void)
}
}
-static SIMP_HASH(pid_t, pid_hash);
-static SIMP_EQUAL(pid_t, pid_equal);
+struct object_t *obj_new(void)
+{
+ struct object_t *new = calloc(1, sizeof(struct object_t));
+ /* generate a unique 128-bit id for this object */
+ /* 64 bits are used to store a nanosecond-resolution timestamp */
+ /* 64 random bits are also used */
+ uint64_t timestamp;
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ timestamp = (obj_id)tv.tv_sec * (obj_id)1000000 + (obj_id)tv.tv_usec;
+
+ uint64_t rand_bits;
+ arc4random_buf(&rand_bits, sizeof(rand_bits));
+
+ new->id = ((obj_id)timestamp << 64) | (obj_id)rand_bits;
+
+ unsigned char bytes[16];
+ memcpy(bytes, &new->id, sizeof(bytes));
+ debugf("UUID: ");
+ for(unsigned i = 0; i < sizeof(bytes); ++i)
+ {
+ if(i == 4 || i == 6 || i == 8 || i == 10)
+ debugf("-");
+ debugf("%02x", bytes[15 - i]);
+ }
+ debugf("\n");
+
+ return new;
+}
+
+bool obj_add(room_id room, struct object_t *obj)
+{
+ return !hash_insert(room_get(room)->objects, &obj->id, obj);
+}
+
+static SIMP_HASH(obj_id, obj_hash);
+static SIMP_EQUAL(obj_id, obj_equal);
+
+#define OBJMAP_SIZE 8
+
+/* initialize the room's hash tables */
+static void room_init_maps(struct room_t *room)
+{
+ room->users = hash_init((userdb_size() / 2) + 1, hash_djb, compare_strings);
+ room->objects = hash_init(OBJMAP_SIZE, obj_hash, obj_equal);
+}
/**
* Loads a world using data on disk and in memory.
@@ -175,7 +227,7 @@ bool world_load(const char *fname, const struct roomdata_t *data, size_t data_sz
for(unsigned i = 0; i < world_sz; ++i)
{
- world[i].users = hash_init((userdb_size() / 2) + 1, pid_hash, pid_equal);
+ room_init_maps(world + i);
world[i].id = read_roomid(fd);
memcpy(&world[i].data, data + i, sizeof(struct roomdata_t));
@@ -200,7 +252,7 @@ void world_init(const struct roomdata_t *data, size_t sz, const char *name)
world_sz = 0;
world_name = strdup(name);
- void *map = hash_init(1, hash_djb, compare_strings);
+ void *map = hash_init(sz / 2 + 1, hash_djb, compare_strings);
for(size_t i = 0; i < sz; ++i)
{
@@ -226,8 +278,7 @@ void world_init(const struct roomdata_t *data, size_t sz, const char *name)
world[i].adjacent[dir] = room->id;
}
}
-
- world[i].users = hash_init((userdb_size() / 2) + 1, pid_hash, pid_equal);
+ room_init_maps(world + i);
world_sz = i + 1;
}
diff --git a/src/room.h b/src/room.h
index c973b6a..d0c1fdb 100644
--- a/src/room.h
+++ b/src/room.h
@@ -48,7 +48,7 @@ struct roomdata_t {
};
struct object_t {
- obj_id id;
+ obj_id id; // don't modify
const char *name; /* no articles: "a", "an", "the" */
@@ -62,7 +62,7 @@ struct object_t {
void (*hook_drop)(struct object_t*, user_t *user);
void (*hook_use)(struct object_t*, user_t *user);
void (*hook_destroy)(struct object_t*);
- char* (*hook_desc)(struct object_t*, user_t*);
+ const char* (*hook_desc)(struct object_t*, user_t*);
};
struct verb_t {
@@ -79,9 +79,9 @@ struct room_t {
room_id adjacent[NUM_DIRECTIONS];
/* hash maps */
- void *objects;
+ void *objects; /* obj_id -> object */
void *verbs;
- void *users; /* PID -> user_t */
+ void *users; /* username -> child_data */
};
/* room/world */
@@ -93,10 +93,10 @@ 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);
-/* returns a new object */
+/* returns a new object with a unique id */
struct object_t *obj_new(void);
-/* new should point to a statically allocated object */
-void obj_add(room_id room, struct object_t *new);
+/* new should point to a new object allocated with obj_new */
+bool obj_add(room_id room, struct object_t *new);
void world_free(void);
diff --git a/src/server.c b/src/server.c
index 6ce4de4..b8d5bb4 100644
--- a/src/server.c
+++ b/src/server.c
@@ -76,8 +76,11 @@ static void handle_disconnects(void)
pid_t pid;
while((pid = waitpid(-1, NULL, WNOHANG)) > 0)
{
+ struct child_data *child = hash_lookup(child_map, &pid);
+
debugf("Client disconnect.\n");
- //struct child_data *child = hash_lookup(child_map, &pid);
+
+ room_user_del(child->room, child);
--num_clients;
@@ -130,7 +133,7 @@ static void __attribute__((noreturn)) serv_cleanup(void)
ev_default_destroy();
- _exit(0);
+ exit(0);
}
static void __attribute__((noreturn)) sigint_handler(int s)
@@ -228,7 +231,7 @@ static void new_connection_cb(EV_P_ ev_io *w, int revents)
if(pipe2(readpipe, O_DIRECT) < 0)
error("error creating pipe, need linux kernel >= 3.4");
- if(pipe2(outpipe, O_NONBLOCK | O_DIRECT) < 0)
+ if(pipe2(outpipe, O_DIRECT) < 0)
error("error creating pipe, need linux kernel >= 3.4");
pid_t pid = fork();
@@ -281,6 +284,7 @@ static void new_connection_cb(EV_P_ ev_io *w, int revents)
ev_io *new_io_watcher = calloc(1, sizeof(ev_io));
ev_io_init(new_io_watcher, childreq_cb, new->readpipe[0], EV_READ);
+ ev_set_priority(new_io_watcher, EV_MINPRI);
ev_io_start(EV_A_ new_io_watcher);
new->io_watcher = new_io_watcher;
diff --git a/src/server_reqs.c b/src/server_reqs.c
index 5a15812..d10acde 100644
--- a/src/server_reqs.c
+++ b/src/server_reqs.c
@@ -29,6 +29,13 @@ static void send_packet(struct child_data *child, unsigned char cmd,
assert(datalen < MSG_MAX);
unsigned char pkt[MSG_MAX];
pkt[0] = cmd;
+
+ //if((data?datalen:0) + 1 > MSG_MAX && cmd == REQ_BCASTMSG)
+ //{
+ // /* TODO: split long messages */
+ // ;
+ //}
+
if(data && datalen)
memcpy(pkt + 1, data, datalen);
tryagain:
@@ -46,6 +53,8 @@ static void req_pass_msg(unsigned char *data, size_t datalen,
(void) sender;
send_packet(child, REQ_BCASTMSG, data, datalen);
+ if(child->pid != sender->pid)
+ send_packet(child, REQ_ALLDONE, NULL, 0);
}
static void req_send_clientinfo(unsigned char *data, size_t datalen,
@@ -84,8 +93,6 @@ static void req_change_state(unsigned char *data, size_t datalen,
(void) data; (void) datalen; (void) child; (void) sender;
if(datalen == sizeof(sender->state))
sender->state = *((int*)data);
- else
- debugf("State data is of the wrong size %*s\n", datalen, data);
}
static void req_change_user(unsigned char *data, size_t datalen,
@@ -112,7 +119,7 @@ static void req_kick_client(unsigned char *data, size_t datalen,
{
pid_t kicked_pid = *((pid_t*)data);
if(kicked_pid == child->pid)
- send_packet(child, REQ_BCASTMSG, data + sizeof(pid_t), datalen - sizeof(pid_t));
+ send_packet(child, REQ_KICK, data + sizeof(pid_t), datalen - sizeof(pid_t));
}
}
@@ -128,6 +135,7 @@ static void req_send_desc(unsigned char *data, size_t datalen, struct child_data
struct room_t *room = room_get(sender->room);
send_packet(sender, REQ_BCASTMSG, room->data.desc, strlen(room->data.desc));
+
send_packet(sender, REQ_PRINTNEWLINE, NULL, 0);
}
@@ -189,10 +197,7 @@ static void req_send_user(unsigned char *data, size_t datalen, struct child_data
}
debugf("looking up user %s failed\n", data);
- debugf("failure 2\n");
}
-
- debugf("failure 1\n");
}
static void req_del_user(unsigned char *data, size_t datalen, struct child_data *sender)
@@ -298,20 +303,23 @@ void reqmap_free(void)
* 7. Parent spins until the needed number of signals is reached.
*/
+static unsigned char packet[MSG_MAX + 1];
+
bool handle_child_req(int in_fd)
{
- unsigned char packet[MSG_MAX + 1];
-
ssize_t packet_len = read(in_fd, packet, MSG_MAX);
- struct child_data *sender = NULL;
+ if((size_t)packet_len < sizeof(pid_t) + 1)
+ {
+ /* the pipe is probably broken (i.e. disconnect), so we don't
+ * try to send a reply */
+ return false;
+ }
- if(packet_len <= 0)
- goto fail;
+ struct child_data *sender = NULL;
pid_t sender_pid;
memcpy(&sender_pid, packet, sizeof(pid_t));
- debugf("servreq: Got request from PID %d\n", sender_pid);
sender = hash_lookup(child_map, &sender_pid);
@@ -328,6 +336,8 @@ bool handle_child_req(int in_fd)
struct child_request *req = hash_lookup(request_map, &cmd);
+ debugf("Child %d sends request %d\n", sender_pid, cmd);
+
if(!req)
{
debugf("Unknown request.\n");
@@ -360,8 +370,6 @@ bool handle_child_req(int in_fd)
if(child->pid == sender->pid)
continue;
- debugf("iterating over child %d\n", child->pid);
-
switch(req->which)
{
case CHILD_ALL:
@@ -375,19 +383,14 @@ bool handle_child_req(int in_fd)
finish:
- debugf("finalizing request\n");
-
if(req && req->finalize)
req->finalize(data, datalen, sender);
/* fall through */
fail:
+
if(sender)
- {
send_packet(sender, REQ_ALLDONE, NULL, 0);
- debugf("sending all done code\n");
- }
-
return true;
}
diff --git a/src/telnet.c b/src/telnet.c
index a28752a..743eb53 100644
--- a/src/telnet.c
+++ b/src/telnet.c
@@ -42,8 +42,6 @@ enum telnet_status telnet_parse_data(const unsigned char *buf, size_t buflen)
bool in_sb = false;
bool line_done = false;
- debugf("telnet: ");
-
for(unsigned i = 0; i < buflen; ++i)
{
unsigned char c = buf[i];
@@ -51,16 +49,12 @@ enum telnet_status telnet_parse_data(const unsigned char *buf, size_t buflen)
if(c == IAC)
iac = true;
else if(c == '\n' || c == '\r')
- {
- debugf("found newline, done reading.\n");
line_done = true;
- }
if(iac)
{
if(TELCMD_OK(c))
{
- debugf("%s ", TELCMD(c));
found_cmd = true;
switch(c)
{
@@ -78,7 +72,7 @@ enum telnet_status telnet_parse_data(const unsigned char *buf, size_t buflen)
while(j < 4 && i < buflen)
{
bytes[j++] = buf[++i];
- debugf("%d ", buf[j - 1]);
+ //debugf("%d ", buf[j - 1]);
if(bytes[j - 1] == 255) /* 255 is doubled to distinguish from IAC */
{
++i;
@@ -94,13 +88,8 @@ enum telnet_status telnet_parse_data(const unsigned char *buf, size_t buflen)
continue;
}
}
- debugf("%d ", c);
}
- debugf("\n");
- if(found_cmd)
- debugf("telnet: is NOT data\n");
-
return found_cmd ? TELNET_FOUNDCMD :
(line_done ? TELNET_LINEOVER : TELNET_DATA);
}
diff --git a/src/userdb.c b/src/userdb.c
index 2d7702c..3a7ebbc 100644
--- a/src/userdb.c
+++ b/src/userdb.c
@@ -156,7 +156,6 @@ struct userdata_t *userdb_request_lookup(const char *name)
if(are_child)
{
send_master(REQ_GETUSERDATA, name, strlen(name) + 1);
- debugf("returned reqdata is of type %d\n", reqdata_type);
if(reqdata_type == TYPE_USERDATA)
return &returned_reqdata.userdata;
return NULL;
diff --git a/src/util.h b/src/util.h
index 8cc44d5..3d7287a 100644
--- a/src/util.h
+++ b/src/util.h
@@ -21,6 +21,6 @@
/* utility functions */
void __attribute__((noreturn,format(printf,1,2))) error(const char *fmt, ...);
-void debugf_real(const char*, int, const char*, const char *fmt, ...);
+void __attribute__((format(printf,4,5))) debugf_real(const char*, int, const char*, const char *fmt, ...);
void remove_cruft(char*);
void all_upper(char*);