]> source.dussan.org Git - rspamd.git/commitdiff
Rework inet_address structure.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 12 Mar 2015 14:17:14 +0000 (14:17 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 12 Mar 2015 14:17:14 +0000 (14:17 +0000)
- Now addresses are opaque.
- Save memory by splitting unix and inet sockaddrs.
- Rework all functions related to inet addrs.
- Use ptr arrays instead of home-made static arrays.

src/libutil/addr.c
src/libutil/addr.h

index 3c4db3c8f9c1645adbee243b5eb192f6c0534ad1..6877ce87cf30615cfa78882ee80917b5db2b9a77 100644 (file)
@@ -32,25 +32,100 @@ enum {
        RSPAMD_IPV6_UNSUPPORTED
 } ipv6_status = RSPAMD_IPV6_UNDEFINED;
 
+/**
+ * Union that is used for storing sockaddrs
+ */
+union sa_union {
+       struct sockaddr sa;
+       struct sockaddr_in s4;
+       struct sockaddr_in6 s6;
+       struct sockaddr_un su;
+       struct sockaddr_storage ss;
+};
+
+union sa_inet {
+       struct sockaddr sa;
+       struct sockaddr_in s4;
+       struct sockaddr_in6 s6;
+};
+
+struct rspamd_addr_unix {
+       struct sockaddr_un addr;
+       gint mode;
+       uid_t owner;
+       gid_t group;
+};
+
+struct rspamd_addr_inet {
+       union sa_inet addr;
+};
+
+struct rspamd_inet_addr_s {
+       union {
+               struct rspamd_addr_inet in;
+               struct rspamd_addr_unix *un;
+       } u;
+       gint af;
+       socklen_t slen;
+};
 
 static void
 rspamd_ip_validate_af (rspamd_inet_addr_t *addr)
 {
-       if (addr->addr.sa.sa_family != addr->af) {
-               addr->addr.sa.sa_family = addr->af;
+       if (addr->af != AF_UNIX) {
+               if (addr->u.in.addr.sa.sa_family != addr->af) {
+                       addr->u.in.addr.sa.sa_family = addr->af;
+               }
        }
+
        if (addr->af == AF_INET) {
-               addr->slen = sizeof (addr->addr.s4);
+               addr->slen = sizeof (struct sockaddr_in);
        }
        else if (addr->af == AF_INET6) {
-               addr->slen = sizeof (addr->addr.s6);
+               addr->slen = sizeof (struct sockaddr_in6);
        }
        else if (addr->af == AF_UNIX) {
 #ifdef SUN_LEN
-               addr->slen = SUN_LEN (&addr->addr.su);
+               addr->slen = SUN_LEN (&addr->u.un->addr);
 #else
-               addr->slen = sizeof (addr->addr.su);
+               addr->slen = sizeof (addr->u.un->addr);
 #endif
+#if defined(FREEBSD) || defined(__APPLE__)
+               addr->u.un->addr.sun_len = addr->slen;
+#endif
+       }
+}
+
+
+static rspamd_inet_addr_t *
+rspamd_inet_addr_create (gint af)
+{
+       rspamd_inet_addr_t *addr;
+
+       addr = g_slice_alloc (sizeof (rspamd_inet_addr_t));
+
+       if (af == AF_UNIX) {
+               addr->u.un = g_slice_alloc (sizeof (*addr->u.un));
+               addr->slen = sizeof (addr->u.un->addr);
+       }
+
+       addr->af = af;
+
+       rspamd_ip_validate_af (addr);
+
+       return addr;
+}
+
+void
+rspamd_inet_address_destroy (rspamd_inet_addr_t *addr)
+{
+       if (addr) {
+               if (addr->af == AF_UNIX) {
+                       if (addr->u.un) {
+                               g_slice_free1 (sizeof (*addr->u.un), addr->u.un);
+                       }
+               }
+               g_slice_free1 (sizeof (rspamd_inet_addr_t), addr);
        }
 }
 
@@ -90,22 +165,22 @@ rspamd_ip_check_ipv6 (void)
 }
 
 gboolean
-rspamd_ip_is_valid (rspamd_inet_addr_t *addr)
+rspamd_ip_is_valid (const rspamd_inet_addr_t *addr)
 {
        const struct in_addr ip4_any = { INADDR_ANY }, ip4_none = { INADDR_NONE };
        const struct in6_addr ip6_any = IN6ADDR_ANY_INIT;
        gboolean ret = FALSE;
 
        if (G_LIKELY (addr->af == AF_INET)) {
-               if (memcmp (&addr->addr.s4.sin_addr, &ip4_any,
+               if (memcmp (&addr->u.in.addr.s4.sin_addr, &ip4_any,
                        sizeof (struct in_addr)) != 0 &&
-                       memcmp (&addr->addr.s4.sin_addr, &ip4_none,
+                       memcmp (&addr->u.in.addr.s4.sin_addr, &ip4_none,
                        sizeof (struct in_addr)) != 0) {
                        ret = TRUE;
                }
        }
        else if (G_UNLIKELY (addr->af == AF_INET6)) {
-               if (memcmp (&addr->addr.s6.sin6_addr, &ip6_any,
+               if (memcmp (&addr->u.in.addr.s6.sin6_addr, &ip6_any,
                        sizeof (struct in6_addr)) != 0) {
                        ret = TRUE;
                }
@@ -115,20 +190,34 @@ rspamd_ip_is_valid (rspamd_inet_addr_t *addr)
 }
 
 gint
-rspamd_accept_from_socket (gint sock, rspamd_inet_addr_t *addr)
+rspamd_accept_from_socket (gint sock, rspamd_inet_addr_t **target)
 {
        gint nfd, serrno;
-       socklen_t len = sizeof (addr->addr.ss);
+       union sa_union su;
+       socklen_t len = sizeof (su);
+       rspamd_inet_addr_t *addr = NULL;
+
+       if ((nfd = accept (sock, &su.sa, &len)) == -1) {
+               if (target) {
+                       *target = NULL;
+               }
 
-       if ((nfd = accept (sock, &addr->addr.sa, &len)) == -1) {
                if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
                        return 0;
                }
                return -1;
        }
 
+       addr = rspamd_inet_addr_create (su.sa.sa_family);
        addr->slen = len;
-       addr->af = addr->addr.sa.sa_family;
+
+       if (addr->af == AF_UNIX) {
+               addr->u.un = g_slice_alloc (sizeof (*addr->u.un));
+               memcpy (&addr->u.un->addr, &su.su, sizeof (struct sockaddr_un));
+       }
+       else {
+               memcpy (&addr->u.in.addr, &su, MIN (len, sizeof (addr->u.in.addr)));
+       }
 
        if (rspamd_socket_nonblocking (nfd) < 0) {
                goto out;
@@ -140,37 +229,48 @@ rspamd_accept_from_socket (gint sock, rspamd_inet_addr_t *addr)
                goto out;
        }
 
+       if (target) {
+               *target = addr;
+       }
+       else {
+               /* Avoid leak */
+               rspamd_inet_address_destroy (addr);
+       }
+
        return (nfd);
 
 out:
        serrno = errno;
        close (nfd);
        errno = serrno;
+       rspamd_inet_address_destroy (addr);
+
        return (-1);
 
 }
 
 static gboolean
-rspamd_parse_unix_path (rspamd_inet_addr_t *target, const char *src)
+rspamd_parse_unix_path (rspamd_inet_addr_t **target, const char *src)
 {
        gchar **tokens, **cur_tok, *p, *pwbuf;
        gint pwlen;
        struct passwd pw, *ppw;
        struct group gr, *pgr;
+       rspamd_inet_addr_t *addr;
 
        tokens = g_strsplit_set (src, " ", -1);
 
-       target->af = AF_UNIX;
-       target->slen = sizeof (target->addr.su);
-       rspamd_strlcpy (target->addr.su.sun_path, tokens[0],
-                       sizeof (target->addr.su.sun_path));
-       #ifdef FREEBSD
-       target->addr.su.sun_len = SUN_LEN (&target->addr.su);
+       addr = rspamd_inet_addr_create (AF_UNIX);
+
+       rspamd_strlcpy (addr->u.un->addr.sun_path, tokens[0],
+                       sizeof (addr->u.un->addr.sun_path));
+       #if defined(FREEBSD) || defined(__APPLE__)
+       addr->u.un->addr.sun_len = SUN_LEN (&addr->u.un->addr);
        #endif
 
-       target->mode = 00644;
-       target->owner = 0;
-       target->group = 0;
+       addr->u.un->mode = 00644;
+       addr->u.un->mode = 0;
+       addr->u.un->group = 0;
 
        cur_tok = &tokens[1];
        pwlen = sysconf (_SC_GETPW_R_SIZE_MAX);
@@ -181,12 +281,12 @@ rspamd_parse_unix_path (rspamd_inet_addr_t *target, const char *src)
                if (g_ascii_strncasecmp (*cur_tok, "mode=", sizeof ("mode=") - 1) == 0) {
                        p = strchr (*cur_tok, '=');
                        /* XXX: add error check */
-                       target->mode = strtoul (p + 1, NULL, 0);
+                       addr->u.un->mode = strtoul (p + 1, NULL, 0);
 
-                       if (target->mode == 0) {
+                       if (addr->u.un->mode == 0) {
                                msg_err ("bad mode: %s", p + 1);
                                errno = EINVAL;
-                               return FALSE;
+                               goto err;
                        }
                }
                else if (g_ascii_strncasecmp (*cur_tok, "owner=",
@@ -198,10 +298,10 @@ rspamd_parse_unix_path (rspamd_inet_addr_t *target, const char *src)
                                if (ppw == NULL) {
                                        errno = ENOENT;
                                }
-                               return FALSE;
+                               goto err;
                        }
-                       target->owner = pw.pw_uid;
-                       target->group = pw.pw_gid;
+                       addr->u.un->owner = pw.pw_uid;
+                       addr->u.un->group = pw.pw_gid;
                }
                else if (g_ascii_strncasecmp (*cur_tok, "group=",
                                sizeof ("group=") - 1) == 0) {
@@ -212,20 +312,37 @@ rspamd_parse_unix_path (rspamd_inet_addr_t *target, const char *src)
                                if (pgr == NULL) {
                                        errno = ENOENT;
                                }
-                               return FALSE;
+                               goto err;
                        }
-                       target->group = gr.gr_gid;
+                       addr->u.un->group = gr.gr_gid;
                }
                cur_tok ++;
        }
 
+       if (target) {
+               *target = addr;
+       }
+       else {
+               rspamd_inet_address_destroy (addr);
+       }
+
        return TRUE;
+
+err:
+
+       rspamd_inet_address_destroy (addr);
+       return FALSE;
 }
 
 gboolean
-rspamd_parse_inet_address (rspamd_inet_addr_t *target, const char *src)
+rspamd_parse_inet_address (rspamd_inet_addr_t **target, const char *src)
 {
        gboolean ret = FALSE;
+       rspamd_inet_addr_t *addr;
+       union sa_inet su;
+
+       g_assert (src != NULL);
+       g_assert (target != NULL);
 
        rspamd_ip_check_ipv6 ();
 
@@ -233,49 +350,49 @@ rspamd_parse_inet_address (rspamd_inet_addr_t *target, const char *src)
                return rspamd_parse_unix_path (target, src);
        }
        else if (ipv6_status == RSPAMD_IPV6_SUPPORTED &&
-                       inet_pton (AF_INET6, src, &target->addr.s6.sin6_addr) == 1) {
-               target->af = AF_INET6;
-               target->slen = sizeof (target->addr.s6);
+                       inet_pton (AF_INET6, src, &su.s6.sin6_addr) == 1) {
+               addr = rspamd_inet_addr_create (AF_INET6);
+               memcpy (&addr->u.in.addr.s6.sin6_addr, &su.s6.sin6_addr,
+                               sizeof (struct in6_addr));
                ret = TRUE;
        }
-       else if (inet_pton (AF_INET, src, &target->addr.s4.sin_addr) == 1) {
-               target->af = AF_INET;
-               target->slen = sizeof (target->addr.s4);
+       else if (inet_pton (AF_INET, src, &su.s4.sin_addr) == 1) {
+               addr = rspamd_inet_addr_create (AF_INET6);
+               memcpy (&addr->u.in.addr.s4.sin_addr, &su.s4.sin_addr,
+                               sizeof (struct in_addr));
                ret = TRUE;
        }
 
-       target->addr.sa.sa_family = target->af;
-
        return ret;
 }
 
 const char *
-rspamd_inet_address_to_string (rspamd_inet_addr_t *addr)
+rspamd_inet_address_to_string (const rspamd_inet_addr_t *addr)
 {
        static char addr_str[INET6_ADDRSTRLEN + 1];
 
        switch (addr->af) {
        case AF_INET:
-               return inet_ntop (addr->af, &addr->addr.s4.sin_addr, addr_str,
+               return inet_ntop (addr->af, &addr->u.in.addr.s4.sin_addr, addr_str,
                                   sizeof (addr_str));
        case AF_INET6:
-               return inet_ntop (addr->af, &addr->addr.s6.sin6_addr, addr_str,
+               return inet_ntop (addr->af, &addr->u.in.addr.s6.sin6_addr, addr_str,
                                   sizeof (addr_str));
        case AF_UNIX:
-               return addr->addr.su.sun_path;
+               return addr->u.un->addr.sun_path;
        }
 
        return "undefined";
 }
 
 uint16_t
-rspamd_inet_address_get_port (rspamd_inet_addr_t *addr)
+rspamd_inet_address_get_port (const rspamd_inet_addr_t *addr)
 {
        switch (addr->af) {
        case AF_INET:
-               return ntohs (addr->addr.s4.sin_port);
+               return ntohs (addr->u.in.addr.s4.sin_port);
        case AF_INET6:
-               return ntohs (addr->addr.s6.sin6_port);
+               return ntohs (addr->u.in.addr.s6.sin6_port);
        }
 
        return 0;
@@ -286,32 +403,38 @@ rspamd_inet_address_set_port (rspamd_inet_addr_t *addr, uint16_t port)
 {
        switch (addr->af) {
        case AF_INET:
-               addr->addr.s4.sin_port = htons (port);
+               addr->u.in.addr.s4.sin_port = htons (port);
                break;
        case AF_INET6:
-               addr->addr.s6.sin6_port = htons (port);
+               addr->u.in.addr.s6.sin6_port = htons (port);
                break;
        }
 }
 
 int
-rspamd_inet_address_connect (rspamd_inet_addr_t *addr, gint type,
+rspamd_inet_address_connect (const rspamd_inet_addr_t *addr, gint type,
                gboolean async)
 {
        int fd, r;
+       const struct sockaddr *sa;
 
        if (addr == NULL) {
                return -1;
        }
 
-       rspamd_ip_validate_af (addr);
-
        fd = rspamd_socket_create (addr->af, type, 0, async);
        if (fd == -1) {
                return -1;
        }
 
-       r = connect (fd, &addr->addr.sa, addr->slen);
+       if (addr->af == AF_UNIX) {
+               sa = (const struct sockaddr *)&addr->u.un->addr;
+       }
+       else {
+               sa = &addr->u.in.addr.sa;
+       }
+
+       r = connect (fd, sa, addr->slen);
 
        if (r == -1) {
                if (!async || errno != EINPROGRESS) {
@@ -326,29 +449,37 @@ rspamd_inet_address_connect (rspamd_inet_addr_t *addr, gint type,
 }
 
 int
-rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
+rspamd_inet_address_listen (const rspamd_inet_addr_t *addr, gint type,
                gboolean async)
 {
        gint fd, r;
        gint on = 1;
+       const struct sockaddr *sa;
+       const char *path;
 
        if (addr == NULL) {
                return -1;
        }
 
-       rspamd_ip_validate_af (addr);
        fd = rspamd_socket_create (addr->af, type, 0, async);
        if (fd == -1) {
                return -1;
        }
 
-       if (addr->af == AF_UNIX && access (addr->addr.su.sun_path, W_OK) != -1) {
+       if (addr->af == AF_UNIX && access (addr->u.un->addr.sun_path, W_OK) != -1) {
                /* Unlink old socket */
-               (void)unlink (addr->addr.su.sun_path);
+               (void)unlink (addr->u.un->addr.sun_path);
+       }
+
+       if (addr->af == AF_UNIX) {
+               sa = (const struct sockaddr *)&addr->u.un->addr;
+       }
+       else {
+               sa = &addr->u.in.addr.sa;
        }
 
        setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof (gint));
-       r = bind (fd, &addr->addr.sa, addr->slen);
+       r = bind (fd, sa, addr->slen);
        if (r == -1) {
                if (!async || errno != EINPROGRESS) {
                        close (fd);
@@ -361,15 +492,16 @@ rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
        if (type != SOCK_DGRAM) {
 
                if (addr->af == AF_UNIX) {
+                       path = addr->u.un->addr.sun_path;
                        /* Try to set mode and owner */
-                       if (chown (addr->addr.su.sun_path, addr->owner, addr->group) == -1) {
+                       if (chown (path, addr->u.un->owner, addr->u.un->group) == -1) {
                                msg_info ("cannot change owner for %s to %d:%d: %s",
-                                               addr->addr.su.sun_path, addr->owner, addr->group,
+                                               path, addr->u.un->owner, addr->u.un->group,
                                                strerror (errno));
                        }
-                       if (chmod (addr->addr.su.sun_path, addr->mode) == -1) {
+                       if (chmod (path, addr->u.un->mode) == -1) {
                                msg_info ("cannot change mode for %s to %od %s",
-                                               addr->addr.su.sun_path, addr->mode, strerror (errno));
+                                               path, addr->u.un->mode, strerror (errno));
                        }
                }
                r = listen (fd, -1);
@@ -384,10 +516,67 @@ rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
        return fd;
 }
 
+gssize
+rspamd_inet_address_recvfrom (gint fd, void *buf, gsize len, gint fl,
+               rspamd_inet_addr_t **target)
+{
+       gssize ret;
+       union sa_union su;
+       socklen_t slen = sizeof (su);
+       rspamd_inet_addr_t *addr = NULL;
+
+       if ((ret = recvfrom (fd, buf, len, fl, &su.sa, &slen)) == -1) {
+               if (target) {
+                       *target = NULL;
+               }
+
+               return -1;
+       }
+
+       if (target) {
+               addr = rspamd_inet_addr_create (su.sa.sa_family);
+               addr->slen = len;
+
+               if (addr->af == AF_UNIX) {
+                       addr->u.un = g_slice_alloc (sizeof (*addr->u.un));
+                       memcpy (&addr->u.un->addr, &su.su, sizeof (struct sockaddr_un));
+               }
+               else {
+                       memcpy (&addr->u.in.addr, &su, MIN (len, sizeof (addr->u.in.addr)));
+               }
+
+               *target = addr;
+       }
+
+       return (ret);
+}
+
+gssize
+rspamd_inet_address_sendto (gint fd, const void *buf, gsize len, gint fl,
+               const rspamd_inet_addr_t *addr)
+{
+       gssize r;
+       const struct sockaddr *sa;
+
+       if (addr == NULL) {
+               return -1;
+       }
+
+       if (addr->af == AF_UNIX) {
+               sa = (struct sockaddr *)&addr->u.un->addr;
+       }
+       else {
+               sa = &addr->u.in.addr.sa;
+       }
+
+       r = sendto (fd, buf, len, fl, sa, addr->slen);
+
+       return r;
+}
+
 gboolean
 rspamd_parse_host_port_priority_strv (gchar **tokens,
-       rspamd_inet_addr_t **addr,
-       guint *max_addrs,
+       GPtrArray **addrs,
        guint *priority,
        gchar **name,
        guint default_port,
@@ -476,34 +665,30 @@ rspamd_parse_host_port_priority_strv (gchar **tokens,
                        /* Now copy up to max_addrs of addresses */
                        addr_cnt = 0;
                        cur = res;
-                       while (cur && addr_cnt < *max_addrs) {
+                       while (cur) {
                                cur = cur->ai_next;
                                addr_cnt ++;
                        }
 
-                       if (pool == NULL) {
-                               *addr = g_new (rspamd_inet_addr_t, addr_cnt);
-                       }
-                       else {
-                               *addr = rspamd_mempool_alloc (pool, addr_cnt *
-                                               sizeof (rspamd_inet_addr_t));
+                       *addrs = g_ptr_array_new_full (addr_cnt,
+                                               (GDestroyNotify)rspamd_inet_address_destroy);
+
+                       if (pool != NULL) {
+                               rspamd_mempool_add_destructor (pool,
+                                               rspamd_ptr_array_free_hard, *addrs);
                        }
 
                        cur = res;
-                       addr_cnt = 0;
-                       while (cur && addr_cnt < *max_addrs) {
-                               cur_addr = &(*addr)[addr_cnt];
-                               memcpy (&cur_addr->addr, cur->ai_addr,
-                                               MIN (sizeof (cur_addr->addr), cur->ai_addrlen));
-                               cur_addr->af = cur->ai_family;
-                               rspamd_ip_validate_af (cur_addr);
-                               cur_addr->slen = cur->ai_addrlen;
+                       while (cur) {
+                               cur_addr = rspamd_inet_address_from_sa (cur->ai_addr,
+                                               cur->ai_addrlen);
+
+                               if (cur_addr != NULL) {
+                                       g_ptr_array_add (*addrs, cur_addr);
+                               }
                                cur = cur->ai_next;
-                               addr_cnt ++;
                        }
 
-                       *max_addrs = addr_cnt;
-
                        freeaddrinfo (res);
                }
                else {
@@ -515,21 +700,22 @@ rspamd_parse_host_port_priority_strv (gchar **tokens,
        }
        else {
                /* Special case of unix socket, as getaddrinfo cannot deal with them */
-               if (pool == NULL) {
-                       *addr = g_new0 (rspamd_inet_addr_t, 1);
-               }
-               else {
-                       *addr = rspamd_mempool_alloc0 (pool, sizeof (rspamd_inet_addr_t));
+               *addrs = g_ptr_array_new_full (1,
+                               (GDestroyNotify)rspamd_inet_address_destroy);
+
+               if (pool != NULL) {
+                       rspamd_mempool_add_destructor (pool,
+                                       rspamd_ptr_array_free_hard, *addrs);
                }
 
-               cur_addr = *addr;
-               if (!rspamd_parse_inet_address (cur_addr, tokens[0])) {
+               if (!rspamd_parse_inet_address (&cur_addr, tokens[0])) {
                        msg_err ("cannot parse unix socket definition %s: %s",
                                        tokens[0],
                                        strerror (errno));
                        goto err;
                }
-               *max_addrs = 1;
+
+               g_ptr_array_add (*addrs, cur_addr);
        }
 
        /* Restore errno */
@@ -552,8 +738,7 @@ err:
 gboolean
 rspamd_parse_host_port_priority (
        const gchar *str,
-       rspamd_inet_addr_t **addr,
-       guint *max_addrs,
+       GPtrArray **addrs,
        guint *priority,
        gchar **name,
        guint default_port,
@@ -567,7 +752,7 @@ rspamd_parse_host_port_priority (
                return FALSE;
        }
 
-       ret = rspamd_parse_host_port_priority_strv (tokens, addr, max_addrs,
+       ret = rspamd_parse_host_port_priority_strv (tokens, addrs,
                        priority, name, default_port, pool);
 
        g_strfreev (tokens);
@@ -577,12 +762,104 @@ rspamd_parse_host_port_priority (
 
 gboolean
 rspamd_parse_host_port (const gchar *str,
-       rspamd_inet_addr_t **addr,
-       guint *max_addrs,
+       GPtrArray **addrs,
        gchar **name,
        guint default_port,
        rspamd_mempool_t *pool)
 {
-       return rspamd_parse_host_port_priority (str, addr, max_addrs, NULL,
+       return rspamd_parse_host_port_priority (str, addrs, NULL,
                        name, default_port, pool);
 }
+
+
+guchar*
+rspamd_inet_address_get_radix_key (const rspamd_inet_addr_t *addr, guint *klen)
+{
+       guchar *res = NULL;
+       static struct in_addr local = {INADDR_LOOPBACK};
+
+       g_assert (addr != NULL);
+       g_assert (klen != NULL);
+
+       if (addr->af == AF_INET) {
+               *klen = sizeof (struct in_addr);
+               res = (guchar *)&addr->u.in.addr.s4.sin_addr;
+       }
+       else if (addr->af == AF_INET6) {
+               *klen = sizeof (struct in6_addr);
+               res = (guchar *)&addr->u.in.addr.s6.sin6_addr;
+       }
+       else if (addr->af == AF_UNIX) {
+               *klen = sizeof (struct in_addr);
+               res = (guchar *)&local;
+       }
+
+       return res;
+}
+
+
+rspamd_inet_addr_t *
+rspamd_inet_address_new (int af, const void *init)
+{
+       rspamd_inet_addr_t *addr;
+
+       addr = rspamd_inet_addr_create (af);
+
+       if (init != NULL) {
+               if (af == AF_UNIX) {
+                       /* Init is a path */
+                       rspamd_strlcpy (addr->u.un->addr.sun_path, init,
+                                       sizeof (addr->u.un->addr.sun_path));
+#if defined(FREEBSD) || defined(__APPLE__)
+                       addr->u.un->addr.sun_len = SUN_LEN (&addr->u.un->addr);
+#endif
+               }
+               else if (af == AF_INET) {
+                       memcpy (&addr->u.in.addr.s4.sin_addr, init, sizeof (struct in_addr));
+               }
+               else if (af == AF_INET6) {
+                       memcpy (&addr->u.in.addr.s6.sin6_addr, init, sizeof (struct in6_addr));
+               }
+       }
+
+       return addr;
+}
+
+rspamd_inet_addr_t *
+rspamd_inet_address_from_sa (const struct sockaddr *sa, socklen_t slen)
+{
+       rspamd_inet_addr_t *addr;
+
+       g_assert (sa != NULL);
+       g_assert (slen >= sizeof (struct sockaddr));
+
+       addr = rspamd_inet_addr_create (sa->sa_family);
+
+       if (sa->sa_family == AF_UNIX) {
+               /* Init is a path */
+               const struct sockaddr_un *un = (const struct sockaddr_un *)sa;
+
+               g_assert (slen >= SUN_LEN (un));
+
+               rspamd_strlcpy (addr->u.un->addr.sun_path, un->sun_path,
+                               sizeof (addr->u.un->addr.sun_path));
+#if defined(FREEBSD) || defined(__APPLE__)
+               addr->u.un->addr.sun_len = un->sun_len;
+#endif
+       }
+       else if (sa->sa_family == AF_INET) {
+               g_assert (slen >= sizeof (struct sockaddr_in));
+               memcpy (&addr->u.in.addr.s4, sa, sizeof (struct sockaddr_in));
+       }
+       else if (sa->sa_family == AF_INET6) {
+               g_assert (slen >= sizeof (struct sockaddr_in6));
+               memcpy (&addr->u.in.addr.s6, sa, sizeof (struct sockaddr_in6));
+       }
+       else {
+               /* XXX: currently we cannot deal with other AF */
+               g_assert (0);
+       }
+
+       return addr;
+}
+
index b5282e34c6835f66ecc187478be1069b9434cede..d3778f6a7286e4892f83d4bb85f305d33fb6d7dc 100644 (file)
 #include "mem_pool.h"
 
 /**
- * Union that is used for storing sockaddrs
- */
-union sa_union {
-       struct sockaddr_storage ss;
-       struct sockaddr sa;
-       struct sockaddr_in s4;
-       struct sockaddr_in6 s6;
-       struct sockaddr_un su;
-};
-
-typedef struct _rspamd_inet_addr_s {
-       union sa_union addr;
-       socklen_t slen;
-       gint af;
-       /* Unix socket specific */
-       gint mode;
-       uid_t owner;
-       gid_t group;
-} rspamd_inet_addr_t;
+ * Opaque structure
+ */
+typedef struct rspamd_inet_addr_s rspamd_inet_addr_t;
+
+/**
+ * Create new inet address structure based on the address familiy and opaque init pointer
+ * @param af
+ * @param init
+ * @return new inet addr
+ */
+rspamd_inet_addr_t * rspamd_inet_address_new (int af, const void *init);
+
+/**
+ * Create new inet address structure from struct sockaddr
+ * @param sa
+ * @param slen
+ * @return
+ */
+rspamd_inet_addr_t * rspamd_inet_address_from_sa (const struct sockaddr *sa,
+               socklen_t slen);
 
 /**
  * Try to parse address from string
@@ -53,7 +54,7 @@ typedef struct _rspamd_inet_addr_s {
  * @param src IP string representation
  * @return TRUE if addr has been parsed
  */
-gboolean rspamd_parse_inet_address (rspamd_inet_addr_t *target,
+gboolean rspamd_parse_inet_address (rspamd_inet_addr_t **target,
        const char *src);
 
 /**
@@ -61,14 +62,52 @@ gboolean rspamd_parse_inet_address (rspamd_inet_addr_t *target,
  * @param addr
  * @return statically allocated string pointer (not thread safe)
  */
-const char * rspamd_inet_address_to_string (rspamd_inet_addr_t *addr);
+const char * rspamd_inet_address_to_string (const rspamd_inet_addr_t *addr);
 
 /**
  * Returns port number for the specified inet address in host byte order
  * @param addr
  * @return
  */
-uint16_t rspamd_inet_address_get_port (rspamd_inet_addr_t *addr);
+uint16_t rspamd_inet_address_get_port (const rspamd_inet_addr_t *addr);
+
+/**
+ * Returns address family of inet address
+ * @param addr
+ * @return
+ */
+gint rspamd_inet_address_get_af (const rspamd_inet_addr_t *addr);
+
+
+/**
+ * Makes a radix key from inet address
+ * @param addr
+ * @param klen
+ * @return
+ */
+guchar * rspamd_inet_address_get_radix_key (const rspamd_inet_addr_t *addr, guint *klen);
+
+/**
+ * Receive data from an unconnected socket and fill the inet_addr structure if needed
+ * @param fd
+ * @param buf
+ * @param len
+ * @param target
+ * @return same as recvfrom(2)
+ */
+gssize rspamd_inet_address_recvfrom (gint fd, void *buf, gsize len, gint fl,
+               rspamd_inet_addr_t **target);
+
+/**
+ * Send data via unconnected socket using the specified inet_addr structure
+ * @param fd
+ * @param buf
+ * @param len
+ * @param target
+ * @return
+ */
+gssize rspamd_inet_address_sendto (gint fd, const void *buf, gsize len, gint fl,
+               const rspamd_inet_addr_t *addr);
 
 /**
  * Set port for inet address
@@ -81,7 +120,7 @@ void rspamd_inet_address_set_port (rspamd_inet_addr_t *addr, uint16_t port);
  * @param async perform operations asynchronously
  * @return newly created and connected socket
  */
-int rspamd_inet_address_connect (rspamd_inet_addr_t *addr, gint type,
+int rspamd_inet_address_connect (const rspamd_inet_addr_t *addr, gint type,
        gboolean async);
 
 /**
@@ -91,7 +130,7 @@ int rspamd_inet_address_connect (rspamd_inet_addr_t *addr, gint type,
  * @param async
  * @return
  */
-int rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
+int rspamd_inet_address_listen (const 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
@@ -99,18 +138,18 @@ int rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
  * @param af address family (AF_INET or AF_INET6)
  * @return TRUE if the address is valid
  */
-gboolean rspamd_ip_is_valid (rspamd_inet_addr_t *addr);
+gboolean rspamd_ip_is_valid (const rspamd_inet_addr_t *addr);
 
 /**
  * Accept from listening socket filling addr structure
  * @param sock listening socket
- * @param addr
+ * @param addr allocated inet addr structur
  * @return
  */
-gint rspamd_accept_from_socket (gint sock, rspamd_inet_addr_t *addr);
+gint rspamd_accept_from_socket (gint sock, rspamd_inet_addr_t **addr);
 
 gboolean rspamd_parse_host_port_priority_strv (gchar **tokens,
-       rspamd_inet_addr_t **addr, guint *max_addrs, guint *priority,
+       GPtrArray **addrs, guint *priority,
        gchar **name, guint default_port, rspamd_mempool_t *pool);
 
 /**
@@ -121,7 +160,7 @@ gboolean rspamd_parse_host_port_priority_strv (gchar **tokens,
  * @return TRUE if string was parsed
  */
 gboolean rspamd_parse_host_port_priority (const gchar *str,
-               rspamd_inet_addr_t **addr, guint *max_addrs,
+               GPtrArray **addrs,
                guint *priority, gchar **name, guint default_port,
                rspamd_mempool_t *pool);
 
@@ -132,8 +171,9 @@ gboolean rspamd_parse_host_port_priority (const gchar *str,
  * @return TRUE if string was parsed
  */
 gboolean rspamd_parse_host_port (const gchar *str,
-       rspamd_inet_addr_t **addr, guint *max_addrs,
+               GPtrArray **addrs,
        gchar **name, guint default_port, rspamd_mempool_t *pool);
 
+void rspamd_inet_address_destroy (rspamd_inet_addr_t *addr);
 
 #endif /* ADDR_H_ */