diff options
| author | Franklin Wei <git@fwei.tk> | 2016-01-08 22:27:43 -0500 |
|---|---|---|
| committer | Franklin Wei <git@fwei.tk> | 2016-01-08 22:27:43 -0500 |
| commit | 50134c46dc337c35b8ecf78b3c5b4308cf8fb791 (patch) | |
| tree | 89d73bca1951129ec7e15b642e2fa6c85567f872 /src/server.c | |
| parent | 2819d11ceeb1ac739ed5f17ccb0abab63f494299 (diff) | |
| download | netcosm-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.c | 401 |
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; |