X-Git-Url: http://git.madism.org/?a=blobdiff_plain;f=common%2Fserver.c;h=64368f41a8d2bd1f33f38ae23a86aa852b820688;hb=fd9afbc80e667a37f1643a8b8d6d401a6ff191e4;hp=b47da2f48c544c05b9f5894f89c1510bc354a5a4;hpb=785558696ffa16453be0b5b565c46b6426126d1e;p=apps%2Fpfixtools.git diff --git a/common/server.c b/common/server.c index b47da2f..64368f4 100644 --- a/common/server.c +++ b/common/server.c @@ -16,213 +16,320 @@ /* products derived from this software without specific prior written */ /* permission. */ /* */ -/* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND */ -/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE */ -/* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */ -/* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS */ -/* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR */ -/* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF */ -/* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS */ -/* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN */ -/* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ -/* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF */ -/* THE POSSIBILITY OF SUCH DAMAGE. */ +/* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS */ +/* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */ +/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ +/* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY */ +/* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */ +/* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS */ +/* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) */ +/* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, */ +/* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN */ +/* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */ +/* POSSIBILITY OF SUCH DAMAGE. */ +/* */ +/* Copyright (c) 2006-2008 the Authors */ +/* see AUTHORS and source files for details */ /******************************************************************************/ /* * Copyright © 2008 Florent Bruneau */ +#include #include "server.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; + +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; -struct ev_loop *global_loop = NULL; -static start_client_t client_start = NULL; -static delete_client_t client_delete = NULL; -static run_client_t client_run = NULL; -static refresh_t config_refresh = NULL; -static void *config_ptr = NULL; +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; -static server_t* server_new(void) + +/* Server io structure methods. + */ + +static inline void server_io_wipe(server_io_t *io) { - server_t* server = p_new(server_t, 1); - server->fd = -1; + 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) +{ + 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) { - if (server->fd >= 0) { - ev_io_stop(global_loop, &server->io); - close(server->fd); - server->fd = -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; } -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 int server_init(void) +/* 2 - Doing I/O */ + +void client_io_none(client_t *server) { - global_loop = ev_default_loop(0); - return 0; + ev_io_stop(gl_loop, &server->io.io); } -static void server_shutdown(void) +void client_io_rw(client_t *server) { - array_deep_wipe(listeners, server_delete); - array_deep_wipe(server_pool, server_delete); + 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); } -module_init(server_init); -module_exit(server_shutdown); -static void client_cb(EV_P_ struct ev_io *w, int events) +void client_io_ro(client_t *server) { - server_t *server = (server_t*)w; + 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); +} - debug("Entering client_cb for %p, %d (%d | %d)", w, events, EV_WRITE, EV_READ); +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->fd) < 0) { - server_release(server); + if (buffer_write(&server->obuf, server->io.fd) < 0) { + client_release(server); return; } if (!server->obuf.len) { - ev_io_set(&server->io, server->fd, EV_READ); + client_io_ro(server); } } if (events & EV_READ) { - if (server->run(server, config_ptr) < 0) { - server_release(server); + if (server->run(server, gl_config) < 0) { + client_release(server); return; } } } -static int start_client(server_t *server, start_client_t starter, - run_client_t runner, delete_client_t deleter) +client_t *client_register(int fd, run_client_t runner, void *data) +{ + if (fd < 0) { + return NULL; + } + + client_t *tmp = client_acquire(); + tmp->io.fd = fd; + tmp->data = data; + 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 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->fd = sock; + tmp = client_acquire(); + tmp->io.fd = sock; tmp->data = data; - tmp->run = runner; - tmp->clear_data = deleter; - ev_io_init(&tmp->io, client_cb, tmp->fd, EV_READ); - ev_io_start(global_loop, &tmp->io); - 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); } -static void server_cb(EV_P_ struct ev_io *w, int events) -{ - server_t *server = (server_t*)w; - if (start_client(server, client_start, client_run, client_delete) != 0) { - ev_unloop(EV_A_ EVUNLOOP_ALL); - } -} - -int start_server(int port, start_listener_t starter, delete_client_t deleter) +listener_t *start_listener(int port) { struct sockaddr_in addr = { .sin_family = AF_INET, .sin_addr = { htonl(INADDR_LOOPBACK) }, }; - server_t *tmp; - void* data = NULL; + listener_t *tmp; int sock; addr.sin_port = htons(port); sock = tcp_listen_nonblock((const struct sockaddr *)&addr, sizeof(addr)); if (sock < 0) { - return -1; - } - - if (starter) { - data = starter(); - if (data == NULL) { - close(sock); - return -1; - } + return NULL; } - tmp = server_acquire(); - tmp->fd = sock; - tmp->data = data; - tmp->run = NULL; - tmp->clear_data = deleter; - ev_io_init(&tmp->io, server_cb, tmp->fd, EV_READ); - ev_io_start(global_loop, &tmp->io); + 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 0; + return tmp; } -server_t *server_register(int fd, run_client_t runner, void *data) + + + +/* Server runtime stuff. + */ + +static int server_init(void) { - if (fd < 0) { - return NULL; - } + gl_loop = ev_default_loop(0); + return 0; +} - server_t *tmp = server_acquire(); - tmp->fd = fd; - tmp->data = data; - tmp->run = runner; - tmp->clear_data = NULL; - ev_io_init(&tmp->io, client_cb, tmp->fd, EV_READ); - ev_io_start(global_loop, &tmp->io); - return tmp; +static void server_shutdown(void) +{ + 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) { - if (!config_refresh(config_ptr)) { + log_state = "refreshing "; + if (!gl_config_refresh(gl_config)) { ev_unloop(EV_A_ EVUNLOOP_ALL); + info("failed"); + } else { + info("done"); } + log_state = ""; } static void exit_cb(EV_P_ struct ev_signal *w, int event) @@ -237,23 +344,24 @@ int server_loop(start_client_t starter, delete_client_t deleter, struct ev_signal ev_sigint; struct ev_signal ev_sigterm; - client_start = starter; - client_delete = deleter; - client_run = runner; - config_refresh = refresh; - config_ptr = config; + gl_client_start = starter; + gl_client_delete = deleter; + gl_client_run = runner; + gl_config_refresh = refresh; + gl_config = config; if (refresh != NULL) { ev_signal_init(&ev_sighup, refresh_cb, SIGHUP); - ev_signal_start(global_loop, &ev_sighup); + ev_signal_start(gl_loop, &ev_sighup); } ev_signal_init(&ev_sigint, exit_cb, SIGINT); - ev_signal_start(global_loop, &ev_sigint); + ev_signal_start(gl_loop, &ev_sigint); ev_signal_init(&ev_sigterm, exit_cb, SIGTERM); - ev_signal_start(global_loop, &ev_sigterm); + ev_signal_start(gl_loop, &ev_sigterm); + log_state = ""; info("entering processing loop"); - ev_loop(global_loop, 0); + ev_loop(gl_loop, 0); info("exit requested"); return EXIT_SUCCESS; }