Implement lightweight getaddrinfo_a wrappers.
authorPierre Habouzit <madcoder@debian.org>
Fri, 27 Apr 2007 01:57:16 +0000 (03:57 +0200)
committerPierre Habouzit <madcoder@debian.org>
Fri, 27 Apr 2007 01:57:16 +0000 (03:57 +0200)
  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 <madcoder@debian.org>
Makefile
gai.c [new file with mode: 0644]
gai.h [new file with mode: 0644]
job.c
job.h
mk/cflags.mk
postfix.c
postlicyd.c
query.h

index 19b5920..179fed8 100644 (file)
--- a/Makefile
+++ b/Makefile
 ##############################################################################
 
 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 (file)
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 <assert.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <syslog.h>
+
+#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 (file)
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 <netdb.h>
+
+#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 (file)
--- 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 (file)
--- a/job.h
+++ b/job.h
 
 #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);
index e4f5b8b..4b453e7 100644 (file)
@@ -35,7 +35,7 @@ endif
 
 LDFLAGS += -Wl,--warn-common
 
-CFLAGS := -g
+CFLAGS += -g
 
 # Use pipes and not temp files.
 CFLAGS += -pipe
index 380988f..f88feba 100644 (file)
--- 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:
index 7877665..c20973e 100644 (file)
 #include <syslog.h>
 
 #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 (file)
--- 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