From f1e708a631d7d5fbe6fc2f74e5f681d6a6786b4e Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Thu, 10 Dec 2015 21:06:38 -0500 Subject: kicking --- src/client.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- src/netcosm.h | 7 +++-- src/server.c | 59 +++++++++++++++++++++++++++++++++-------- 3 files changed, 128 insertions(+), 23 deletions(-) diff --git a/src/client.c b/src/client.c index 4835881..d64846c 100644 --- a/src/client.c +++ b/src/client.c @@ -1,10 +1,24 @@ #include "netcosm.h" -int client_fd, to_parent, from_parent; +static int client_fd, to_parent, from_parent; + +static volatile sig_atomic_t output_locked = 0, done_printing; void out_raw(const unsigned char *buf, size_t len) { - write(client_fd, buf, len); +try_again: + while(output_locked); + + /* something weird happened and the value changed between the loop and here */ + if(!output_locked) + { + output_locked = 1; + write(client_fd, buf, len); + output_locked = 0; + done_printing = 1; + } + else + goto try_again; } void __attribute__((format(printf,1,2))) out(const char *fmt, ...) @@ -18,6 +32,11 @@ void __attribute__((format(printf,1,2))) out(const char *fmt, ...) out_raw((unsigned char*)buf, len); } +void send_master(unsigned char cmd) +{ + write(to_parent, &cmd, 1); + kill(getppid(), SIGUSR1); +} #define BUFSZ 128 @@ -58,16 +77,35 @@ void all_upper(char *s) } } -volatile sig_atomic_t done_printing; - void sigusr2_handler(int s) { (void) s; + printf("got SIGUSR2\n"); + unsigned char cmd; + read(from_parent, &cmd, 1); unsigned char buf[MSG_MAX + 1]; - size_t len = read(from_parent, buf, MSG_MAX); - buf[MSG_MAX] = '\0'; - out_raw(buf, len); - done_printing = 1; + switch(cmd) + { + case REQ_BCASTMSG: + { + printf("reading...\n"); + size_t len = read(from_parent, buf, MSG_MAX); + printf("done reading\n"); + buf[MSG_MAX] = '\0'; + out_raw(buf, len); + break; + } + case REQ_KICK: + { + size_t len = read(from_parent, buf, MSG_MAX); + buf[MSG_MAX] = '\0'; + out_raw(buf, len); + exit(EXIT_SUCCESS); + } + default: + fprintf(stderr, "WARNING: client process received unknown request\n"); + break; + } } void client_change_state(int state) @@ -94,6 +132,8 @@ void client_main(int fd, struct sockaddr_in *addr, int total, int to, int from) to_parent = to; from_parent = from; + output_locked = 0; + signal(SIGUSR2, sigusr2_handler); telnet_init(); @@ -197,7 +237,7 @@ void client_main(int fd, struct sockaddr_in *addr, int total, int to, int from) out("Usage: USER DEL \n"); } } - else if(!strcmp(what, "ADD") || !strcmp(what, "PASS")) + else if(!strcmp(what, "ADD") || !strcmp(what, "MODIFY")) { char *user = strtok_r(NULL, WSPACE, &save); if(user) @@ -231,7 +271,7 @@ void client_main(int fd, struct sockaddr_in *addr, int total, int to, int from) free(pass); } else - out("Usage: USER ADD|CHANGE \n"); + out("Usage: USER \n"); } else if(!strcmp(what, "LIST")) { @@ -242,6 +282,10 @@ void client_main(int fd, struct sockaddr_in *addr, int total, int to, int from) { char *what = strtok_r(NULL, WSPACE, &save); all_upper(what); + if(!what) + { + out("Usage: CLIENT \n"); + } if(!strcmp(what, "LIST")) { done_printing = 0; @@ -251,7 +295,28 @@ void client_main(int fd, struct sockaddr_in *addr, int total, int to, int from) waitpid(-1, NULL, 0); while(!done_printing); } + else if(!strcmp(what, "KICK")) + { + char *pid_s = strtok_r(NULL, WSPACE, &save); + if(pid_s) + { + unsigned char cmd_code = REQ_KICK; + write(to_parent, &cmd_code, sizeof(cmd_code)); + pid_t pid = strtol(pid_s, NULL, 0); + write(to_parent, &pid, sizeof(pid)); + char buf[128]; + int len = snprintf(buf, sizeof(buf), "You were kicked.\n"); + write(to_parent, buf, len); + kill(getppid(), SIGUSR1); + } + else + out("Usage: CLIENT KICK \n"); + } } + //else if(!strcmp(tok, "HANG")) + //{ + // send_master(REQ_HANG); + //} } if(!strcmp(tok, "QUIT") || !strcmp(tok, "EXIT")) diff --git a/src/netcosm.h b/src/netcosm.h index f9f0fc4..16ace01 100644 --- a/src/netcosm.h +++ b/src/netcosm.h @@ -56,12 +56,15 @@ void telnet_echo_off(void); void remove_cruft(char*); -/* child->master commands */ -#define REQ_INVALID 0 +/* child<->master commands */ +/* children might not implement all of these */ +#define REQ_NOP 0 #define REQ_BCASTMSG 1 #define REQ_LISTCLIENTS 2 #define REQ_CHANGESTATE 3 #define REQ_CHANGEUSER 4 +#define REQ_HANG 5 +#define REQ_KICK 6 #define STATE_INIT 0 #define STATE_AUTH 1 diff --git a/src/server.c b/src/server.c index c680b37..46d0ac4 100644 --- a/src/server.c +++ b/src/server.c @@ -141,6 +141,7 @@ void req_send_clientinfo(unsigned char *data, size_t datalen, "LOGGED IN AS ADMIN", "ACCESS DENIED", }; + if(child->user) len = snprintf(buf, sizeof(buf), "Client %s PID %d [%s] USER %s\n", inet_ntoa(child->addr), child->pid, state[child->state], child->user); @@ -168,34 +169,61 @@ void req_change_state(unsigned char *data, size_t datalen, } void req_change_user(unsigned char *data, size_t datalen, - struct child_data *sender, struct child_data *child) + struct child_data *sender, struct child_data *child) { 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); +//} + +void req_kick_client(unsigned char *data, size_t datalen, + struct child_data *sender, struct child_data *child) +{ + 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)); + kill(child->pid, SIGUSR2); + } + } +} + static const struct child_request { unsigned char code; bool havedata; - enum { CHILD_SENDER, CHILD_ALL_BUT_SENDER, CHILD_ALL } which; + enum { CHILD_NONE, CHILD_SENDER, CHILD_ALL_BUT_SENDER, CHILD_ALL } which; /* sender_pipe is the pipe to the sender of the request */ - /* data is bogus if havedata = false */ + /* 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)(struct child_data *sender); + + /* what byte to write back to the sender if != REQ_NOP */ + unsigned char cmd_to_send; } requests[] = { - { REQ_BCASTMSG, true, CHILD_ALL, req_pass_msg, NULL }, - { REQ_LISTCLIENTS, false, CHILD_ALL, req_send_clientinfo, req_signal_sender }, - { REQ_CHANGESTATE, true, CHILD_SENDER, req_change_state, NULL }, - { REQ_CHANGEUSER, true, CHILD_SENDER, req_change_user, NULL }, + { 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, req_signal_sender, 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_HANG, false, CHILD_SENDER, req_hang, NULL, REQ_NOP }, + { REQ_KICK, true, CHILD_ALL, req_kick_client, NULL, REQ_NOP }, }; - /* SIGUSR1 is used by children to communicate with the master process */ /* the master handles commands that involve multiple children, i.e. message passing, listing clients, etc. */ void sigusr1_handler(int s, siginfo_t *info, void *vp) @@ -203,7 +231,7 @@ void sigusr1_handler(int s, siginfo_t *info, void *vp) (void) s; (void) vp; pid_t sender_pid = info->si_pid; - printf("PID %d requests a broadcast message\n", sender_pid); + printf("PID %d sends a client request\n", sender_pid); unsigned char cmd, data[MSG_MAX + 1]; const struct child_request *req = NULL; @@ -211,7 +239,7 @@ void sigusr1_handler(int s, siginfo_t *info, void *vp) struct child_data *sender = NULL; /* we have to iterate over the linked list twice */ - /* first to get the data, second to send it to all the children */ + /* first to get the data, second to send it to the rest of the children */ struct child_data *iter = child_data; @@ -243,6 +271,9 @@ void sigusr1_handler(int s, siginfo_t *info, void *vp) datalen = read(iter->readpipe[0], data, sizeof(data)); } + if(req->cmd_to_send) + write(sender->outpipe[1], &req->cmd_to_send, 1); + switch(req->which) { case CHILD_SENDER: @@ -251,6 +282,8 @@ void sigusr1_handler(int s, siginfo_t *info, void *vp) if(req->which == CHILD_SENDER) goto finish; break; + case CHILD_NONE: + goto finish; default: break; } @@ -290,14 +323,17 @@ finish: if(req->finalize) req->finalize(sender); + + printf("finished handling client request\n"); } void init_signals(void) { struct sigaction sa; - sa.sa_sigaction = sigchld_handler; // reap all dead processes sigemptyset(&sa.sa_mask); + + sa.sa_sigaction = sigchld_handler; // reap all dead processes sa.sa_flags = SA_RESTART | SA_SIGINFO; if (sigaction(SIGCHLD, &sa, NULL) < 0) error("sigaction"); @@ -309,6 +345,7 @@ void init_signals(void) if(sigaction(SIGTERM, &sa, NULL) < 0) error("sigaction"); + sigaddset(&sa.sa_mask, SIGUSR1); sa.sa_sigaction = sigusr1_handler; sa.sa_flags = SA_RESTART | SA_SIGINFO; if(sigaction(SIGUSR1, &sa, NULL) < 0) -- cgit v1.1