aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2016-01-26 19:22:53 -0500
committerFranklin Wei <git@fwei.tk>2016-01-26 19:27:13 -0500
commit3b8df7146fe31518080f3a38eee98222d97ee5b2 (patch)
tree7fd7dffd98d0bfd3bdf20e24b184ec5440ca3909 /src
parentcbe6bc14de8ad8fd035e0598a3fcc23fb38cfa1a (diff)
downloadnetcosm-3b8df7146fe31518080f3a38eee98222d97ee5b2.zip
netcosm-3b8df7146fe31518080f3a38eee98222d97ee5b2.tar.gz
netcosm-3b8df7146fe31518080f3a38eee98222d97ee5b2.tar.bz2
netcosm-3b8df7146fe31518080f3a38eee98222d97ee5b2.tar.xz
fix a memory leak, bumps version to 0.4.0-rc1
Diffstat (limited to 'src')
-rw-r--r--src/auth.c6
-rw-r--r--src/client.c10
-rw-r--r--src/globals.h6
-rw-r--r--src/obj.c106
-rw-r--r--src/obj.h86
-rw-r--r--src/room.c10
-rw-r--r--src/server_reqs.c72
-rw-r--r--src/server_reqs.h1
-rw-r--r--src/userdb.c9
-rw-r--r--src/userdb.h2
-rw-r--r--src/util.c15
-rw-r--r--src/util.h3
12 files changed, 293 insertions, 33 deletions
diff --git a/src/auth.c b/src/auth.c
index b7af56d..5fd8219 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -41,10 +41,10 @@ static char *hash_pass_hex(const char *pass, const char *salt)
SHA512(salted, pass_len + SALT_LEN, hash);
unsigned char tmp[AUTH_HASHLEN];
- /* now hash the hash half a million times to slow things down */
- for(int i = 0; i < HASH_ITERS - 1; ++i)
+ /* now hash the hash a million times to slow things down */
+ for(int i = 0; i < (HASH_ITERS / 2) - 1; ++i)
{
- memcpy(tmp, hash, AUTH_HASHLEN);
+ AUTH_HASHFUNC(hash, AUTH_HASHLEN, tmp);
AUTH_HASHFUNC(tmp, AUTH_HASHLEN, hash);
}
memset(tmp, 0, sizeof(tmp));
diff --git a/src/client.c b/src/client.c
index 3fab9cb..6812702 100644
--- a/src/client.c
+++ b/src/client.c
@@ -436,6 +436,11 @@ void client_inventory(void)
send_master(REQ_PRINTINVENTORY, NULL, 0);
}
+void client_drop(char *what)
+{
+ send_master(REQ_DROP, what, strlen(what) + 1);
+}
+
#define WSPACE " \t\r\n"
void client_main(int fd, struct sockaddr_in *addr, int total, int to, int from)
@@ -739,6 +744,11 @@ auth:
else
out("Expected direction after GO.\n");
}
+ else if(!strcmp(tok, "DROP"))
+ {
+ char *what = strtok_r(NULL, " ", &save);
+ client_drop(what);
+ }
next_cmd:
diff --git a/src/globals.h b/src/globals.h
index fcf6784..5edc153 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -28,7 +28,6 @@
#include <arpa/inet.h>
#include <arpa/telnet.h>
#include <assert.h>
-#include <bsd/stdlib.h> // for arc4random
#include <bsd/string.h> // for strlcat
#include <ctype.h>
#include <errno.h>
@@ -64,9 +63,10 @@
#define WORLDFILE "world.dat"
#define LOGFILE "netcosm.log"
-#define WORLD_MAGIC 0x31415926
+#define WORLD_MAGIC 0x31415926
+#define USERDB_MAGIC 0x27182818
#define MAX_FAILURES 3
-#define NETCOSM_VERSION "0.3.0"
+#define NETCOSM_VERSION "0.4.0-rc1"
/* username length */
#define MAX_NAME_LEN 32
diff --git a/src/obj.c b/src/obj.c
new file mode 100644
index 0000000..0f9c554
--- /dev/null
+++ b/src/obj.c
@@ -0,0 +1,106 @@
+/*
+ * NetCosm - a MUD server
+ * Copyright (C) 2016 Franklin Wei
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "globals.h"
+
+#include "hash.h"
+#include "obj.h"
+
+/* map of class names -> object classes */
+static void *obj_class_map = NULL;
+
+struct object_t *obj_new(const char *class_name)
+{
+ if(!obj_class_map)
+ {
+ extern const struct obj_class_t netcosm_obj_classes[];
+ extern const size_t netcosm_obj_classes_sz;
+ obj_class_map = hash_init(netcosm_obj_classes_sz / 2 + 1,
+ hash_djb,
+ compare_strings);
+ for(unsigned i = 0; i < netcosm_obj_classes_sz; ++i)
+ {
+ if(hash_insert(obj_class_map,
+ netcosm_obj_classes[i].class_name,
+ netcosm_obj_classes + i))
+ error("duplicate object class name");
+ }
+ }
+
+ struct object_t *obj = calloc(1, sizeof(struct object_t));
+
+ obj->class = hash_lookup(obj_class_map, class_name);
+ if(!obj->class)
+ {
+ free(obj);
+ error("unknown object class '%s'", class_name);
+ }
+ else
+ return obj;
+}
+
+void obj_write(int fd, struct object_t *obj)
+{
+ write_string(fd, obj->class->class_name);
+ write_string(fd, obj->name);
+ write_bool(fd, obj->list);
+
+ if(obj->class->hook_serialize)
+ obj->class->hook_serialize(fd, obj);
+}
+
+struct object_t *obj_read(int fd)
+{
+ char *class_name = read_string(fd);
+ struct object_t *obj = obj_new(class_name);
+ free(class_name);
+
+ obj->name = read_string(fd);
+ obj->list = read_bool(fd);
+ if(obj->class->hook_deserialize)
+ obj->class->hook_deserialize(fd, obj);
+
+ return obj;
+}
+
+struct object_t *obj_dup(struct object_t *obj)
+{
+ struct object_t *new = calloc(1, sizeof(struct object_t));
+ memcpy(new, obj, sizeof(*new));
+ new->name = strdup(obj->name);
+ new->userdata = obj->class->hook_clone(obj->userdata);
+ return new;
+}
+
+void obj_free(void *ptr)
+{
+ struct object_t *obj = ptr;
+ debugf("Freeing obj %s\n", obj->name);
+
+ if(obj->class->hook_destroy)
+ obj->class->hook_destroy(obj);
+
+ free(obj->name);
+ free(obj);
+}
+
+void obj_shutdown(void)
+{
+ hash_free(obj_class_map);
+ obj_class_map = NULL;
+}
diff --git a/src/obj.h b/src/obj.h
new file mode 100644
index 0000000..240b4a9
--- /dev/null
+++ b/src/obj.h
@@ -0,0 +1,86 @@
+/*
+ * NetCosm - a MUD server
+ * Copyright (C) 2016 Franklin Wei
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "globals.h"
+
+#include "room.h"
+
+/* Objects belong to an object class. Objects define their object
+ * class through the class name, which is converted to a class ID
+ * internally.
+ */
+
+struct object_t;
+
+typedef struct child_data user_t; // see server.h for the definition
+
+struct obj_class_t {
+ const char *class_name;
+
+ /* write an object's user data to disk */
+ void (*hook_serialize)(int fd, struct object_t*);
+
+ /* read an object's user data */
+ void (*hook_deserialize)(int fd, struct object_t*);
+
+ /* called when an object is taken;
+ * true = can take
+ * false = can't take
+ * no function (NULL) = can take */
+ bool (*hook_take)(struct object_t*, user_t *user);
+
+ /* called when dropping an object;
+ * true: can drop
+ * false: can't drop
+ * NULL: can drop
+ */
+ bool (*hook_drop)(struct object_t*, user_t *user);
+ void* (*hook_clone)(void*); /* clone the user data pointer */
+ void (*hook_destroy)(struct object_t*);
+ const char* (*hook_desc)(struct object_t*, user_t*);
+};
+
+struct object_t {
+ char *name; /* no articles: "a", "an", "the", needs to be free()able */
+
+ struct obj_class_t *class;
+
+ bool list;
+
+ void *userdata;
+};
+
+/* returns a new object of class 'c' */
+struct object_t *obj_new(const char *c);
+
+/* serialize an object */
+void obj_write(int fd, struct object_t *obj);
+
+/* deserialize an object */
+struct object_t *obj_read(int fd);
+
+/* make a duplicate of an object
+ * used for "moving" an object */
+struct object_t *obj_dup(struct object_t *obj);
+
+void obj_free(void*);
+
+/* shut down the obj_* module */
+void obj_shutdown(void);
diff --git a/src/room.c b/src/room.c
index 848c9e5..de0950d 100644
--- a/src/room.c
+++ b/src/room.c
@@ -64,8 +64,7 @@ bool room_user_del(room_id id, struct child_data *child)
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_uint32(fd, WORLD_MAGIC);
write(fd, &world_sz, sizeof(world_sz));
write_string(fd, world_name);
for(unsigned i = 0; i < world_sz; ++i)
@@ -139,6 +138,7 @@ 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, hash_djb, compare_strings);
+ hash_setfreedata_cb(room->objects, obj_free);
}
/**
@@ -153,9 +153,8 @@ 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)
+
+ if(read_uint32(fd) != WORLD_MAGIC)
return false;
if(world)
@@ -193,7 +192,6 @@ bool world_load(const char *fname, const struct roomdata_t *data, size_t data_sz
for(unsigned j = 0; j < n_objects; ++j)
{
- debugf("READING %dth OBJECT\n", j);
struct object_t *obj = obj_read(fd);
if(!room_obj_add(i, obj))
diff --git a/src/server_reqs.c b/src/server_reqs.c
index 689c2be..f02ed1c 100644
--- a/src/server_reqs.c
+++ b/src/server_reqs.c
@@ -47,6 +47,18 @@ tryagain:
}
}
+static void __attribute__((format(printf,2,3)))
+send_msg(struct child_data *child, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ char *buf;
+ int len = vasprintf(&buf, fmt, ap);
+ va_end(ap);
+ send_packet(child, REQ_BCASTMSG, buf, len);
+ free(buf);
+}
+
static void req_pass_msg(unsigned char *data, size_t datalen,
struct child_data *sender, struct child_data *child)
{
@@ -243,9 +255,7 @@ static void req_send_geninfo(unsigned char *data, size_t datalen, struct child_d
{
(void) data;
(void) datalen;
- char buf[128];
- int len = snprintf(buf, sizeof(buf), "Total clients: %d\n", num_clients);
- send_packet(sender, REQ_BCASTMSG, buf, len);
+ send_msg(sender, "Total clients: %d\n", num_clients);
}
static void req_kick_always(unsigned char *data, size_t datalen,
@@ -267,8 +277,7 @@ static void req_look_at(unsigned char *data, size_t datalen, struct child_data *
}
else
{
- const char *msg = "I don't know what that is.\n";
- send_packet(sender, REQ_BCASTMSG, (void*)msg, strlen(msg));
+ send_msg(sender, "I don't know what that is.\n");
}
}
@@ -278,6 +287,12 @@ static void req_take(unsigned char *data, size_t datalen, struct child_data *sen
struct object_t *obj = room_obj_get(sender->room, (const char*)data);
if(obj)
{
+ if(obj->class->hook_take && !obj->class->hook_take(obj, sender))
+ {
+ send_msg(sender, "You can't take that.\n");
+ return;
+ }
+
struct object_t *dup = obj_dup(obj);
hash_insert(userdb_lookup(sender->user)->objects,
dup->name, dup);
@@ -285,11 +300,13 @@ static void req_take(unsigned char *data, size_t datalen, struct child_data *sen
room_obj_del(sender->room, (const char*)data);
world_save(WORLDFILE);
+ userdb_write(USERFILE);
+
+ send_msg(sender, "Taken.\n");
}
else
{
- const char *msg = "I don't know what that is.\n";
- send_packet(sender, REQ_BCASTMSG, (void*)msg, strlen(msg));
+ send_msg(sender, "I don't know what that is.\n");
}
}
@@ -299,22 +316,50 @@ static void req_inventory(unsigned char *data, size_t datalen, struct child_data
(void) data;
void *ptr = userdb_lookup(sender->user)->objects, *save;
- char buf[MSG_MAX] = "You currently have:\n";
- send_packet(sender, REQ_BCASTMSG, (void*)buf, strlen(buf));
+ send_msg(sender, "You currently have:\n");
while(1)
{
struct object_t *obj = hash_iterate(ptr, &save, NULL);
+
if(!obj)
break;
+
ptr = NULL;
+
+ char buf[MSG_MAX];
int len = snprintf(buf, sizeof(buf), "A %s\n", obj->name);
+
send_packet(sender, REQ_BCASTMSG, (void*)buf, len);
}
- const char *msg = "Nothing!\n";
if(ptr)
- send_packet(sender, REQ_BCASTMSG, (void*)msg, strlen(msg));
+ send_msg(sender, "Nothing!\n");
+}
+
+static void req_drop(unsigned char *data, size_t datalen, struct child_data *sender)
+{
+ (void) datalen;
+ (void) data;
+
+ struct userdata_t *user = userdb_lookup(sender->user);
+ if(!user)
+ return;
+ struct object_t *obj = hash_lookup(user->objects, (const char*)data);
+ if(!obj)
+ {
+ send_msg(sender, "You don't have that.\n");
+ return;
+ }
+
+ struct object_t *dup = obj_dup(obj);
+ room_obj_add(sender->room, dup);
+ hash_remove(user->objects, (const char*)data);
+
+ send_msg(sender, "Dropped.\n");
+
+ world_save(WORLDFILE);
+ userdb_write(USERFILE);
}
static const struct child_request {
@@ -347,8 +392,9 @@ static const struct child_request {
{ REQ_ADDUSERDATA, true, CHILD_NONE, NULL, req_add_user, },
{ REQ_KICKALL, true, CHILD_ALL_BUT_SENDER, req_kick_always, NULL, },
{ REQ_LOOKAT, true, CHILD_NONE, NULL, req_look_at, },
- { REQ_TAKE, true, CHILD_NONE, NULL, req_take },
- { REQ_PRINTINVENTORY, false, CHILD_NONE, NULL, req_inventory },
+ { REQ_TAKE, true, CHILD_NONE, NULL, req_take, },
+ { REQ_PRINTINVENTORY, false, CHILD_NONE, NULL, req_inventory, },
+ { REQ_DROP, true, CHILD_NONE, NULL, req_drop, },
//{ REQ_ROOMMSG, true, CHILD_ALL, req_send_room_msg, NULL, },
};
diff --git a/src/server_reqs.h b/src/server_reqs.h
index 8b455ce..2b3d08f 100644
--- a/src/server_reqs.h
+++ b/src/server_reqs.h
@@ -41,6 +41,7 @@
#define REQ_LOOKAT 19 /* server: send object description */
#define REQ_TAKE 20 /* server: add object to user inventory */
#define REQ_PRINTINVENTORY 21 /* server: print user inventory */
+#define REQ_DROP 22 /* server: drop user object if allowed */
/* child states, sent as an int to the master */
#define STATE_INIT 0 /* initial state */
diff --git a/src/userdb.c b/src/userdb.c
index 5e948ab..5c80581 100644
--- a/src/userdb.c
+++ b/src/userdb.c
@@ -30,8 +30,6 @@ static void free_userdata_and_objs(void *ptr)
{
struct userdata_t *data = ptr;
- debugf("Freeing DATA AND OBJECTS of %s\n", data->username);
-
if(data->objects)
{
hash_setfreedata_cb(data->objects, obj_free);
@@ -66,6 +64,8 @@ void userdb_init(const char *file)
/* 0 is a valid fd */
if(fd >= 0)
{
+ if(read_uint32(fd) != USERDB_MAGIC)
+ error("bad userdb magic value");
while(1)
{
struct userdata_t *data = calloc(1, sizeof(*data));
@@ -87,8 +87,6 @@ void userdb_init(const char *file)
hash_djb,
compare_strings);
- debugf("READING %d OBJECTS INTO INVENTORY\n", n_objects);
-
for(unsigned i = 0; i < n_objects; ++i)
{
struct object_t *obj = obj_read(fd);
@@ -105,6 +103,7 @@ void userdb_init(const char *file)
void userdb_write(const char *file)
{
int fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ write_uint32(fd, USERDB_MAGIC);
void *save, *ptr = map;
while(1)
{
@@ -123,8 +122,6 @@ void userdb_write(const char *file)
write(fd, &n_objects, sizeof(n_objects));
- debugf("WRITING %d OBJECTS\n", n_objects);
-
/* write objects */
if(n_objects)
diff --git a/src/userdb.h b/src/userdb.h
index c4705a9..2f122a9 100644
--- a/src/userdb.h
+++ b/src/userdb.h
@@ -30,7 +30,7 @@ struct userdata_t {
char salt[SALT_LEN + 1];
- /* in hex + NULL terminator */
+ /* in lowercase hex + NULL terminator */
char passhash[AUTH_HASHLEN * 2 + 1];
priv_t priv;
diff --git a/src/util.c b/src/util.c
index 3da294b..85914ca 100644
--- a/src/util.c
+++ b/src/util.c
@@ -95,7 +95,6 @@ char *read_string(int fd)
{
error("read_string: EOF");
}
- debugf("sz is %d\n", sz);
char *ret = malloc(sz + 1);
if(read(fd, ret, sz) < 0)
{
@@ -119,3 +118,17 @@ void write_bool(int fd, bool b)
if(write(fd, &b, sizeof(b)) != sizeof(b))
error("write failed");
}
+
+uint32_t read_uint32(int fd)
+{
+ uint32_t ret;
+ if(read(fd, &ret, sizeof(ret)) != sizeof(ret))
+ error("unexpected EOF");
+ return ret;
+}
+
+void write_uint32(int fd, uint32_t b)
+{
+ if(write(fd, &b, sizeof(b)) != sizeof(b))
+ error("write failed");
+}
diff --git a/src/util.h b/src/util.h
index fefd735..02030c2 100644
--- a/src/util.h
+++ b/src/util.h
@@ -36,3 +36,6 @@ room_id read_roomid(int fd);
void write_bool(int fd, bool b);
bool read_bool(int fd);
+
+void write_uint32(int fd, uint32_t i);
+uint32_t read_uint32(int fd);