X-Git-Url: http://git.madism.org/?a=blobdiff_plain;f=common%2Fserver.c;h=585f241ba36775004a49b15fa3c3a07b8ab58588;hb=56eeb7d73ed0c82f2a8165b6aba525af73c58f73;hp=a085c4067439efa621c0764bd50e051dc388a4eb;hpb=ae0c2eb5d2ea501fd9e458fc138696c268a14569;p=apps%2Fpfixtools.git diff --git a/common/server.c b/common/server.c index a085c40..585f241 100644 --- a/common/server.c +++ b/common/server.c @@ -33,257 +33,332 @@ * Copyright © 2008 Florent Bruneau */ +#include #include "server.h" -#include "epoll.h" #include "common.h" -static PA(server_t) listeners = ARRAY_INIT; -static PA(server_t) server_pool = ARRAY_INIT; +typedef struct server_io_t { + struct ev_io io; + int fd; +} server_io_t; -static server_t* server_new(void) +struct listener_t { + server_io_t io; +}; + +struct client_t { + server_io_t io; + + buffer_t ibuf; + buffer_t obuf; + + run_client_t run; + delete_client_t clear_data; + void* data; +}; + + +static PA(listener_t) listeners = ARRAY_INIT; +static PA(client_t) client_pool = ARRAY_INIT; + +static struct ev_loop *gl_loop = NULL; +static start_client_t gl_client_start = NULL; +static delete_client_t gl_client_delete = NULL; +static run_client_t gl_client_run = NULL; +static refresh_t gl_config_refresh = NULL; +static void *gl_config = NULL; + + +/* Server io structure methods. + */ + +static inline void server_io_wipe(server_io_t *io) +{ + if (io->fd >= 0) { + ev_io_stop(gl_loop, &io->io); + close(io->fd); + io->fd = -1; + } +} + + +/* Client methods. + */ + +/* 1 - managing clients */ + +static client_t* client_new(void) { - server_t* server = p_new(server_t, 1); - server->fd = -1; - server->fd2 = -1; + client_t* server = p_new(client_t, 1); + server->io.fd = -1; return server; } -static void server_wipe(server_t *server) +static void client_wipe(client_t *server) { - server->listener = server->event = false; - if (server->fd > 0) { - epoll_modify(server->fd, 0, NULL); - close(server->fd); - server->fd = -1; - } - if (server->fd2 > 0) { - close(server->fd2); - server->fd2 = -1; - } + server_io_wipe(&server->io); if (server->data && server->clear_data) { server->clear_data(&server->data); } + server->obuf.len = 0; + server->ibuf.len = 0; + server->data = NULL; + server->clear_data = NULL; + server->run = NULL; } -static void server_delete(server_t **server) +void client_delete(client_t **server) { if (*server) { buffer_wipe(&(*server)->ibuf); buffer_wipe(&(*server)->obuf); - server_wipe(*server); + client_wipe(*server); p_delete(server); } } -static server_t* server_acquire(void) +static client_t* client_acquire(void) { - if (server_pool.len != 0) { - return array_elt(server_pool, --server_pool.len); + if (client_pool.len != 0) { + return array_pop_last(client_pool); } else { - return server_new(); + return client_new(); } } -void server_release(server_t *server) +void client_release(client_t *server) { - server_wipe(server); - array_add(server_pool, server); + client_wipe(server); + array_add(client_pool, server); } -static void server_shutdown(void) +/* 2 - Doing I/O */ + +void client_io_none(client_t *server) { - printf("Server shutdown"); - array_deep_wipe(listeners, server_delete); - array_deep_wipe(server_pool, server_delete); + ev_io_stop(gl_loop, &server->io.io); } -module_exit(server_shutdown); +void client_io_rw(client_t *server) +{ + ev_io_stop(gl_loop, &server->io.io); + ev_io_set(&server->io.io, server->io.fd, EV_READ | EV_WRITE); + ev_io_start(gl_loop, &server->io.io); +} -int start_server(int port, start_listener_t starter, delete_client_t deleter) +void client_io_ro(client_t *server) { - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_addr = { htonl(INADDR_LOOPBACK) }, - }; - server_t *tmp; - void* data = NULL; - int sock; + ev_io_stop(gl_loop, &server->io.io); + ev_io_set(&server->io.io, server->io.fd, EV_READ); + ev_io_start(gl_loop, &server->io.io); +} - addr.sin_port = htons(port); - sock = tcp_listen_nonblock((const struct sockaddr *)&addr, sizeof(addr)); - if (sock < 0) { - return -1; +ssize_t client_read(client_t *client) +{ + return buffer_read(&client->ibuf, client->io.fd, -1); +} + +buffer_t *client_input_buffer(client_t *client) +{ + return &client->ibuf; +} + +buffer_t *client_output_buffer(client_t *client) +{ + return &client->obuf; +} + +void *client_data(client_t *client) +{ + return client->data; +} + + +static void client_cb(EV_P_ struct ev_io *w, int events) +{ + client_t *server = (client_t*)w; + + if (events & EV_WRITE && server->obuf.len) { + if (buffer_write(&server->obuf, server->io.fd) < 0) { + client_release(server); + return; + } + if (!server->obuf.len) { + client_io_ro(server); + } + } + + if (events & EV_READ) { + if (server->run(server, gl_config) < 0) { + client_release(server); + return; + } } +} - if (starter) { - data = starter(); - if (data == NULL) { - close(sock); - return -1; - } +client_t *client_register(int fd, run_client_t runner, void *data) +{ + if (fd < 0) { + return NULL; } - tmp = server_acquire(); - tmp->fd = sock; - tmp->listener = true; - tmp->event = false; + client_t *tmp = client_acquire(); + tmp->io.fd = fd; tmp->data = data; - tmp->clear_data = deleter; - epoll_register(sock, EPOLLIN, tmp); - array_add(listeners, tmp); - return 0; + tmp->run = runner; + tmp->clear_data = NULL; + ev_io_init(&tmp->io.io, client_cb, tmp->io.fd, EV_READ); + ev_io_start(gl_loop, &tmp->io.io); + return tmp; +} + + +/* Listeners management. + */ + +/* 1 - Allocation */ + +static listener_t *listener_new(void) +{ + listener_t *io = p_new(listener_t, 1); + io->io.fd = -1; + return io; +} + +static inline void listener_wipe(listener_t *io) +{ + server_io_wipe(&io->io); } -static int start_client(server_t *server, start_client_t starter, - delete_client_t deleter) +static inline void listener_delete(listener_t **io) +{ + if (*io) { + listener_wipe(*io); + p_delete(io); + } +} + + +/* 2 - Management */ + +static void listener_cb(EV_P_ struct ev_io *w, int events) { - server_t *tmp; + listener_t *server = (listener_t*)w; + client_t *tmp; void* data = NULL; int sock; - sock = accept_nonblock(server->fd); + sock = accept_nonblock(server->io.fd); if (sock < 0) { UNIXERR("accept"); - return -1; + ev_unloop(EV_A_ EVUNLOOP_ALL); + return; } - if (starter) { - data = starter(server); + if (gl_client_start) { + data = gl_client_start(server); if (data == NULL) { close(sock); - return -1; + ev_unloop(EV_A_ EVUNLOOP_ALL); + return; } } - tmp = server_acquire(); - tmp->listener = false; - tmp->event = false; - tmp->fd = sock; + tmp = client_acquire(); + tmp->io.fd = sock; tmp->data = data; - tmp->clear_data = deleter; - epoll_register(sock, EPOLLIN, tmp); - return 0; + tmp->run = gl_client_run; + tmp->clear_data = gl_client_delete; + ev_io_init(&tmp->io.io, client_cb, tmp->io.fd, EV_READ); + ev_io_start(gl_loop, &tmp->io.io); } -server_t * event_register(int fd, void *data) +listener_t *start_listener(int port) { - int fds[2]; - if (fd == -1) { - if (pipe(fds) != 0) { - UNIXERR("pipe"); - return NULL; - } - if (setnonblock(fds[0]) != 0) { - close(fds[0]); - close(fds[1]); - return NULL; - } + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr = { htonl(INADDR_LOOPBACK) }, + }; + listener_t *tmp; + int sock; + + addr.sin_port = htons(port); + sock = tcp_listen_nonblock((const struct sockaddr *)&addr, sizeof(addr)); + if (sock < 0) { + return NULL; } - server_t *tmp = server_acquire(); - tmp->listener = false; - tmp->event = true; - tmp->fd = fd == -1 ? fds[0] : fd; - tmp->fd2 = fd == -1 ? fds[1] : -1; - tmp->data = data; - epoll_register(fds[0], EPOLLIN, tmp); + tmp = listener_new(); + tmp->io.fd = sock; + ev_io_init(&tmp->io.io, listener_cb, tmp->io.fd, EV_READ); + ev_io_start(gl_loop, &tmp->io.io); + array_add(listeners, tmp); return tmp; } -bool event_fire(server_t *event) + + + +/* Server runtime stuff. + */ + +static int server_init(void) { - static const char *data = ""; - if (event->fd2 == -1) { - return false; - } - return write(event->fd2, data, 1) == 0; + gl_loop = ev_default_loop(0); + return 0; } -bool event_cancel(server_t *event) +static void server_shutdown(void) { - char buff[32]; - while (true) { - ssize_t res = read(event->fd, buff, 32); - if (res == -1 && errno != EAGAIN && errno != EINTR) { - UNIXERR("read"); - return false; - } else if (res == -1 && errno == EINTR) { - continue; - } else if (res != 32) { - return true; - } + array_deep_wipe(listeners, listener_delete); + array_deep_wipe(client_pool, client_delete); +} +module_init(server_init); +module_exit(server_shutdown); + + +static void refresh_cb(EV_P_ struct ev_signal *w, int event) +{ + log_state = "refreshing "; + if (!gl_config_refresh(gl_config)) { + ev_unloop(EV_A_ EVUNLOOP_ALL); + info("failed"); + } else { + info("done"); } + log_state = ""; } -void event_release(server_t *event) +static void exit_cb(EV_P_ struct ev_signal *w, int event) { - epoll_unregister(event->fd); - server_release(event); + ev_unloop(EV_A_ EVUNLOOP_ALL); } int server_loop(start_client_t starter, delete_client_t deleter, - run_client_t runner, event_handler_t handler, - refresh_t refresh, void* config) + run_client_t runner, refresh_t refresh, void* config) { - info("entering processing loop"); - while (!sigint) { - struct epoll_event evts[1024]; - int n; - - if (sighup && refresh) { - sighup = false; - info("refreshing..."); - if (!refresh(config)) { - crit("error while refreshing configuration"); - return EXIT_FAILURE; - } - info("refresh done, processing loop restarts"); - } + struct ev_signal ev_sighup; + struct ev_signal ev_sigint; + struct ev_signal ev_sigterm; - n = epoll_select(evts, countof(evts), -1); - if (n < 0) { - if (errno != EAGAIN && errno != EINTR) { - UNIXERR("epoll_wait"); - return EXIT_FAILURE; - } - continue; - } + gl_client_start = starter; + gl_client_delete = deleter; + gl_client_run = runner; + gl_config_refresh = refresh; + gl_config = config; - while (--n >= 0) { - server_t *d = evts[n].data.ptr; - - if (d->listener) { - (void)start_client(d, starter, deleter); - continue; - } else if (d->event) { - if (handler) { - if (!handler(d, config)) { - event_release(d); - } - } else { - event_release(d); - } - continue; - } - - if (evts[n].events & EPOLLIN) { - if (runner(d, config) < 0) { - server_release(d); - continue; - } - } - - if ((evts[n].events & EPOLLOUT) && d->obuf.len) { - if (buffer_write(&d->obuf, d->fd) < 0) { - server_release(d); - continue; - } - if (!d->obuf.len) { - epoll_modify(d->fd, EPOLLIN, d); - } - } - } + if (refresh != NULL) { + ev_signal_init(&ev_sighup, refresh_cb, SIGHUP); + ev_signal_start(gl_loop, &ev_sighup); } + ev_signal_init(&ev_sigint, exit_cb, SIGINT); + ev_signal_start(gl_loop, &ev_sigint); + ev_signal_init(&ev_sigterm, exit_cb, SIGTERM); + ev_signal_start(gl_loop, &ev_sigterm); + + log_state = ""; + info("entering processing loop"); + ev_loop(gl_loop, 0); info("exit requested"); return EXIT_SUCCESS; }