summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2014-02-20 16:30:27 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2014-02-20 16:30:27 +0000
commit6039f81e4886071d61e5cfebc3b16e9ab0b8f01f (patch)
tree93f7d92f733015e6bef331538d79fcdace1b3ae7
parent5c026b66583e20f4f1455f7f0da773f64c26992d (diff)
downloadrspamd-6039f81e4886071d61e5cfebc3b16e9ab0b8f01f.tar.gz
rspamd-6039f81e4886071d61e5cfebc3b16e9ab0b8f01f.zip
Support accepting listening sockets from systemd.
-rw-r--r--src/cfg_file.h1
-rw-r--r--src/cfg_utils.c10
-rw-r--r--src/main.c54
3 files changed, 61 insertions, 4 deletions
diff --git a/src/cfg_file.h b/src/cfg_file.h
index 13acb158f..c1ebfd93c 100644
--- a/src/cfg_file.h
+++ b/src/cfg_file.h
@@ -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;
};
diff --git a/src/cfg_utils.c b/src/cfg_utils.c
index 8575b254b..dbd4f0f83 100644
--- a/src/cfg_utils.c
+++ b/src/cfg_utils.c
@@ -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))) {
diff --git a/src/main.c b/src/main.c
index ae4d5d409..a8196ef06 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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);