aboutsummaryrefslogtreecommitdiff
path: root/src/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/server.c')
-rw-r--r--src/server.c103
1 files changed, 70 insertions, 33 deletions
diff --git a/src/server.c b/src/server.c
index ad2502d..ff4a4d0 100644
--- a/src/server.c
+++ b/src/server.c
@@ -319,6 +319,24 @@ void sig_printf(const char *fmt, ...)
va_end(ap);
}
+static void force_read(int fd, void *buf, size_t n)
+{
+ unsigned char *ptr = buf;
+ size_t n_read = 0;
+ while(n_read < n)
+ {
+ ssize_t ret = read(fd, ptr, n - n_read);
+ ptr += ret;
+ n_read += ret;
+ }
+}
+
+static void empty_pipe(int fd)
+{
+ char buf[4096];
+ read(fd, buf, sizeof(buf));
+}
+
/**
* Here's how child-parent requests work
* 1. Child writes its PID and length of request to the parent's pipe, followed
@@ -335,43 +353,45 @@ void sig_printf(const char *fmt, ...)
static bool handle_child_req(int in_fd)
{
pid_t sender_pid;
- if(read(in_fd, &sender_pid, sizeof(sender_pid)) != sizeof(pid_t))
- return false;
- sig_printf("PID %d sends a client request\n", sender_pid);
-
- size_t msglen;
- if(read(in_fd, &msglen, sizeof(msglen)) != sizeof(msglen))
- return false;
- if(msglen > MSG_MAX)
+ if(read(in_fd, &sender_pid, sizeof(sender_pid)) != sizeof(sender_pid))
{
- sig_printf("message data too long, dropping\n");
- return false;
- }
- else if(msglen < 1)
- {
- sig_printf("message too short to be valid, ignoring.\n");
- return false;
+ sig_printf("Couldn't get sender PID\n");
+ goto fail;
}
+ sig_printf("PID %d sends a client request\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)
{
- printf("WARNING: got data from unknown PID, ignoring.\n");
- return false;
+ sig_printf("WARNING: got data from unknown PID, ignoring.\n");
+ goto fail;
}
- sigset_t old, block;
-
- sigemptyset(&block);
- sigaddset(&block, SIGRTMIN+1);
- sigprocmask(SIG_BLOCK, &block, &old);
+ if(read(in_fd, &msglen, sizeof(msglen)) != sizeof(msglen))
+ {
+ sig_printf("Couldn't read message length, dropping.\n");
+ goto fail;
+ }
- num_acks_wanted = 1;
- num_acks_recvd = 0;
- inc_acks = 1;
+ if(msglen < 1)
+ {
+ sig_printf("message too short to be valid, ignoring.\n");
+ goto fail;
+ }
+ else if(msglen > MSG_MAX)
+ {
+ sig_printf("message too long, ignoring.\n");
+ goto fail;
+ }
unsigned char *msgptr = msg;
size_t have = 0;
@@ -381,7 +401,7 @@ static bool handle_child_req(int in_fd)
if(ret < 0)
{
sig_printf("unexpected EOF\n");
- return true;
+ goto fail;
}
msgptr += ret;
have += ret;
@@ -392,14 +412,23 @@ static bool handle_child_req(int in_fd)
unsigned char *data = msg + 1;
- size_t datalen = msglen - 1;
+ datalen = msglen - 1;
+ req = hash_lookup(request_map, &cmd);
- const struct child_request *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_printf("Unknown request.\n");
- return true;
+ goto fail;
}
write(sender->outpipe[1], &req->cmd_to_send, 1);
@@ -448,7 +477,10 @@ finish:
req->finalize(data, datalen, sender);
union sigval junk;
- sigqueue(sender->pid, SIGRTMIN, junk);
+ if(sender)
+ sigqueue(sender->pid, SIGRTMIN, junk);
+ else
+ sig_printf("Unknown PID send request.\n");
sig_printf("Waiting for %d acks\n", num_acks_wanted);
@@ -465,6 +497,9 @@ finish:
sig_printf("finished handling client request\n");
return true;
+fail:
+ empty_pipe(in_fd);
+ return true;
}
static void master_ack_handler(int s, siginfo_t *info, void *v)
@@ -484,6 +519,7 @@ void init_signals(void)
struct sigaction sa;
sigemptyset(&sa.sa_mask);
+ sigaddset(&sa.sa_mask, SIGCHLD);
sa.sa_sigaction = sigchld_handler; // reap all dead processes
sa.sa_flags = SA_RESTART | SA_SIGINFO;
if (sigaction(SIGCHLD, &sa, NULL) < 0)
@@ -513,6 +549,7 @@ void init_signals(void)
/* set this now so there's no race condition later */
sigemptyset(&sa.sa_mask);
+ sigaddset(&sa.sa_mask, SIGRTMIN);
void sig_rt_0_handler(int s, siginfo_t *info, void *v);
sa.sa_sigaction = sig_rt_0_handler;
sa.sa_flags = SA_RESTART | SA_SIGINFO;
@@ -598,8 +635,8 @@ int main(int argc, char *argv[])
reqmap_init();
- /* this is set very low to make iteration faster */
- child_map = hash_init(11, pid_hash, pid_equal);
+ /* this initial size very low to make iteration faster */
+ child_map = hash_init(7, pid_hash, pid_equal);
hash_setfreedata_cb(child_map, free_child_data);
hash_setfreekey_cb(child_map, free);
@@ -644,7 +681,7 @@ int main(int argc, char *argv[])
if(pipe(readpipe) < 0)
error("pipe");
- if(pipe(outpipe) < 0)
+ if(pipe2(outpipe, O_NONBLOCK) < 0)
error("pipe");
pid_t pid = fork();