aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2014-10-29 12:18:13 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2014-10-29 12:18:13 +0000
commit8c9cf87f25a81677b52ed1a309fea505d1c2174f (patch)
treea5a2de658bc8611452baf8dd76c00dba31e43ac5
parentf58fb61175aa8616b307ec29e919f5556d42777d (diff)
downloadrspamd-8c9cf87f25a81677b52ed1a309fea505d1c2174f.tar.gz
rspamd-8c9cf87f25a81677b52ed1a309fea505d1c2174f.zip
Rework and simplify listen sockets creation.
-rw-r--r--src/libserver/cfg_file.h6
-rw-r--r--src/libserver/cfg_utils.c57
-rw-r--r--src/libutil/addr.c53
-rw-r--r--src/libutil/addr.h9
-rw-r--r--src/main.c63
5 files changed, 96 insertions, 92 deletions
diff --git a/src/libserver/cfg_file.h b/src/libserver/cfg_file.h
index f9e2aa46e..833dd053d 100644
--- a/src/libserver/cfg_file.h
+++ b/src/libserver/cfg_file.h
@@ -199,9 +199,9 @@ struct rspamd_classifier_config {
};
struct rspamd_worker_bind_conf {
- gchar *bind_host;
- guint16 bind_port;
- gint ai;
+ rspamd_inet_addr_t *addrs;
+ guint cnt;
+ gchar *name;
gboolean is_systemd;
struct rspamd_worker_bind_conf *next;
};
diff --git a/src/libserver/cfg_utils.c b/src/libserver/cfg_utils.c
index 8d7988b01..cd1aa0f0f 100644
--- a/src/libserver/cfg_utils.c
+++ b/src/libserver/cfg_utils.c
@@ -59,8 +59,8 @@ rspamd_parse_bind_line (struct rspamd_config *cfg,
const gchar *str)
{
struct rspamd_worker_bind_conf *cnf;
- gchar **tokens, *tmp, *err;
- gboolean ret = TRUE, rc;
+ gchar **tokens, *err;
+ gboolean ret = TRUE;
if (str == NULL) {
return FALSE;
@@ -74,63 +74,30 @@ rspamd_parse_bind_line (struct rspamd_config *cfg,
cnf =
rspamd_mempool_alloc0 (cfg->cfg_pool,
sizeof (struct rspamd_worker_bind_conf));
- cnf->bind_port = DEFAULT_BIND_PORT;
- cnf->bind_host = rspamd_mempool_strdup (cfg->cfg_pool, str);
- cnf->ai = AF_UNSPEC;
-
- if (*tokens[0] == '/' || *tokens[0] == '.') {
- cnf->ai = AF_UNIX;
- LL_PREPEND (cf->bind_conf, cnf);
- }
- else if (strcmp (tokens[0], "*") == 0) {
- /* We need to add two listen entries: one for ipv4 and one for ipv6 */
- tmp = tokens[0];
- tokens[0] = "*v4";
- cnf->ai = AF_INET;
- if ((ret = parse_host_port_priority_strv (cfg->cfg_pool, tokens,
- &cnf->bind_host, &cnf->bind_port, NULL, DEFAULT_BIND_PORT))) {
- LL_PREPEND (cf->bind_conf, cnf);
- }
- cnf =
- rspamd_mempool_alloc0 (cfg->cfg_pool,
- sizeof (struct rspamd_worker_bind_conf));
- cnf->bind_port = DEFAULT_BIND_PORT;
- cnf->bind_host = rspamd_mempool_strdup (cfg->cfg_pool, str);
- cnf->ai = AF_INET6;
- tokens[0] = "*v6";
- if ((rc = parse_host_port_priority_strv (cfg->cfg_pool, tokens,
- &cnf->bind_host, &cnf->bind_port, NULL, DEFAULT_BIND_PORT))) {
- LL_PREPEND (cf->bind_conf, cnf);
- }
- tokens[0] = tmp;
- }
- else if (strcmp (tokens[0], "systemd") == 0) {
+
+ cnf->cnt = 1024;
+ if (strcmp (tokens[0], "systemd") == 0) {
/* The actual socket will be passed by systemd environment */
- cnf->bind_host = rspamd_mempool_strdup (cfg->cfg_pool, str);
- cnf->ai = strtoul (tokens[1], &err, 10);
cnf->is_systemd = TRUE;
+ cnf->cnt = strtoul (tokens[1], &err, 10);
+ cnf->addrs = NULL;
if (err == NULL || *err == '\0') {
LL_PREPEND (cf->bind_conf, cnf);
}
else {
+ msg_err ("cannot parse bind line: %s", str);
ret = FALSE;
}
}
else {
- cnf->bind_host = rspamd_mempool_strdup (cfg->cfg_pool, tokens[0]);
- if (tokens[1] == NULL) {
- cnf->bind_port = DEFAULT_BIND_PORT;
- err = NULL;
+ if (!rspamd_parse_host_port_priority_strv (tokens, &cnf->addrs,
+ &cnf->cnt, NULL, &cnf->name, DEFAULT_BIND_PORT, cfg->cfg_pool)) {
+ msg_err ("cannot parse bind line: %s", str);
+ ret = FALSE;
}
else {
- cnf->bind_port = strtoul (tokens[1], &err, 10);
- }
- if (err == NULL || *err == '\0') {
LL_PREPEND (cf->bind_conf, cnf);
}
- else {
- ret = FALSE;
- }
}
g_strfreev (tokens);
diff --git a/src/libutil/addr.c b/src/libutil/addr.c
index 3f5dd8e0e..1257fb98f 100644
--- a/src/libutil/addr.c
+++ b/src/libutil/addr.c
@@ -192,6 +192,46 @@ rspamd_inet_address_connect (rspamd_inet_addr_t *addr, gint type,
return fd;
}
+int
+rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
+ gboolean async)
+{
+ gint fd, r;
+ gint on = 1;
+
+ if (addr == NULL) {
+ return -1;
+ }
+
+ fd = rspamd_socket_create (addr->af, type, 0, async);
+ if (fd == -1) {
+ return -1;
+ }
+
+ setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof (gint));
+ r = bind (fd, &addr->addr.sa, addr->slen);
+ if (r == -1) {
+ if (!async || errno != EINPROGRESS) {
+ close (fd);
+ msg_warn ("bind failed: %d, '%s'", errno,
+ strerror (errno));
+ return -1;
+ }
+ }
+
+ if (type != SOCK_DGRAM) {
+ r = listen (fd, -1);
+
+ if (r == -1) {
+ msg_warn ("listen failed: %d, '%s'", errno, strerror (errno));
+ close (fd);
+ return -1;
+ }
+ }
+
+ return fd;
+}
+
gboolean
rspamd_parse_host_port_priority_strv (gchar **tokens,
rspamd_inet_addr_t **addr,
@@ -216,19 +256,12 @@ rspamd_parse_host_port_priority_strv (gchar **tokens,
cur_tok = tokens[0];
- if (strcmp (cur_tok, "*v6") == 0) {
- hints.ai_family = AF_INET6;
+ if (strcmp (cur_tok, "*") == 0) {
hints.ai_flags |= AI_PASSIVE;
cur_tok = NULL;
}
- else if (strcmp (cur_tok, "*v4") == 0) {
- hints.ai_family = AF_INET;
- hints.ai_flags |= AI_PASSIVE;
- cur_tok = NULL;
- }
- else {
- hints.ai_family = AF_UNSPEC;
- }
+
+ hints.ai_family = AF_UNSPEC;
if (tokens[1] != NULL) {
/* Port part */
diff --git a/src/libutil/addr.h b/src/libutil/addr.h
index 16fe58a8d..c907d80c2 100644
--- a/src/libutil/addr.h
+++ b/src/libutil/addr.h
@@ -81,6 +81,15 @@ int rspamd_inet_address_connect (rspamd_inet_addr_t *addr, gint type,
gboolean async);
/**
+ * Listen on a specified inet address
+ * @param addr
+ * @param type
+ * @param async
+ * @return
+ */
+int rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
+ gboolean async);
+/**
* Check whether specified ip is valid (not INADDR_ANY or INADDR_NONE) for ipv4 or ipv6
* @param ptr pointer to struct in_addr or struct in6_addr
* @param af address family (AF_INET or AF_INET6)
diff --git a/src/main.c b/src/main.c
index d4bd66b78..e5e2112c6 100644
--- a/src/main.c
+++ b/src/main.c
@@ -561,27 +561,17 @@ delay_fork (struct rspamd_worker_conf *cf)
}
static GList *
-create_listen_socket (const gchar *addr, gint port, gint listen_type)
+create_listen_socket (rspamd_inet_addr_t *addrs, guint cnt, gint listen_type)
{
- gint listen_sock = -1;
- GList *result, *cur;
- /* Create listen sockets */
- result = make_universal_sockets_list (addr,
- port,
- listen_type,
- TRUE,
- TRUE,
- TRUE);
-
- cur = result;
- while (cur != NULL) {
- listen_sock = GPOINTER_TO_INT (cur->data);
- if (listen_sock != -1 && listen_type != SOCK_DGRAM) {
- if (listen (listen_sock, -1) == -1) {
- msg_err ("cannot listen on socket. %s", strerror (errno));
- }
+ GList *result = NULL;
+ gint fd;
+ guint i;
+
+ for (i = 0; i < cnt; i ++) {
+ fd = rspamd_inet_address_listen (&addrs[i], listen_type, TRUE);
+ if (fd != -1) {
+ result = g_list_prepend (result, GINT_TO_POINTER (fd));
}
- cur = g_list_next (cur);
}
return result;
@@ -645,14 +635,22 @@ fork_delayed (struct rspamd_main *rspamd)
}
static inline uintptr_t
-make_listen_key (gint ai, const gchar *addr, gint port)
+make_listen_key (struct rspamd_worker_bind_conf *cf)
{
gpointer xxh;
+ guint i;
- xxh = XXH32_init (0xbeef);
- XXH32_update (xxh, addr, strlen (addr));
- XXH32_update (xxh, (guchar *)&ai, sizeof (gint));
- XXH32_update (xxh, (guchar *)&port, sizeof (gint));
+ xxh = XXH32_init (0xdeadbeef);
+ if (cf->is_systemd) {
+ XXH32_update (xxh, "systemd", sizeof ("systemd"));
+ XXH32_update (xxh, &cf->cnt, sizeof (cf->cnt));
+ }
+ else {
+ XXH32_update (xxh, cf->name, strlen (cf->name));
+ for (i = 0; i < cf->cnt; i ++) {
+ XXH32_update (xxh, &cf->addrs[i].addr, cf->addrs[i].slen);
+ }
+ }
return XXH32_digest (xxh);
}
@@ -662,8 +660,9 @@ spawn_workers (struct rspamd_main *rspamd)
{
GList *cur, *ls;
struct rspamd_worker_conf *cf;
- gint i, key;
+ gint i;
gpointer p;
+ guintptr key;
struct rspamd_worker_bind_conf *bcf;
cur = rspamd->cfg->workers;
@@ -678,29 +677,25 @@ spawn_workers (struct rspamd_main *rspamd)
if (cf->worker->has_socket) {
LL_FOREACH (cf->bind_conf, bcf)
{
- key = make_listen_key (bcf->ai,
- bcf->bind_host,
- bcf->bind_port);
+ key = make_listen_key (bcf);
if ((p =
g_hash_table_lookup (listen_sockets,
GINT_TO_POINTER (key))) == NULL) {
if (!bcf->is_systemd) {
/* Create listen socket */
- ls = create_listen_socket (bcf->bind_host,
- bcf->bind_port,
+ ls = create_listen_socket (bcf->addrs, bcf->cnt,
cf->worker->listen_type);
}
else {
- ls = systemd_get_socket (bcf->ai);
+ ls = systemd_get_socket (bcf->cnt);
}
if (ls == NULL) {
msg_err ("cannot listen on socket %s: %s",
- bcf->bind_host,
+ bcf->name,
strerror (errno));
exit (-errno);
}
- g_hash_table_insert (listen_sockets,
- GINT_TO_POINTER (key), ls);
+ g_hash_table_insert (listen_sockets, (gpointer)key, ls);
}
else {
/* We had socket for this type of worker */