From 59c1f51ef38081d87885a37873545154c7a23e2d Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Fri, 27 Apr 2007 03:57:16 +0200 Subject: [PATCH] Implement lightweight getaddrinfo_a wrappers. Add the module gai.[hc]. Various improvements for jobs. Cosmetics in postlicyd.c Yes we are doing _GNU_SOURCE code now (Makefile). Signed-off-by: Pierre Habouzit --- Makefile | 5 +- gai.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++ gai.h | 56 ++++++++++++++ job.c | 22 +++--- job.h | 15 ++-- mk/cflags.mk | 2 +- postfix.c | 6 +- postlicyd.c | 20 +++-- query.h | 3 - 9 files changed, 302 insertions(+), 32 deletions(-) create mode 100644 gai.c create mode 100644 gai.h diff --git a/Makefile b/Makefile index 19b5920..179fed8 100644 --- a/Makefile +++ b/Makefile @@ -30,12 +30,13 @@ ############################################################################## include mk/cflags.mk +CFLAGS += --std=gnu99 -D_GNU_SOURCE -D_FORTIFY_SOURCE=1 PROGRAMS = postlicyd postlicyd_SOURCES = \ - str.h buffer.h job.h postfix.h query.h \ - str.c buffer.c job.c postfix.c \ + str.h buffer.h job.h postfix.h gai.h query.h \ + str.c buffer.c job.c postfix.c gai.c \ postlicyd.c postlicyd_LIBADD = -lanl diff --git a/gai.c b/gai.c new file mode 100644 index 0000000..ce91e8b --- /dev/null +++ b/gai.c @@ -0,0 +1,205 @@ +/******************************************************************************/ +/* postlicyd: a postfix policy daemon with a lot of features */ +/* ~~~~~~~~~ */ +/* ________________________________________________________________________ */ +/* */ +/* 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 © 2007 Pierre Habouzit + */ + +#include +#include +#include +#include +#include + +#include "gai.h" + +#define GAI_SIGNO (SIGRTMIN+0) + +static struct { + gai_req **ring; + int start, len, size; +} fifo = { + .ring = NULL, + .start = 0, + .len = 0, + .size = 0, +}; + +static int gai_fifo_end(void) +{ + int res = fifo.start + fifo.len; + return res >= fifo.size ? res - fifo.size : fifo.size; +} + +static void gai_fifo_append(gai_req *rq) +{ + if (fifo.len >= fifo.size) { + p_realloc(&fifo.ring, fifo.size += 16); + } + + fifo.ring[gai_fifo_end()] = rq; + fifo.len++; +} + +static gai_req *gai_fifo_pop(void) +{ + gai_req *res = NULL; + + while (!res && fifo.len) { + res = fifo.ring[fifo.start]; + fifo.start++, fifo.len--; + if (fifo.start >= fifo.size) + fifo.start = 0; + } + + return res; +} + +static void gai_fifo_remove(gai_req *rq) +{ + int i, end = gai_fifo_end(); + + if (fifo.start + fifo.len <= fifo.size) { + for (i = fifo.start; i < end; i++) { + if (fifo.ring[i] == rq) + fifo.ring[i] = NULL; + } + } else { + for (i = fifo.start; i < fifo.size; i++) { + if (fifo.ring[i] == rq) + fifo.ring[i] = NULL; + } + for (i = 0; i < end; i++) { + if (fifo.ring[i] == rq) + fifo.ring[i] = NULL; + } + } +} + +static gai_req *gai_req_new(void) +{ + gai_req *rq = p_new(gai_req, 1); + rq->cbp = &rq->cb; + return rq; +} +static void gai_req_delete(gai_req **rqp) +{ + if (*rqp) { + gai_req *rq = *rqp; + + switch (gai_error(rq->cbp)) { + case EAI_INPROGRESS: + if (gai_cancel(rq->cbp) == EAI_NOTCANCELED) { + rq->caller = NULL; + *rqp = NULL; + return; + } + break; + + case EAI_CANCELED: + break; + + default: /* we are likely in the notify list remove us ! */ + if (rq->caller) { + gai_fifo_remove(rq); + } + } + + p_delete((char **)&rq->cb.ar_name); + freeaddrinfo(rq->cb.ar_result); + rq->cb.ar_result = NULL; + p_delete(rqp); + } +} + +gai_req *gai_query(job_t *caller, const char *lookup) +{ + struct sigevent se = { + .sigev_signo = GAI_SIGNO, + .sigev_notify = SIGEV_SIGNAL, + }; + gai_req *res; + + se.sigev_value.sival_ptr = res = gai_req_new(); + res->cb.ar_name = strdup(lookup); + res->caller = caller; + getaddrinfo_a(GAI_NOWAIT, &res->cbp, 1, &se); + + return res; +} + +void gai_abort(gai_req **rqp) +{ + gai_req_delete(rqp); +} + + +static void gai_sigaction(int sig, siginfo_t *si, void *ctx) +{ + gai_req *req = si->_sifields._rt.si_sigval.sival_ptr; + + assert (sig == GAI_SIGNO); + assert (req && gai_error(req->cbp) != EAI_INPROGRESS); + + if (req->caller) { + gai_fifo_append(req); + } else { + gai_req_delete(&req); + } +} + +void gai_initialize(void) +{ + struct sigaction sa = { + .sa_sigaction = &gai_sigaction, + .sa_flags = SA_SIGINFO, + }; + if (sigaction(GAI_SIGNO, &sa, NULL) < 0) { + syslog(LOG_ERR, "cannot hook SIGRTMIN+0: %m"); + exit(EX_OSERR); + } +} + +void gai_process(void) +{ + gai_req *req; + + while ((req = gai_fifo_pop())) { + assert (req->caller && req->caller->process); + req->caller->process(req->caller); + req->caller = NULL; /* make delete faster: avoid gai_fifo_remove() */ + } +} + +void gai_shutdown(void) +{ + /* TODO: deallocate the fifo properly */ +} diff --git a/gai.h b/gai.h new file mode 100644 index 0000000..decc0ea --- /dev/null +++ b/gai.h @@ -0,0 +1,56 @@ +/******************************************************************************/ +/* postlicyd: a postfix policy daemon with a lot of features */ +/* ~~~~~~~~~ */ +/* ________________________________________________________________________ */ +/* */ +/* 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 © 2007 Pierre Habouzit + */ + +#ifndef POSTLICYD_GAI_H +#define POSTLICYD_GAI_H + +#include + +#include "job.h" + +typedef struct gai_req { + struct gaicb cb; + struct gaicb *cbp; /* points to cb */ + job_t *caller; +} gai_req; + +gai_req *gai_query(job_t *, const char *lookup); +void gai_abort(gai_req **); + +void gai_initialize(void); +void gai_process(void); +void gai_shutdown(void); + +#endif diff --git a/job.c b/job.c index b7edeac..454b35b 100644 --- a/job.c +++ b/job.c @@ -54,8 +54,8 @@ # endif #endif - #include "job.h" +#include "gai.h" static int epollfd = -1; static bool sigint = false; @@ -77,11 +77,11 @@ static job_t *job_register_fd(job_t *job) { struct epoll_event event = { .data.ptr = job, .events = EPOLLRDHUP }; - if (job->state & (JOB_READ | JOB_LISTEN)) { + if (job->mode & (JOB_READ | JOB_LISTEN)) { event.events |= EPOLLIN; } - if (job->state & (JOB_WRITE | JOB_CONN)) { + if (job->mode & (JOB_WRITE | JOB_CONN)) { event.events |= EPOLLOUT; } @@ -94,19 +94,19 @@ static job_t *job_register_fd(job_t *job) return job; } -void job_update_state(job_t *job, int state) +void job_update_mode(job_t *job, int mode) { struct epoll_event event = { .data.ptr = job, .events = EPOLLRDHUP }; - if (job->state == state) + if (job->mode == mode) return; - job->state = state; - if (job->state & (JOB_READ | JOB_LISTEN)) { + job->mode = mode; + if (job->mode & (JOB_READ | JOB_LISTEN)) { event.events |= EPOLLIN; } - if (job->state & (JOB_WRITE | JOB_CONN)) { + if (job->mode & (JOB_WRITE | JOB_CONN)) { event.events |= EPOLLOUT; } @@ -116,7 +116,7 @@ void job_update_state(job_t *job, int state) } } -job_t *job_accept(job_t *listener, int state) +job_t *job_accept(job_t *listener, int mode) { int sock; job_t *res; @@ -133,7 +133,7 @@ job_t *job_accept(job_t *listener, int state) res = job_new(); res->fd = sock; - res->state = state; + res->mode = mode; res->process = listener->process; res->stop = listener->stop; return job_register_fd(res); @@ -202,6 +202,8 @@ void job_loop(void) job_delete(&job); } } + + gai_process(); } } diff --git a/job.h b/job.h index 7a63829..481f625 100644 --- a/job.h +++ b/job.h @@ -38,11 +38,11 @@ #include "mem.h" -enum job_state { +enum job_mode { JOB_IDLE = 0x00, JOB_READ = 0x01, JOB_WRITE = 0x02, - JOB_RDWR = 0x03, + JOB_RDWR = JOB_READ | JOB_WRITE, JOB_LISTEN = 0x04, JOB_CONN = 0x08, }; @@ -61,9 +61,10 @@ enum smtp_state { typedef struct jpriv_t jpriv_t; typedef struct job_t { - unsigned state : 6; - unsigned done : 1; - unsigned error : 1; + unsigned mode : 6; /* 4 are enough, 2 used as padding */ + unsigned done : 1; + unsigned error : 1; + unsigned state : 24; int fd; @@ -80,8 +81,8 @@ static inline job_t *job_new(void) { } void job_delete(job_t **job); -void job_update_state(job_t *job, int state); -job_t *job_accept(job_t *listener, int state); +void job_update_mode(job_t *job, int mode); +job_t *job_accept(job_t *listener, int mode); void job_initialize(void); void job_loop(void); diff --git a/mk/cflags.mk b/mk/cflags.mk index e4f5b8b..4b453e7 100644 --- a/mk/cflags.mk +++ b/mk/cflags.mk @@ -35,7 +35,7 @@ endif LDFLAGS += -Wl,--warn-common -CFLAGS := -g +CFLAGS += -g # Use pipes and not temp files. CFLAGS += -pipe diff --git a/postfix.c b/postfix.c index 380988f..f88feba 100644 --- a/postfix.c +++ b/postfix.c @@ -70,7 +70,7 @@ static void postfix_process(job_t *job) { int nb; - switch (job->state) { + switch (job->mode) { case JOB_LISTEN: if ((job = job_accept(job, JOB_READ))) { job->jdata = postfix_jpriv_new(); @@ -92,7 +92,7 @@ static void postfix_process(job_t *job) if (job->jdata->obuf.len) return; - job_update_state(job, JOB_READ); + job_update_mode(job, JOB_READ); /* fall through */ @@ -114,7 +114,7 @@ static void postfix_process(job_t *job) return; /* TODO: do the parse */ - job_update_state(job, JOB_IDLE); + job_update_mode(job, JOB_IDLE); return; default: diff --git a/postlicyd.c b/postlicyd.c index 7877665..c20973e 100644 --- a/postlicyd.c +++ b/postlicyd.c @@ -39,30 +39,38 @@ #include #include "job.h" +#include "gai.h" bool cleanexit = false; -static void shutdown(void) +static void main_initialize(void) +{ + openlog("postlicyd", LOG_PID, LOG_MAIL); + gai_initialize(); + job_initialize(); + syslog(LOG_INFO, "Starting..."); +} + +static void main_shutdown(void) { syslog(LOG_INFO, cleanexit ? "Stopping..." : "Unclean exit..."); job_shutdown(); + gai_shutdown(); closelog(); } int main(void) { - if (atexit(shutdown)) { + if (atexit(main_shutdown)) { fputs("Cannot hook my atexit function, quitting !\n", stderr); return EX_CONFIG; } - openlog("postlicyd", LOG_PID, LOG_MAIL); - job_initialize(); - syslog(LOG_INFO, "Starting..."); + main_initialize(); job_loop(); cleanexit = true; - shutdown(); + main_shutdown(); return 0; } diff --git a/query.h b/query.h index 57a3eb3..f8df50a 100644 --- a/query.h +++ b/query.h @@ -81,7 +81,4 @@ static inline void query_wipe(query_t *rq) { DO_NEW(query_t, query); DO_DELETE(query_t, query); - -job_t *job_accept(job_t *listener, int state); - #endif -- 2.20.1