From 0ab94d648289babfbeade80b0ce2d566e2518ed8 Mon Sep 17 00:00:00 2001 From: laurent Date: Tue, 27 Mar 2012 01:21:50 +0200 Subject: initial import from my hg repository --- glougloud/server.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 glougloud/server.c (limited to 'glougloud/server.c') diff --git a/glougloud/server.c b/glougloud/server.c new file mode 100644 index 0000000..196c3a2 --- /dev/null +++ b/glougloud/server.c @@ -0,0 +1,230 @@ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "glougloud.h" +#include "imsgev.h" + +#define USER_TIMEOUT 300 +#define USERTIMER 10 + +struct server { + struct imsgev iev; + struct event ev; + + struct event usrtimer_ev; + struct timeval usrtimer_tv; + time_t time; +}; +enum user_status { + USER_REQUESTED, + USER_ACCEPTED, + USER_REFUSED +}; +struct user { + LIST_ENTRY(user) entry; + struct sockaddr_in addr; + enum user_status status; + time_t lastseen; +}; + +static void imsgev_main(struct imsgev *, int, struct imsg *); +static void receive(int, short, void *); +static void ev_usrtimer(int, short, void *); + +struct server *srv; +LIST_HEAD(, user) usr_list; + +static void +sig_handler(int sig, short why, void *data) +{ + log_info("server: got signal %d", sig); + if (sig == SIGINT || sig == SIGTERM) + event_loopexit(NULL); +} + +int +server_init(int fd[2]) +{ + struct event ev_sigint, ev_sigterm, ev_sigchld, ev_sighup; + int pid; + + pid = fork(); + if (pid < 0) + fatal("server fork"); + if (pid > 0) + return pid; + + setproctitle("server"); + event_init(); + close(fd[0]); + + signal_set(&ev_sigint, SIGINT, sig_handler, NULL); + signal_set(&ev_sigterm, SIGTERM, sig_handler, NULL); + signal_set(&ev_sigchld, SIGCHLD, sig_handler, NULL); + signal_set(&ev_sighup, SIGHUP, sig_handler, NULL); + signal_add(&ev_sigint, NULL); + signal_add(&ev_sigterm, NULL); + signal_add(&ev_sigchld, NULL); + signal_add(&ev_sighup, NULL); + signal(SIGPIPE, SIG_IGN); + + srv = xmalloc(sizeof(struct server)); + imsgev_init(&srv->iev, fd[1], NULL, &imsgev_main); + srv->time = time(NULL); + + event_set(&srv->ev, net_socket, EV_READ|EV_PERSIST, receive, NULL); + event_add(&srv->ev, NULL); + + srv->usrtimer_tv.tv_sec = USERTIMER; + srv->usrtimer_tv.tv_usec = 0; + evtimer_set(&srv->usrtimer_ev, ev_usrtimer, NULL); + if (event_add(&srv->usrtimer_ev, &srv->usrtimer_tv) == -1) + fatal("server: event_add usrtimr failed: %s", strerror(errno)); + + droppriv(); + + log_info("server: entering event loop"); + event_dispatch(); + + log_info("server: exiting"); + exit(0); +} + +static struct user * +finduser(struct sockaddr_in *remote) { + struct user *usr; + struct sockaddr_in *u; + + LIST_FOREACH(usr, &usr_list, entry) { + u = &usr->addr; + if (u->sin_addr.s_addr == remote->sin_addr.s_addr && + u->sin_port == remote->sin_port) + return usr; + } + return NULL; +} + +static void +srvconn(struct imsgev *iev, struct imsg *imsg) +{ + struct imsg_srvconn *res; + struct user *usr; + + res = imsg->data; + usr = finduser(&res->addr); + if (!usr || usr->status != USER_REQUESTED) + fatal("server: received srvconn response for inexistant connection"); + if (res->ok) { + usr->status = USER_ACCEPTED; + } else { + usr->status = USER_REFUSED; + } +} + +static void +imsgev_main(struct imsgev *iev, int code, struct imsg *imsg) +{ + switch (code) { + case IMSGEV_IMSG: + log_debug("server: %s got imsg %i on fd %i", + __func__, imsg->hdr.type, iev->ibuf.fd); + switch (imsg->hdr.type) { + case IMSG_SRVCONN_RES: + srvconn(iev, imsg); + break; + default: + fatal("%s, unexpected imsg %d", + __func__, imsg->hdr.type); + } + break; + case IMSGEV_EREAD: + case IMSGEV_EWRITE: + case IMSGEV_EIMSG: + fatal("imsgev read/write error"); + /* NOTREACHED */ + break; + case IMSGEV_DONE: + event_loopexit(NULL); + /* NOTREACHED */ + break; + } +} + +static void +receive(int fd, short why, void *data) +{ + struct sockaddr_in remote; + struct imsg_srvconn req; + socklen_t len; + char buf[16384]; + struct user *usr; + int rv; + + len = sizeof(remote); + rv = recvfrom(fd, buf, sizeof(buf), 0, + (struct sockaddr *)&remote, &len); + if (rv < 0) { + log_warn("server: recvfrom failed"); + return; + } + usr = finduser(&remote); + if (usr) { + switch (usr->status) { + case USER_ACCEPTED: + log_tmp("server: data for existing user"); + break; + case USER_REQUESTED: + log_warn("server: data for not yet accepted user"); + break; + case USER_REFUSED: + log_warn("server: data for banned user !"); + break; + } + } else { + log_debug("server: new user request"); + + usr = xmalloc(sizeof(struct user)); + addrcpy(&usr->addr, &remote); + usr->status = USER_REQUESTED; + usr->lastseen = srv->time; + LIST_INSERT_HEAD(&usr_list, usr, entry); + + addrcpy(&req.addr, &remote); + req.deco = 0; + imsgev_compose(&srv->iev, IMSG_SRVCONN_REQ, 0, 0, -1, + &req, sizeof(req)); + } +} + +static void +ev_usrtimer(int fd, short why, void *data) +{ + struct user *usr; + struct imsg_srvconn req; + + srv->time = time(NULL); + + LIST_FOREACH(usr, &usr_list, entry) { + if (srv->time > usr->lastseen + USER_TIMEOUT) { + addrcpy(&req.addr, &usr->addr); + req.deco = 1; + imsgev_compose(&srv->iev, IMSG_SRVCONN_REQ, 0, 0, -1, + &req, sizeof(req)); + + LIST_REMOVE(usr, entry); + free(usr); + } + } + + if (event_add(&srv->usrtimer_ev, &srv->usrtimer_tv) == -1) + fatal("server: event_add usrtimer failed : %s", strerror(errno)); +} -- cgit v1.2.3-59-g8ed1b