aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2015-12-10 21:06:38 -0500
committerFranklin Wei <git@fwei.tk>2015-12-10 21:06:38 -0500
commitf1e708a631d7d5fbe6fc2f74e5f681d6a6786b4e (patch)
tree1613192f78bc85489548786f95ceb1c286394beb /src
parent33e3462fb86a715e6f71e387233e36c7be255038 (diff)
downloadnetcosm-f1e708a631d7d5fbe6fc2f74e5f681d6a6786b4e.zip
netcosm-f1e708a631d7d5fbe6fc2f74e5f681d6a6786b4e.tar.gz
netcosm-f1e708a631d7d5fbe6fc2f74e5f681d6a6786b4e.tar.bz2
netcosm-f1e708a631d7d5fbe6fc2f74e5f681d6a6786b4e.tar.xz
kicking
Diffstat (limited to 'src')
-rw-r--r--src/client.c85
-rw-r--r--src/netcosm.h7
-rw-r--r--src/server.c59
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 <USERNAME>\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 <USERNAME>\n");
+ out("Usage: USER <ADD|MODIFY> <USERNAME>\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 <LIST|KICK> <PID>\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 <PID>\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)