aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2016-02-16 21:17:46 -0500
committerFranklin Wei <git@fwei.tk>2016-02-16 21:17:46 -0500
commit02de31c48c021742c6245b711790f6d853866c36 (patch)
treed145f3ce9156de42064f8bceb3d0eb4362e3bb5a /src
parent8c58ee885941af4c944995b029363f139b8f54bd (diff)
downloadnetcosm-02de31c48c021742c6245b711790f6d853866c36.zip
netcosm-02de31c48c021742c6245b711790f6d853866c36.tar.gz
netcosm-02de31c48c021742c6245b711790f6d853866c36.tar.bz2
netcosm-02de31c48c021742c6245b711790f6d853866c36.tar.xz
refactor client_ module
Diffstat (limited to 'src')
-rw-r--r--src/client.c275
-rw-r--r--src/client.h17
-rw-r--r--src/client_reqs.c286
-rw-r--r--src/client_reqs.h46
-rw-r--r--src/server.c4
5 files changed, 345 insertions, 283 deletions
diff --git a/src/client.c b/src/client.c
index a90dc4b..7ed0df5 100644
--- a/src/client.c
+++ b/src/client.c
@@ -26,9 +26,9 @@
#include "telnet.h"
#include "util.h"
-static bool admin = false;
+bool are_admin = false;
-static int client_fd, to_parent, from_parent;
+int client_fd, to_parent, from_parent;
static room_id current_room = 0;
@@ -114,63 +114,6 @@ void __attribute__((format(printf,1,2))) out(const char *fmt, ...)
free(line_buf);
}
-static volatile sig_atomic_t request_complete;
-
-/* for rate-limiting */
-static int reqs_since_ts;
-static time_t ts = 0;
-
-void send_master(unsigned char cmd, const void *data, size_t sz)
-{
- if(!admin)
- {
- time_t t = time(NULL);
- if(ts != t)
- {
- ts = t;
- reqs_since_ts = 0;
- }
- if(reqs_since_ts++ > 10)
- {
- out("Rate limit exceeded.\n");
- return;
- }
- }
-
- request_complete = 0;
-
- pid_t our_pid = getpid();
-
- if(!data)
- sz = 0;
-
- /* format of child->parent packets:
- * | PID | CMD | DATA |
- */
-
- /* pack it all into one write so it's atomic */
- char *req = malloc(sizeof(pid_t) + 1 + sz);
-
- memcpy(req, &our_pid, sizeof(pid_t));
- memcpy(req + sizeof(pid_t), &cmd, 1);
- if(data)
- memcpy(req + sizeof(pid_t) + 1, data, sz);
-
- assert(1 + sizeof(pid_t) + sz <= MSG_MAX);
- write(to_parent, req, 1 + sizeof(pid_t) + sz);
-
- /* poll till we get data */
- struct pollfd pfd;
- pfd.fd = from_parent;
- pfd.events = POLLIN;
-
- poll(&pfd, 1, -1);
-
- while(!request_complete) poll_requests();
-
- free(req);
-}
-
#define CLIENT_READ_SZ 128
char *client_read(void)
@@ -249,211 +192,6 @@ char *client_read_password(void)
return ret;
}
-enum reqdata_typespec reqdata_type = TYPE_NONE;
-union reqdata_t returned_reqdata;
-
-bool poll_requests(void)
-{
- if(!are_child)
- return false;
-
- bool got_cmd = false;
-
- while(1)
- {
- unsigned char packet[MSG_MAX + 1];
- memset(packet, 0, sizeof(packet));
-
- ssize_t packetlen = read(from_parent, packet, MSG_MAX);
-
- unsigned char *data = packet + 1;
- size_t datalen = packetlen - 1;
- packet[MSG_MAX] = '\0';
-
- /* no data yet */
- if(packetlen < 0)
- goto fail;
-
- /* parent closed pipe */
- if(!packetlen)
- {
- debugf("master process died\n");
- exit(0);
- }
-
- got_cmd = true;
-
- unsigned char cmd = packet[0];
-
- switch(cmd)
- {
- case REQ_BCASTMSG:
- {
- out((char*)data, datalen);
- break;
- }
- case REQ_KICK:
-
- {
- out((char*)data, datalen);
- exit(EXIT_SUCCESS);
- }
- case REQ_MOVE:
- {
- int status = *((int*)data);
-
- reqdata_type = TYPE_BOOLEAN;
- returned_reqdata.boolean = status;
- if(!status)
- out("You cannot go that way.\n");
- break;
- }
- case REQ_GETUSERDATA:
- {
- if(datalen == sizeof(struct userdata_t))
- reqdata_type = TYPE_USERDATA;
- else
- break;
-
- struct userdata_t *user = &returned_reqdata.userdata;
- *user = *((struct userdata_t*)data);
- break;
- }
- case REQ_DELUSERDATA:
- {
- reqdata_type = TYPE_BOOLEAN;
- returned_reqdata.boolean = *((bool*)data);
- break;
- }
- case REQ_ADDUSERDATA:
- {
- reqdata_type = TYPE_BOOLEAN;
- returned_reqdata.boolean = *((bool*)data);
- break;
- }
- case REQ_NOP:
- break;
- case REQ_PRINTNEWLINE:
- {
- out("\n");
- break;
- }
- case REQ_ALLDONE:
- request_complete = 1;
- return true;
- default:
- debugf("WARNING: client process received unknown code %d\n", cmd);
- break;
- }
- }
-fail:
-
- return got_cmd;
-}
-
-void client_change_state(int state)
-{
- send_master(REQ_CHANGESTATE, &state, sizeof(state));
-}
-
-void client_change_user(const char *user)
-{
- send_master(REQ_CHANGEUSER, user, strlen(user) + 1);
-}
-
-void client_change_room(room_id id)
-{
- send_master(REQ_SETROOM, &id, sizeof(id));
-}
-
-void *dir_map = NULL;
-
-bool client_move(const char *dir)
-{
- const struct dir_pair {
- const char *text;
- enum direction_t val;
- } dirs[] = {
- { "N", DIR_N },
- { "NORTH", DIR_N },
- { "NE", DIR_NE },
- { "NORTHEAST", DIR_N },
- { "E", DIR_E },
- { "EAST", DIR_E },
- { "SE", DIR_SE },
- { "SOUTHEAST", DIR_SE },
- { "S", DIR_S },
- { "SOUTH", DIR_S },
- { "SW", DIR_SW },
- { "SOUTHWEST", DIR_SW },
- { "W", DIR_W },
- { "WEST", DIR_W },
- { "NW", DIR_NW },
- { "NORTHWEST", DIR_NW },
- { "U", DIR_UP },
- { "UP", DIR_UP },
- { "D", DIR_DN },
- { "DOWN", DIR_DN },
- { "IN", DIR_IN },
- { "OUT", DIR_OT },
- };
-
- if(!dir_map)
- {
- dir_map = hash_init(ARRAYLEN(dirs), hash_djb, compare_strings);
- hash_insert_pairs(dir_map, (struct hash_pair*)dirs, sizeof(struct dir_pair), ARRAYLEN(dirs));
- }
-
- struct dir_pair *pair = hash_lookup(dir_map, 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)
-{
- send_master(REQ_GETROOMNAME, NULL, 0);
- out("\n");
- send_master(REQ_GETROOMDESC, NULL, 0);
-}
-
-void client_look_at(char *obj)
-{
- all_lower(obj);
- send_master(REQ_LOOKAT, obj, strlen(obj) + 1);
-}
-
-void client_take(char *obj)
-{
- all_lower(obj);
- send_master(REQ_TAKE, obj, strlen(obj) + 1);
-}
-
-void client_inventory(void)
-{
- send_master(REQ_PRINTINVENTORY, NULL, 0);
-}
-
-void client_drop(char *what)
-{
- send_master(REQ_DROP, what, strlen(what) + 1);
-}
-
-void client_user_list(void)
-{
- send_master(REQ_LISTUSERS, NULL, 0);
-}
-
#define WSPACE " \t\r\n"
#define CMD_OK 0
@@ -721,7 +459,6 @@ void client_shutdown(void)
cmd_map = NULL;
}
-
void client_main(int fd, struct sockaddr_in *addr, int total, int to, int from)
{
client_fd = fd;
@@ -797,8 +534,8 @@ auth:
if(authlevel == PRIV_NONE)
return;
- admin = (authlevel == PRIV_ADMIN);
- if(admin)
+ are_admin = (authlevel == PRIV_ADMIN);
+ if(are_admin)
client_change_state(STATE_ADMIN);
else
client_change_state(STATE_LOGGEDIN);
@@ -827,7 +564,7 @@ auth:
all_upper(tok);
const struct client_cmd *cmd = hash_lookup(cmd_map, tok);
- if(cmd && cmd->cb && (!cmd->admin_only || (cmd->admin_only && admin)))
+ if(cmd && cmd->cb && (!cmd->admin_only || (cmd->admin_only && are_admin)))
{
int ret = cmd->cb(&save);
switch(ret)
@@ -846,7 +583,7 @@ auth:
error("client: bad callback return value");
}
}
- else if(cmd && cmd->admin_only && !admin)
+ else if(cmd && cmd->admin_only && !are_admin)
{
out("You are not allowed to do that.\n");
goto next_cmd;
diff --git a/src/client.h b/src/client.h
index 4ab7f9b..5b5c5ff 100644
--- a/src/client.h
+++ b/src/client.h
@@ -19,25 +19,18 @@
/* You should use #pragma once everywhere. */
#pragma once
+#include "globals.h"
+
+#include "client_reqs.h"
#include "room.h"
#include "userdb.h"
-enum reqdata_typespec { TYPE_NONE = 0, TYPE_USERDATA, TYPE_BOOLEAN } reqdata_type;
-
-union reqdata_t {
- struct userdata_t userdata;
- bool boolean;
-};
-
-extern enum reqdata_typespec reqdata_type;
-extern union reqdata_t returned_reqdata;
+extern int client_fd, to_parent, from_parent;
+extern bool are_admin;
/* call from child process ONLY */
void send_master(unsigned char cmd, const void *data, size_t sz);
-/* the master sends the child SIGRTMIN+0 */
-void sig_rt_0_handler(int s, siginfo_t *info, void *v);
-
void out(const char *fmt, ...) __attribute__((format(printf,1,2)));
void out_raw(const void*, size_t);
diff --git a/src/client_reqs.c b/src/client_reqs.c
new file mode 100644
index 0000000..39a67f9
--- /dev/null
+++ b/src/client_reqs.c
@@ -0,0 +1,286 @@
+/*
+ * 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 "client.h"
+#include "hash.h"
+
+enum reqdata_typespec reqdata_type = TYPE_NONE;
+union reqdata_t returned_reqdata;
+
+static int request_complete;
+
+/* for rate-limiting */
+static int reqs_since_ts;
+static time_t ts = 0;
+
+bool poll_requests(void)
+{
+ if(!are_child)
+ return false;
+
+ bool got_cmd = false;
+
+ while(1)
+ {
+ unsigned char packet[MSG_MAX + 1];
+ memset(packet, 0, sizeof(packet));
+
+ ssize_t packetlen = read(from_parent, packet, MSG_MAX);
+
+ unsigned char *data = packet + 1;
+ size_t datalen = packetlen - 1;
+ packet[MSG_MAX] = '\0';
+
+ /* no data yet */
+ if(packetlen < 0)
+ goto fail;
+
+ /* parent closed pipe */
+ if(!packetlen)
+ {
+ debugf("master process died\n");
+ exit(0);
+ }
+
+ got_cmd = true;
+
+ unsigned char cmd = packet[0];
+
+ switch(cmd)
+ {
+ case REQ_BCASTMSG:
+ {
+ out((char*)data, datalen);
+ break;
+ }
+ case REQ_KICK:
+
+ {
+ out((char*)data, datalen);
+ exit(EXIT_SUCCESS);
+ }
+ case REQ_MOVE:
+ {
+ int status = *((int*)data);
+
+ reqdata_type = TYPE_BOOLEAN;
+ returned_reqdata.boolean = status;
+ if(!status)
+ out("You cannot go that way.\n");
+ break;
+ }
+ case REQ_GETUSERDATA:
+ {
+ if(datalen == sizeof(struct userdata_t))
+ reqdata_type = TYPE_USERDATA;
+ else
+ break;
+
+ struct userdata_t *user = &returned_reqdata.userdata;
+ *user = *((struct userdata_t*)data);
+ break;
+ }
+ case REQ_DELUSERDATA:
+ {
+ reqdata_type = TYPE_BOOLEAN;
+ returned_reqdata.boolean = *((bool*)data);
+ break;
+ }
+ case REQ_ADDUSERDATA:
+ {
+ reqdata_type = TYPE_BOOLEAN;
+ returned_reqdata.boolean = *((bool*)data);
+ break;
+ }
+ case REQ_NOP:
+ break;
+ case REQ_PRINTNEWLINE:
+ {
+ out("\n");
+ break;
+ }
+ case REQ_ALLDONE:
+ request_complete = 1;
+ return true;
+ default:
+ debugf("WARNING: client process received unknown code %d\n", cmd);
+ break;
+ }
+ }
+fail:
+
+ return got_cmd;
+}
+
+void client_change_state(int state)
+{
+ send_master(REQ_CHANGESTATE, &state, sizeof(state));
+}
+
+void client_change_user(const char *user)
+{
+ send_master(REQ_CHANGEUSER, user, strlen(user) + 1);
+}
+
+void client_change_room(room_id id)
+{
+ send_master(REQ_SETROOM, &id, sizeof(id));
+}
+
+void send_master(unsigned char cmd, const void *data, size_t sz)
+{
+ if(!are_admin)
+ {
+ time_t t = time(NULL);
+ if(ts != t)
+ {
+ ts = t;
+ reqs_since_ts = 0;
+ }
+ if(reqs_since_ts++ > 10)
+ {
+ out("Rate limit exceeded.\n");
+ return;
+ }
+ }
+
+ request_complete = 0;
+
+ pid_t our_pid = getpid();
+
+ if(!data)
+ sz = 0;
+
+ /*
+ * format of child->parent packets:
+ * | PID | CMD | DATA |
+ */
+
+ /* pack it all into one write so it's atomic */
+ char *req = malloc(sizeof(pid_t) + 1 + sz);
+
+ memcpy(req, &our_pid, sizeof(pid_t));
+ memcpy(req + sizeof(pid_t), &cmd, 1);
+ if(data)
+ memcpy(req + sizeof(pid_t) + 1, data, sz);
+
+ assert(1 + sizeof(pid_t) + sz <= MSG_MAX);
+ write(to_parent, req, 1 + sizeof(pid_t) + sz);
+
+ /* poll till we get data */
+ struct pollfd pfd;
+ pfd.fd = from_parent;
+ pfd.events = POLLIN;
+
+ poll(&pfd, 1, -1);
+
+ while(!request_complete) poll_requests();
+
+ free(req);
+}
+
+/* freed by server_cleanup */
+void *dir_map = NULL;
+
+bool client_move(const char *dir)
+{
+ const struct dir_pair {
+ const char *text;
+ enum direction_t val;
+ } dirs[] = {
+ { "N", DIR_N },
+ { "NORTH", DIR_N },
+ { "NE", DIR_NE },
+ { "NORTHEAST", DIR_N },
+ { "E", DIR_E },
+ { "EAST", DIR_E },
+ { "SE", DIR_SE },
+ { "SOUTHEAST", DIR_SE },
+ { "S", DIR_S },
+ { "SOUTH", DIR_S },
+ { "SW", DIR_SW },
+ { "SOUTHWEST", DIR_SW },
+ { "W", DIR_W },
+ { "WEST", DIR_W },
+ { "NW", DIR_NW },
+ { "NORTHWEST", DIR_NW },
+ { "U", DIR_UP },
+ { "UP", DIR_UP },
+ { "D", DIR_DN },
+ { "DOWN", DIR_DN },
+ { "IN", DIR_IN },
+ { "OUT", DIR_OT },
+ };
+
+ if(!dir_map)
+ {
+ dir_map = hash_init(ARRAYLEN(dirs), hash_djb, compare_strings);
+ hash_insert_pairs(dir_map, (struct hash_pair*)dirs, sizeof(struct dir_pair), ARRAYLEN(dirs));
+ }
+
+ struct dir_pair *pair = hash_lookup(dir_map, 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)
+{
+ send_master(REQ_GETROOMNAME, NULL, 0);
+ out("\n");
+ send_master(REQ_GETROOMDESC, NULL, 0);
+}
+
+void client_look_at(char *obj)
+{
+ all_lower(obj);
+ send_master(REQ_LOOKAT, obj, strlen(obj) + 1);
+}
+
+void client_take(char *obj)
+{
+ all_lower(obj);
+ send_master(REQ_TAKE, obj, strlen(obj) + 1);
+}
+
+void client_inventory(void)
+{
+ send_master(REQ_PRINTINVENTORY, NULL, 0);
+}
+
+void client_drop(char *what)
+{
+ send_master(REQ_DROP, what, strlen(what) + 1);
+}
+
+void client_user_list(void)
+{
+ send_master(REQ_LISTUSERS, NULL, 0);
+}
diff --git a/src/client_reqs.h b/src/client_reqs.h
new file mode 100644
index 0000000..979da9a
--- /dev/null
+++ b/src/client_reqs.h
@@ -0,0 +1,46 @@
+/*
+ * 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 "server.h"
+#include "server_reqs.h"
+#include "userdb.h"
+
+enum reqdata_typespec { TYPE_NONE = 0, TYPE_USERDATA, TYPE_BOOLEAN } reqdata_type;
+
+union reqdata_t {
+ struct userdata_t userdata;
+ bool boolean;
+};
+
+extern enum reqdata_typespec reqdata_type;
+extern union reqdata_t returned_reqdata;
+
+void client_change_room(room_id id);
+void client_change_user(const char *user);
+void client_change_state(int state);
+bool client_move(const char *dir);
+void client_look(void);
+void client_look_at(char *obj);
+void client_inventory(void);
+void client_drop(char *what);
+void client_user_list(void);
+void client_take(char *obj);
diff --git a/src/server.c b/src/server.c
index 43afd69..5f2478a 100644
--- a/src/server.c
+++ b/src/server.c
@@ -106,7 +106,7 @@ static void handle_client(int fd, struct sockaddr_in *addr,
client_main(fd, addr, nclients, to, from);
}
-static void __attribute__((noreturn)) serv_cleanup(void)
+static void __attribute__((noreturn)) server_cleanup(void)
{
if(!are_child)
debugf("Shutdown server.\n");
@@ -427,7 +427,7 @@ int server_main(int argc, char *argv[])
ev_io_start(EV_A_ &server_watcher);
- atexit(serv_cleanup);
+ atexit(server_cleanup);
/* everything's ready, hand it over to libev */
ev_loop(loop, 0);