aboutsummaryrefslogtreecommitdiff
path: root/src/server.c
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2016-01-08 22:27:43 -0500
committerFranklin Wei <git@fwei.tk>2016-01-08 22:27:43 -0500
commit50134c46dc337c35b8ecf78b3c5b4308cf8fb791 (patch)
tree89d73bca1951129ec7e15b642e2fa6c85567f872 /src/server.c
parent2819d11ceeb1ac739ed5f17ccb0abab63f494299 (diff)
downloadnetcosm-50134c46dc337c35b8ecf78b3c5b4308cf8fb791.zip
netcosm-50134c46dc337c35b8ecf78b3c5b4308cf8fb791.tar.gz
netcosm-50134c46dc337c35b8ecf78b3c5b4308cf8fb791.tar.bz2
netcosm-50134c46dc337c35b8ecf78b3c5b4308cf8fb791.tar.xz
some stuff
Diffstat (limited to 'src/server.c')
-rw-r--r--src/server.c401
1 files changed, 15 insertions, 386 deletions
diff --git a/src/server.c b/src/server.c
index e24c9f7..02e71b2 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1,6 +1,6 @@
/*
* NetCosm - a MUD server
- * Copyright (C) 2015 Franklin Wei
+ * 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
@@ -79,19 +79,23 @@ static void handle_client(int fd, struct sockaddr_in *addr,
int server_socket;
-static void *request_map = NULL;
-
static void serv_cleanup(void)
{
sig_debugf("Shutdown server.\n");
+
if(shutdown(server_socket, SHUT_RDWR) > 0)
error("shutdown");
close(server_socket);
+
world_free();
- hash_free(request_map);
- request_map = NULL;
+
+ reqmap_free();
+
hash_free(child_map);
child_map = NULL;
+
+ userdb_shutdown();
+
_exit(0);
}
@@ -101,383 +105,6 @@ static void sigint_handler(int s)
serv_cleanup();
}
-static volatile sig_atomic_t num_acks_wanted, num_acks_recvd, inc_acks = 0;
-
-static void req_pass_msg(unsigned char *data, size_t datalen,
- struct child_data *sender, struct child_data *child)
-{
- (void) sender;
-
- if(sender->pid != child->pid)
- {
- unsigned char cmd = REQ_BCASTMSG;
- write(child->outpipe[1], &cmd, 1);
- }
-
- write(child->outpipe[1], data, datalen);
- union sigval nothing;
-
- if(sender->pid != child->pid)
- {
- sigqueue(child->pid, SIGRTMIN, nothing);
- ++num_acks_wanted;
- }
-}
-
-static void req_send_clientinfo(unsigned char *data, size_t datalen,
- struct child_data *sender, struct child_data *child)
-{
- (void) data;
- (void) datalen;
- char buf[128];
- const char *state[] = {
- "INIT",
- "LOGIN SCREEN",
- "CHECKING CREDENTIALS",
- "LOGGED IN AS USER",
- "LOGGED IN AS ADMIN",
- "ACCESS DENIED",
- };
-
- if(child->user)
- snprintf(buf, sizeof(buf), "Client %s PID %d [%s] USER %s",
- inet_ntoa(child->addr), child->pid, state[child->state], child->user);
- else
- snprintf(buf, sizeof(buf), "Client %s PID %d [%s]",
- inet_ntoa(child->addr), child->pid, state[child->state]);
-
- if(sender->pid == child->pid)
- strncat(buf, " [YOU]\n", sizeof(buf));
- else
- strncat(buf, "\n", sizeof(buf));
-
- write(sender->outpipe[1], buf, strlen(buf));
-}
-
-static void req_change_state(unsigned char *data, size_t datalen,
- struct child_data *sender, struct child_data *child)
-{
- (void) data; (void) datalen; (void) child; (void) sender;
- if(datalen == sizeof(sender->state))
- {
- sender->state = *((int*)data);
- debugf("State changed to %d\n", sender->state);
- }
- else
- {
- debugf("State data is of the wrong size\n");
- for(size_t i = 0; i < datalen; ++i)
- debugf("%02x\n", data[i]);
- }
-}
-
-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) sender;
- if(sender->user)
- free(sender->user);
- sender->user = strdup((char*)data);
-}
-
-//void req_hang(unsigned char *data, size_t datalen,
-// struct child_data *sender, struct child_data *child)
-//{
-// while(1);
-//}
-
-static void req_kick_client(unsigned char *data, size_t datalen,
- struct child_data *sender, struct child_data *child)
-{
- (void) data; (void) datalen; (void) child; (void) sender;
- if(datalen >= sizeof(pid_t))
- {
- pid_t kicked_pid = *((pid_t*)data);
- if(kicked_pid == child->pid)
- {
- unsigned char cmd = REQ_KICK;
- write(child->outpipe[1], &cmd, 1);
- write(child->outpipe[1], data + sizeof(pid_t), datalen - sizeof(pid_t));
- union sigval nothing;
- sigqueue(child->pid, SIGRTMIN, nothing);
- }
- }
-}
-
-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 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);
-
- char newline = '\n';
- write(sender->outpipe[1], &newline, 1);
-}
-
-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);
-
- char newline = '\n';
- write(sender->outpipe[1], &newline, 1);
-}
-
-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);
-
- child_set_room(sender, id);
-}
-
-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_debugf("Moving in direction %d\n", dir);
- room_id new = current->adjacent[dir];
- int status;
- if(new != ROOM_NONE)
- {
- child_set_room(sender, new);
- status = 1;
- }
- else
- {
- status = 0;
- }
- write(sender->outpipe[1], &status, sizeof(status));
-}
-
-static const struct child_request {
- unsigned char code;
-
- bool havedata;
-
- enum { CHILD_NONE, CHILD_SENDER, CHILD_ALL_BUT_SENDER, CHILD_ALL } which;
-
- /* sender_pipe is the pipe to the sender of the request */
- /* data points to bogus if havedata = false */
- void (*handle_child)(unsigned char *data, size_t len,
- struct child_data *sender, struct child_data *child);
-
- void (*finalize)(unsigned char *data, size_t len, struct child_data *sender);
-
- /* byte to write back to the sender */
- unsigned char cmd_to_send;
-} requests[] = {
- { REQ_NOP, false, CHILD_NONE, NULL, NULL, REQ_NOP },
- { REQ_BCASTMSG, true, CHILD_ALL, req_pass_msg, NULL, REQ_BCASTMSG },
- { REQ_LISTCLIENTS, false, CHILD_ALL, req_send_clientinfo, NULL, REQ_BCASTMSG },
- { REQ_CHANGESTATE, true, CHILD_SENDER, req_change_state, NULL, REQ_NOP },
- { REQ_CHANGEUSER, true, CHILD_SENDER, req_change_user, NULL, REQ_NOP },
- { REQ_KICK, true, CHILD_ALL, req_kick_client, NULL, REQ_NOP },
- { REQ_WAIT, false, CHILD_NONE, NULL, req_wait, REQ_NOP },
- { REQ_GETROOMDESC, false, CHILD_NONE, NULL, req_send_desc, REQ_BCASTMSG },
- { 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 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);
-}
-
-/**
- * Here's how child-parent requests work
- * 1. Child writes its PID and length of request to the parent's pipe, followed
- * by up to MSG_MAX bytes of data. If the length exceeds MSG_MAX bytes, the
- * request will be ignored.
- * 1.1 Child spins until parent response.
- * 2. Parent handles the request.
- * 3. Parent writes its PID and length of message back to the child(ren).
- * 4. Parent signals child(ren) with SIGRTMIN
- * 5. Child(ren) handle parent's message.
- * 6. Child(ren) send the parent SIGRTMIN+1 to acknowledge receipt of message.
- * 7. Parent spins until the needed number of signals is reached.
- */
-
-static bool handle_child_req(int in_fd)
-{
- pid_t sender_pid;
-
- if(read(in_fd, &sender_pid, sizeof(sender_pid)) != sizeof(sender_pid))
- {
- sig_debugf("Couldn't get sender PID\n");
- return false;
- }
-
- sig_debugf("Got request from PID %d\n", sender_pid);
-
- size_t msglen;
- const struct child_request *req = NULL;
- size_t datalen;
-
- unsigned char cmd, msg[MSG_MAX + 1];
-
- struct child_data *sender = hash_lookup(child_map, &sender_pid);
-
- if(!sender)
- {
- sig_debugf("WARNING: got data from unknown PID, ignoring.\n");
- goto fail;
- }
-
- if(read(in_fd, &msglen, sizeof(msglen)) != sizeof(msglen))
- {
- sig_debugf("Couldn't read message length, dropping.\n");
- goto fail;
- }
-
- if(msglen < 1)
- {
- sig_debugf("message too short to be valid, ignoring.\n");
- goto fail;
- }
- else if(msglen > MSG_MAX)
- {
- sig_debugf("message too long, ignoring.\n");
- goto fail;
- }
-
- unsigned char *msgptr = msg;
- size_t have = 0;
- while(have < msglen)
- {
- ssize_t ret = read(sender->readpipe[0], msgptr, msglen - have);
- if(ret < 0)
- {
- sig_debugf("unexpected EOF\n");
- goto fail;
- }
- msgptr += ret;
- have += ret;
- }
-
- cmd = msg[0];
- msg[MSG_MAX] = '\0';
-
- unsigned char *data = msg + 1;
-
- datalen = msglen - 1;
- req = hash_lookup(request_map, &cmd);
-
- sigset_t old, block;
-
- sigemptyset(&block);
- sigaddset(&block, SIGRTMIN+1);
- sigprocmask(SIG_BLOCK, &block, &old);
-
- num_acks_wanted = 1;
- num_acks_recvd = 0;
- inc_acks = 1;
-
- if(!req)
- {
- sig_debugf("Unknown request.\n");
- goto fail;
- }
-
- write(sender->outpipe[1], &req->cmd_to_send, 1);
-
- switch(req->which)
- {
- case CHILD_SENDER:
- case CHILD_ALL:
- req->handle_child(data, datalen, sender, sender);
- if(req->which == CHILD_SENDER)
- goto finish;
- break;
- case CHILD_NONE:
- goto finish;
- default:
- break;
- }
-
- struct child_data *child = NULL;
- void *ptr = child_map, *save;
-
- do {
- pid_t *key;
- child = hash_iterate(ptr, &save, (void**)&key);
- ptr = NULL;
- if(!child)
- break;
- if(child->pid == sender->pid)
- continue;
-
- switch(req->which)
- {
- case CHILD_ALL:
- case CHILD_ALL_BUT_SENDER:
- req->handle_child(data, datalen, sender, child);
- break;
- default:
- break;
- }
- } while(1);
-
-finish:
-
- if(req && req->finalize)
- req->finalize(data, datalen, sender);
-
- union sigval junk;
- if(sender)
- sigqueue(sender->pid, SIGRTMIN, junk);
- else
- sig_debugf("Unknown PID sent request.\n");
-
- while(num_acks_recvd < MIN(num_clients,num_acks_wanted))
- {
- sigsuspend(&old);
- }
-
- inc_acks = 0;
-
- sigprocmask(SIG_SETMASK, &old, NULL);
-
- return true;
-fail:
- return true;
-}
-
-static void master_ack_handler(int s, siginfo_t *info, void *v)
-{
- (void) s;
- (void) v;
- if(inc_acks && hash_lookup(child_map, &info->si_pid))
- {
- ++num_acks_recvd;
- }
-}
-
void init_signals(void)
{
struct sigaction sa;
@@ -526,7 +153,7 @@ void init_signals(void)
static void check_userfile(void)
{
- if(access(USERFILE, F_OK) < 0)
+ if(access(USERFILE, F_OK) < 0 || userdb_size() == 0)
first_run_setup();
if(access(USERFILE, R_OK | W_OK) < 0)
@@ -535,7 +162,7 @@ static void check_userfile(void)
static void load_worldfile(void)
{
- if(access(WORLDFILE, F_OK) < 0 || userdb_size() == 0)
+ if(access(WORLDFILE, F_OK) < 0)
{
world_init(netcosm_world, netcosm_world_sz, netcosm_world_name);
@@ -662,11 +289,13 @@ int main(int argc, char *argv[])
/* only the master process controls the world */
world_free();
- hash_free(request_map);
- request_map = NULL;
+ reqmap_free();
hash_free(child_map);
child_map = NULL;
+ /* user DB requests go through the master */
+ userdb_shutdown();
+
debugf("Child with PID %d spawned\n", getpid());
server_socket = new_sock;