]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
Support accepting listening sockets from systemd.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 20 Feb 2014 16:30:27 +0000 (16:30 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 20 Feb 2014 16:30:27 +0000 (16:30 +0000)
src/cfg_file.h
src/cfg_utils.c
src/main.c

index 13acb158fba5773c97cf17688e2f701a8e14ed4a..c1ebfd93c2d75f6ee1071562ce8117a9765afa70 100644 (file)
@@ -227,6 +227,7 @@ struct rspamd_worker_bind_conf {
        gchar *bind_host;
        guint16 bind_port;
        gint ai;
+       gboolean is_systemd;
        struct rspamd_worker_bind_conf *next;
 };
 
index 8575b254b96b565adeed8e636fa8c636363db74e..dbd4f0f83fe961a96978ac90b2c7ee8f405fa763 100644 (file)
@@ -196,7 +196,7 @@ gboolean
 parse_bind_line (struct config_file *cfg, struct worker_conf *cf, const gchar *str)
 {
        struct rspamd_worker_bind_conf *cnf;
-       gchar **tokens, *tmp;
+       gchar **tokens, *tmp, *err;
        gboolean ret;
 
        if (str == NULL) {
@@ -238,6 +238,14 @@ parse_bind_line (struct config_file *cfg, struct worker_conf *cf, const gchar *s
                }
                tokens[0] = tmp;
        }
+       else if (strcmp (tokens[0], "systemd") == 0) {
+               /* The actual socket will be passed by systemd environment */
+               cnf->bind_host = memory_pool_strdup (cfg->cfg_pool, str);
+               cnf->ai = strtoul (tokens[1], &err, 10);
+               if (err == NULL || *err == '\0') {
+                       LL_PREPEND (cf->bind_conf, cnf);
+               }
+       }
        else {
                if ((ret = parse_host_port_priority_strv (cfg->cfg_pool, tokens,
                                &cnf->bind_host, &cnf->bind_port, NULL, DEFAULT_BIND_PORT))) {
index ae4d5d4098bdd1c0d18d4ee8d5ddcab798ed4093..a8196ef062e80902e685798bdc36ab868a3f7c12 100644 (file)
@@ -549,6 +549,48 @@ create_listen_socket (const gchar *addr, gint port, gint listen_type)
        return result;
 }
 
+static GList *
+systemd_get_socket (gint number, gint listen_type)
+{
+       int sock, max;
+       GList *result = NULL;
+       const gchar *e;
+       gchar *err;
+       struct stat st;
+       /* XXX: can we trust the current choice ? */
+       static const int sd_listen_fds_start = 3;
+
+       e = getenv ("LISTEN_FDS");
+       if (e != NULL) {
+               errno = 0;
+               max = strtoul (e, &err, 10);
+               if ((e == NULL || *e == '\0') && max > number + sd_listen_fds_start) {
+                       sock = number + sd_listen_fds_start;
+                       if (fstat (sock, &st) == -1) {
+                               return NULL;
+                       }
+                       if (!S_ISSOCK (st.st_mode)) {
+                               errno = EINVAL;
+                               return NULL;
+                       }
+                       if (listen_type != SOCK_DGRAM) {
+                               if (listen (sock, -1) == -1) {
+                                       return NULL;
+                               }
+                       }
+                       result = g_list_prepend (result, GINT_TO_POINTER (sock));
+               }
+               else if (max <= number + sd_listen_fds_start) {
+                       errno = EOVERFLOW;
+               }
+       }
+       else {
+               errno = ENOENT;
+       }
+
+       return result;
+}
+
 static void
 fork_delayed (struct rspamd_main *rspamd)
 {
@@ -599,10 +641,16 @@ spawn_workers (struct rspamd_main *rspamd)
                                LL_FOREACH (cf->bind_conf, bcf) {
                                        key = make_listen_key (bcf->ai, bcf->bind_host, bcf->bind_port);
                                        if ((p = g_hash_table_lookup (listen_sockets, GINT_TO_POINTER (key))) == NULL) {
-                                               /* Create listen socket */
-                                               ls = create_listen_socket (bcf->bind_host, bcf->bind_port,
-                                                               cf->worker->listen_type);
+                                               if (!bcf->is_systemd) {
+                                                       /* Create listen socket */
+                                                       ls = create_listen_socket (bcf->bind_host, bcf->bind_port,
+                                                                       cf->worker->listen_type);
+                                               }
+                                               else {
+                                                       ls = systemd_get_socket (bcf->ai, cf->worker->listen_type);
+                                               }
                                                if (ls == NULL) {
+                                                       msg_err ("cannot listen on socket %s: %s", bcf->bind_host, strerror (errno));
                                                        exit (-errno);
                                                }
                                                g_hash_table_insert (listen_sockets, GINT_TO_POINTER (key), ls);