diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2015-03-12 14:17:14 +0000 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2015-03-12 14:17:14 +0000 |
commit | a943f89d45c1ee9073d894aee7d28077187120b7 (patch) | |
tree | 534b1f25b8dec5b93237792352dd0628d4f76b63 | |
parent | e80283ac81f3677ed70f084275f157781d0ebba1 (diff) | |
download | rspamd-a943f89d45c1ee9073d894aee7d28077187120b7.tar.gz rspamd-a943f89d45c1ee9073d894aee7d28077187120b7.zip |
Rework inet_address structure.
- 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.
-rw-r--r-- | src/libutil/addr.c | 471 | ||||
-rw-r--r-- | src/libutil/addr.h | 100 |
2 files changed, 444 insertions, 127 deletions
diff --git a/src/libutil/addr.c b/src/libutil/addr.c index 3c4db3c8f..6877ce87c 100644 --- a/src/libutil/addr.c +++ b/src/libutil/addr.c @@ -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; +} + diff --git a/src/libutil/addr.h b/src/libutil/addr.h index b5282e34c..d3778f6a7 100644 --- a/src/libutil/addr.h +++ b/src/libutil/addr.h @@ -27,25 +27,26 @@ #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_ */ |