diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2014-10-29 12:18:13 +0000 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2014-10-29 12:18:13 +0000 |
commit | 8c9cf87f25a81677b52ed1a309fea505d1c2174f (patch) | |
tree | a5a2de658bc8611452baf8dd76c00dba31e43ac5 | |
parent | f58fb61175aa8616b307ec29e919f5556d42777d (diff) | |
download | rspamd-8c9cf87f25a81677b52ed1a309fea505d1c2174f.tar.gz rspamd-8c9cf87f25a81677b52ed1a309fea505d1c2174f.zip |
Rework and simplify listen sockets creation.
-rw-r--r-- | src/libserver/cfg_file.h | 6 | ||||
-rw-r--r-- | src/libserver/cfg_utils.c | 57 | ||||
-rw-r--r-- | src/libutil/addr.c | 53 | ||||
-rw-r--r-- | src/libutil/addr.h | 9 | ||||
-rw-r--r-- | src/main.c | 63 |
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 */ |