aboutsummaryrefslogtreecommitdiff
path: root/src/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/server.c')
-rw-r--r--src/server.c178
1 files changed, 82 insertions, 96 deletions
diff --git a/src/server.c b/src/server.c
index 3476f38..2ea5d1d 100644
--- a/src/server.c
+++ b/src/server.c
@@ -35,7 +35,7 @@ void __attribute__((noreturn)) error(const char *fmt, ...)
/* assume int is atomic */
volatile int num_clients = 0;
-struct child_data *child_data;
+void *child_map = NULL;
static void sigchld_handler(int s, siginfo_t *info, void *vp)
{
@@ -50,20 +50,9 @@ static void sigchld_handler(int s, siginfo_t *info, void *vp)
pid_t pid;
while((pid = waitpid(-1, NULL, WNOHANG)) > 0)
{
- struct child_data *iter = child_data, *last = NULL;
- while(iter)
- {
- if(iter->pid == pid)
- {
- if(!last)
- child_data = iter->next;
- else
- last->next = iter->next;
- free(iter);
- break;
- }
- iter = iter->next;
- }
+ void *key = hash_getkeyptr(child_map, &pid);
+ hash_remove(child_map, &pid);
+ free(key);
}
errno = saved_errno;
@@ -107,7 +96,9 @@ static void req_pass_msg(unsigned char *data, size_t datalen,
}
write(child->outpipe[1], data, datalen);
- kill(child->pid, SIGUSR2);
+
+ if(sender->pid != child->pid)
+ kill(child->pid, SIGUSR2);
}
static void req_send_clientinfo(unsigned char *data, size_t datalen,
@@ -127,12 +118,17 @@ static void req_send_clientinfo(unsigned char *data, size_t datalen,
};
if(child->user)
- len = snprintf(buf, sizeof(buf), "Client %s PID %d [%s] USER %s\n",
+ len = snprintf(buf, sizeof(buf), "Client %s PID %d [%s] USER %s",
inet_ntoa(child->addr), child->pid, state[child->state], child->user);
else
- len = snprintf(buf, sizeof(buf), "Client %s PID %d [%s]\n",
+ len = 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, len);
}
@@ -317,80 +313,67 @@ static void sigusr1_handler(int s, siginfo_t *info, void *vp)
unsigned char cmd, data[MSG_MAX + 1];
const struct child_request *req = NULL;
size_t datalen = 0;
- struct child_data *sender = NULL;
+ struct child_data *sender = hash_lookup(child_map, &sender_pid);
- /* we have to iterate over the linked list twice */
- /* first to get the data, second to send it to the rest of the children */
+ if(!sender)
+ {
+ printf("WARNING: got SIGUSR1 from unknown PID, ignoring.\n");
+ return;
+ }
- struct child_data *iter = child_data;
+ read(sender->readpipe[0], &cmd, 1);
+ req = hash_lookup(request_map, &cmd);
+ if(!req)
+ {
+ sig_printf("Unknown request.\n");
+ return;
+ }
- while(iter)
+ sig_printf("Got command %d\n", cmd);
+ if(req->havedata)
{
- if(!req)
- {
- if(iter->pid == sender_pid)
- {
- sender = iter;
- read(iter->readpipe[0], &cmd, 1);
- req = hash_lookup(request_map, &cmd);
- if(!req)
- {
- sig_printf("Unknown request.\n");
- return;
- }
-
- sig_printf("Got command %d\n", cmd);
- if(req->havedata)
- {
- datalen = read(iter->readpipe[0], data, sizeof(data));
- }
-
- write(sender->outpipe[1], &req->cmd_to_send, 1);
-
- switch(req->which)
- {
- case CHILD_SENDER:
- case CHILD_ALL:
- req->handle_child(data, datalen, sender, iter);
- if(req->which == CHILD_SENDER)
- goto finish;
- break;
- case CHILD_NONE:
- goto finish;
- default:
- break;
- }
- }
- }
- else
- {
- switch(req->which)
- {
- case CHILD_ALL:
- case CHILD_ALL_BUT_SENDER:
- req->handle_child(data, datalen, sender, iter);
- break;
- default:
- break;
- }
- }
- iter = iter->next;
+ datalen = read(sender->readpipe[0], data, sizeof(data));
}
- /* iterate over the rest of the children, if needed */
- if(req && req->which != CHILD_SENDER)
+ write(sender->outpipe[1], &req->cmd_to_send, 1);
+
+ switch(req->which)
{
- iter = child_data;
- while(iter)
- {
- if(iter->pid == sender_pid)
- break;
+ 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;
+ }
- req->handle_child(data, datalen, sender, iter);
+ struct child_data *child = NULL;
+ void *ptr = child_map, *save;
- iter = iter->next;
+ do {
+ pid_t *key;
+ child = hash_iterate(ptr, &save, (void**)&key);
+ ptr = NULL;
+ if(!child)
+ break;
+ sig_printf("Iterating over PID %d\n", *key);
+ 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:
@@ -402,9 +385,6 @@ finish:
else
sig_printf("WARN: unknown child sent request.\n");
- if(!req)
- sig_printf("WARN: unknown request, request ignored\n");
-
sig_printf("finished handling client request\n");
}
@@ -487,6 +467,9 @@ static int server_bind(void)
return sock;
}
+static SIMP_HASH(pid_t, pid_hash);
+static SIMP_EQUAL(pid_t, pid_equal);
+
int main(int argc, char *argv[])
{
if(argc != 2)
@@ -508,7 +491,8 @@ int main(int argc, char *argv[])
reqmap_init();
- child_data = NULL;
+ /* this is set very low to make iteration faster */
+ child_map = hash_init(8, pid_hash, pid_equal);
printf("Listening on port %d\n", port);
@@ -558,16 +542,18 @@ int main(int argc, char *argv[])
close(outpipe[0]);
close(new_sock);
- /* add the child to the child list */
- struct child_data *old = child_data;
- child_data = malloc(sizeof(struct child_data));
- memcpy(child_data->outpipe, outpipe, sizeof(outpipe));
- memcpy(child_data->readpipe, readpipe, sizeof(readpipe));
- child_data->addr = client.sin_addr;
- child_data->next = old;
- child_data->pid = pid;
- child_data->state = STATE_INIT;
- child_data->user = NULL;
+ /* add the child to the child map */
+ struct child_data *new = calloc(1, sizeof(struct child_data));
+ memcpy(new->outpipe, outpipe, sizeof(outpipe));
+ memcpy(new->readpipe, readpipe, sizeof(readpipe));
+ new->addr = client.sin_addr;
+ new->pid = pid;
+ new->state = STATE_INIT;
+ new->user = NULL;
+
+ pid_t *pidbuf = malloc(sizeof(pid_t));
+ *pidbuf = pid;
+ hash_insert(child_map, pidbuf, new);
}
}
}