From 10b49f7af56977b8c27a26438b3cfb07ca63ae90 Mon Sep 17 00:00:00 2001 From: Florent Bruneau Date: Mon, 8 Sep 2008 12:10:50 +0200 Subject: [PATCH] Abstract server loop. Signed-off-by: Florent Bruneau --- Makefile | 2 +- main-postlicyd.c | 114 +++++--------------------------- server.c | 165 +++++++++++++++++++++++++++++++++++++++++++++++ server.h | 62 ++++++++++++++++++ 4 files changed, 243 insertions(+), 100 deletions(-) create mode 100644 server.c create mode 100644 server.h diff --git a/Makefile b/Makefile index 40894b5..d4c2aa0 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ GENERATED = tokens.h tokens.c lib_SOURCES = str.c buffer.c common.c epoll.c $(GENERATED) -postlicyd_SOURCES = greylist.c rbl.c main-postlicyd.c lib.a +postlicyd_SOURCES = greylist.c rbl.c main-postlicyd.c server.c lib.a postlicyd_LIBADD = $(TC_LIBS) pfix-srsd_SOURCES = main-srsd.c lib.a diff --git a/main-postlicyd.c b/main-postlicyd.c index 1e1ce4d..97afe21 100644 --- a/main-postlicyd.c +++ b/main-postlicyd.c @@ -39,6 +39,7 @@ #include "common.h" #include "epoll.h" #include "tokens.h" +#include "server.h" #define DAEMON_NAME "postlicyd" #define DEFAULT_PORT 10000 @@ -91,30 +92,16 @@ typedef struct query_t { const char *eoq; } query_t; -typedef struct plicyd_t { - unsigned listener : 1; - int fd; - buffer_t ibuf; - buffer_t obuf; - query_t q; -} plicyd_t; - - -static plicyd_t *plicyd_new(void) +static void* query_new() { - plicyd_t *plicyd = p_new(plicyd_t, 1); - plicyd->fd = -1; - return plicyd; + return p_new(query_t, 1); } -static void plicyd_delete(plicyd_t **plicyd) +static void query_delete(void *arg) { - if (*plicyd) { - if ((*plicyd)->fd >= 0) - close((*plicyd)->fd); - buffer_wipe(&(*plicyd)->ibuf); - buffer_wipe(&(*plicyd)->obuf); - p_delete(plicyd); + query_t **query = arg; + if (*query) { + p_delete(query); } } @@ -213,23 +200,23 @@ static int postfix_parsejob(query_t *query, char *p) } __attribute__((format(printf,2,0))) -static void policy_answer(plicyd_t *pcy, const char *fmt, ...) +static void policy_answer(server_t *pcy, const char *fmt, ...) { va_list args; va_start(args, fmt); buffer_addvf(&pcy->obuf, fmt, args); va_end(args); buffer_addstr(&pcy->obuf, "\n\n"); - buffer_consume(&pcy->ibuf, pcy->q.eoq - pcy->ibuf.data); + buffer_consume(&pcy->ibuf, ((query_t*)(pcy->data))->eoq - pcy->ibuf.data); epoll_modify(pcy->fd, EPOLLIN | EPOLLOUT, pcy); } -static void policy_process(plicyd_t *pcy) +static void policy_process(server_t *pcy) { policy_answer(pcy, "DUNNO"); } -static int policy_run(plicyd_t *pcy) +static int policy_run(server_t *pcy, void* config) { ssize_t search_offs = MAX(0, pcy->ibuf.len - 1); int nb = buffer_read(&pcy->ibuf, pcy->fd, -1); @@ -250,9 +237,9 @@ static int policy_run(plicyd_t *pcy) if (!(eoq = strstr(pcy->ibuf.data + search_offs, "\n\n"))) return 0; - if (postfix_parsejob(&pcy->q, pcy->ibuf.data) < 0) + if (postfix_parsejob(pcy->data, pcy->ibuf.data) < 0) return -1; - pcy->q.eoq = eoq + strlen("\n\n"); + ((query_t*)pcy->data)->eoq = eoq + strlen("\n\n"); epoll_modify(pcy->fd, 0, pcy); policy_process(pcy); return 0; @@ -260,40 +247,7 @@ static int policy_run(plicyd_t *pcy) int start_listener(int port) { - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_addr = { htonl(INADDR_LOOPBACK) }, - }; - plicyd_t *tmp; - int sock; - - addr.sin_port = htons(port); - sock = tcp_listen_nonblock((const struct sockaddr *)&addr, sizeof(addr)); - if (sock < 0) { - return -1; - } - - tmp = plicyd_new(); - tmp->fd = sock; - tmp->listener = true; - epoll_register(sock, EPOLLIN, tmp); - return 0; -} - -void start_client(plicyd_t *d) -{ - plicyd_t *tmp; - int sock; - - sock = accept_nonblock(d->fd); - if (sock < 0) { - UNIXERR("accept"); - return; - } - - tmp = plicyd_new(); - tmp->fd = sock; - epoll_register(sock, EPOLLIN, tmp); + return start_server(port, NULL, NULL); } /* administrivia {{{ */ @@ -379,45 +333,7 @@ int main(int argc, char *argv[]) if (start_listener(port) < 0) return EXIT_FAILURE; - while (!sigint) { - struct epoll_event evts[1024]; - int n; - - n = epoll_select(evts, countof(evts), -1); - if (n < 0) { - if (errno != EAGAIN && errno != EINTR) { - UNIXERR("epoll_wait"); - return EXIT_FAILURE; - } - continue; - } - - while (--n >= 0) { - plicyd_t *d = evts[n].data.ptr; - - if (d->listener) { - start_client(d); - continue; - } - - if (evts[n].events & EPOLLIN) { - if (policy_run(d) < 0) { - plicyd_delete(&d); - continue; - } - } - - if ((evts[n].events & EPOLLOUT) && d->obuf.len) { - if (buffer_write(&d->obuf, d->fd) < 0) { - plicyd_delete(&d); - continue; - } - if (!d->obuf.len) { - epoll_modify(d->fd, EPOLLIN, d); - } - } - } - } + (void)server_loop(query_new, query_delete, policy_run, NULL); syslog(LOG_INFO, "Stopping..."); return EXIT_SUCCESS; diff --git a/server.c b/server.c new file mode 100644 index 0000000..3becd75 --- /dev/null +++ b/server.c @@ -0,0 +1,165 @@ +/******************************************************************************/ +/* pfixtools: a collection of postfix related tools */ +/* ~~~~~~~~~ */ +/* ________________________________________________________________________ */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions */ +/* are met: */ +/* */ +/* 1. Redistributions of source code must retain the above copyright */ +/* notice, this list of conditions and the following disclaimer. */ +/* 2. Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* 3. The names of its contributors may not be used to endorse or promote */ +/* 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. */ +/******************************************************************************/ + +/* + * Copyright © 2008 Florent Bruneau + */ + +#include "server.h" +#include "epoll.h" + +static server_t* server_new(void) +{ + server_t* server = p_new(server_t, 1); + server->fd = -1; + return server; +} + +static void server_delete(server_t **server) +{ + if (*server) { + if ((*server)->fd >= 0) { + close((*server)->fd); + } + if ((*server)->data && (*server)->clear_data) { + (*server)->clear_data(&(*server)->data); + } + buffer_wipe(&(*server)->ibuf); + buffer_wipe(&(*server)->obuf); + p_delete(server); + } +} + +int start_server(int port, start_listener_t starter, delete_client_t deleter) +{ + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr = { htonl(INADDR_LOOPBACK) }, + }; + server_t *tmp; + void* data = NULL; + 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; + } + } + + tmp = server_new(); + tmp->fd = sock; + tmp->listener = true; + tmp->data = data; + tmp->clear_data = deleter; + epoll_register(sock, EPOLLIN, tmp); + return 0; +} + +static int start_client(server_t *server, start_client_t starter, + delete_client_t deleter) +{ + server_t *tmp; + void* data = NULL; + int sock; + + sock = accept_nonblock(server->fd); + if (sock < 0) { + UNIXERR("accept"); + return -1; + } + + if (starter) { + data = starter(); + if (data == NULL) { + close(sock); + return -1; + } + } + + tmp = server_new(); + tmp->fd = sock; + tmp->data = data; + tmp->clear_data = deleter; + epoll_register(sock, EPOLLIN, tmp); + return 0; +} + +int server_loop(start_client_t starter, delete_client_t deleter, + run_client_t runner, void* config) { + while (!sigint) { + struct epoll_event evts[1024]; + int n; + + n = epoll_select(evts, countof(evts), -1); + if (n < 0) { + if (errno != EAGAIN && errno != EINTR) { + UNIXERR("epoll_wait"); + return -1; + } + continue; + } + + while (--n >= 0) { + server_t *d = evts[n].data.ptr; + + if (d->listener) { + (void)start_client(d, starter, deleter); + continue; + } + + if (evts[n].events & EPOLLIN) { + if (runner(d, config) < 0) { + server_delete(&d); + continue; + } + } + + if ((evts[n].events & EPOLLOUT) && d->obuf.len) { + if (buffer_write(&d->obuf, d->fd) < 0) { + server_delete(&d); + continue; + } + if (!d->obuf.len) { + epoll_modify(d->fd, EPOLLIN, d); + } + } + } + } + return 0; +} diff --git a/server.h b/server.h new file mode 100644 index 0000000..9cfba36 --- /dev/null +++ b/server.h @@ -0,0 +1,62 @@ +/******************************************************************************/ +/* pfixtools: a collection of postfix related tools */ +/* ~~~~~~~~~ */ +/* ________________________________________________________________________ */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions */ +/* are met: */ +/* */ +/* 1. Redistributions of source code must retain the above copyright */ +/* notice, this list of conditions and the following disclaimer. */ +/* 2. Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* 3. The names of its contributors may not be used to endorse or promote */ +/* 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. */ +/******************************************************************************/ + +/* + * Copyright © 2008 Florent Bruneau + */ + +#ifndef PFIXTOOLS_SERVER_H +#define PFIXTOOLS_SERVER_H + +#include "buffer.h" + +typedef struct server_t server_t; + +typedef void *(*start_listener_t)(void); +typedef void (*delete_client_t)(void*); +typedef void *(*start_client_t)(void); +typedef int (*run_client_t)(server_t*, void*); + +struct server_t { + unsigned listener : 1; + int fd; + buffer_t ibuf; + buffer_t obuf; + void* data; + delete_client_t clear_data; +}; + +int start_server(int port, start_listener_t starter, delete_client_t deleter); + +int server_loop(start_client_t starter, delete_client_t deleter, + run_client_t runner, void* config); + +#endif -- 2.20.1