xref: /unit/src/nxt_sockaddr.c (revision 2141:c820888cd98c)
10Sigor@sysoev.ru 
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
40Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
50Sigor@sysoev.ru  */
60Sigor@sysoev.ru 
70Sigor@sysoev.ru #include <nxt_main.h>
80Sigor@sysoev.ru 
90Sigor@sysoev.ru 
100Sigor@sysoev.ru #if (NXT_INET6)
110Sigor@sysoev.ru static u_char *nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end);
120Sigor@sysoev.ru #endif
130Sigor@sysoev.ru 
1499Sigor@sysoev.ru static nxt_sockaddr_t *nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr);
1599Sigor@sysoev.ru static nxt_sockaddr_t *nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr);
1699Sigor@sysoev.ru static nxt_sockaddr_t *nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr);
1799Sigor@sysoev.ru 
180Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs);
190Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs);
200Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs);
210Sigor@sysoev.ru 
220Sigor@sysoev.ru 
230Sigor@sysoev.ru nxt_sockaddr_t *
nxt_sockaddr_cache_alloc(nxt_event_engine_t * engine,nxt_listen_socket_t * ls)24358Sigor@sysoev.ru nxt_sockaddr_cache_alloc(nxt_event_engine_t *engine, nxt_listen_socket_t *ls)
25337Sigor@sysoev.ru {
261266Sigor@sysoev.ru     size_t          size;
27358Sigor@sysoev.ru     uint8_t         hint;
28358Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
29337Sigor@sysoev.ru 
301266Sigor@sysoev.ru     hint = NXT_EVENT_ENGINE_NO_MEM_HINT;
31337Sigor@sysoev.ru     size = offsetof(nxt_sockaddr_t, u) + ls->socklen + ls->address_length;
32337Sigor@sysoev.ru 
33358Sigor@sysoev.ru     sa = nxt_event_engine_mem_alloc(engine, &hint, size);
34337Sigor@sysoev.ru 
35337Sigor@sysoev.ru     if (nxt_fast_path(sa != NULL)) {
36337Sigor@sysoev.ru         /* Zero only beginning of structure up to sockaddr_un.sun_path[1]. */
37337Sigor@sysoev.ru         nxt_memzero(sa, offsetof(nxt_sockaddr_t, u.sockaddr.sa_data[1]));
38337Sigor@sysoev.ru 
39358Sigor@sysoev.ru         sa->cache_hint = hint;
40337Sigor@sysoev.ru         sa->socklen = ls->socklen;
41337Sigor@sysoev.ru         sa->length = ls->address_length;
42337Sigor@sysoev.ru 
43337Sigor@sysoev.ru         sa->type = ls->sockaddr->type;
44337Sigor@sysoev.ru         /*
45337Sigor@sysoev.ru          * Set address family for unspecified Unix domain socket,
46337Sigor@sysoev.ru          * because these sockaddr's are not updated by old BSD systems,
47337Sigor@sysoev.ru          * see comment in nxt_conn_io_accept().
48337Sigor@sysoev.ru          */
49337Sigor@sysoev.ru         sa->u.sockaddr.sa_family = ls->sockaddr->u.sockaddr.sa_family;
50337Sigor@sysoev.ru     }
51337Sigor@sysoev.ru 
52337Sigor@sysoev.ru     return sa;
53337Sigor@sysoev.ru }
54337Sigor@sysoev.ru 
55337Sigor@sysoev.ru 
56337Sigor@sysoev.ru void
nxt_sockaddr_cache_free(nxt_event_engine_t * engine,nxt_conn_t * c)57337Sigor@sysoev.ru nxt_sockaddr_cache_free(nxt_event_engine_t *engine, nxt_conn_t *c)
58337Sigor@sysoev.ru {
591266Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
601266Sigor@sysoev.ru 
611266Sigor@sysoev.ru     sa = c->remote;
621266Sigor@sysoev.ru 
631266Sigor@sysoev.ru     nxt_event_engine_mem_free(engine, sa->cache_hint, sa, 0);
64337Sigor@sysoev.ru }
65337Sigor@sysoev.ru 
66337Sigor@sysoev.ru 
67337Sigor@sysoev.ru nxt_sockaddr_t *
nxt_sockaddr_alloc(nxt_mp_t * mp,socklen_t socklen,size_t address_length)6865Sigor@sysoev.ru nxt_sockaddr_alloc(nxt_mp_t *mp, socklen_t socklen, size_t address_length)
690Sigor@sysoev.ru {
7013Sigor@sysoev.ru     size_t          size;
710Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
720Sigor@sysoev.ru 
7313Sigor@sysoev.ru     size = offsetof(nxt_sockaddr_t, u) + socklen + address_length;
7413Sigor@sysoev.ru 
750Sigor@sysoev.ru     /*
760Sigor@sysoev.ru      * The current struct sockaddr's define 32-bit fields at maximum
770Sigor@sysoev.ru      * and may define 64-bit AF_INET6 fields in the future.  Alignment
7865Sigor@sysoev.ru      * of memory allocated by nxt_mp_zalloc() is enough for these fields.
790Sigor@sysoev.ru      * If 128-bit alignment will be required then nxt_mem_malloc() and
800Sigor@sysoev.ru      * nxt_memzero() should be used instead.
810Sigor@sysoev.ru      */
8213Sigor@sysoev.ru 
8365Sigor@sysoev.ru     sa = nxt_mp_zalloc(mp, size);
840Sigor@sysoev.ru 
850Sigor@sysoev.ru     if (nxt_fast_path(sa != NULL)) {
8613Sigor@sysoev.ru         sa->socklen = socklen;
8713Sigor@sysoev.ru         sa->length = address_length;
880Sigor@sysoev.ru     }
890Sigor@sysoev.ru 
900Sigor@sysoev.ru     return sa;
910Sigor@sysoev.ru }
920Sigor@sysoev.ru 
930Sigor@sysoev.ru 
940Sigor@sysoev.ru nxt_sockaddr_t *
nxt_sockaddr_create(nxt_mp_t * mp,struct sockaddr * sockaddr,socklen_t length,size_t address_length)9565Sigor@sysoev.ru nxt_sockaddr_create(nxt_mp_t *mp, struct sockaddr *sockaddr, socklen_t length,
9665Sigor@sysoev.ru     size_t address_length)
970Sigor@sysoev.ru {
980Sigor@sysoev.ru     size_t          size, copy;
990Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
1000Sigor@sysoev.ru 
10110Sigor@sysoev.ru     size = length;
10210Sigor@sysoev.ru     copy = length;
1030Sigor@sysoev.ru 
1040Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
1050Sigor@sysoev.ru 
1060Sigor@sysoev.ru     /*
1070Sigor@sysoev.ru      * Unspecified Unix domain sockaddr_un form and length are very
108211Sru@nginx.com      * platform depended (see comment in nxt_socket.h).  Here they are
1090Sigor@sysoev.ru      * normalized to the sockaddr_un with single zero byte sun_path[].
1100Sigor@sysoev.ru      */
1110Sigor@sysoev.ru 
1120Sigor@sysoev.ru     if (size <= offsetof(struct sockaddr_un, sun_path)) {
1130Sigor@sysoev.ru         /*
1140Sigor@sysoev.ru          * Small socket length means a short unspecified Unix domain
1150Sigor@sysoev.ru          * socket address:
1160Sigor@sysoev.ru          *
1170Sigor@sysoev.ru          *   getsockname() and getpeername() on OpenBSD prior to 5.3
1180Sigor@sysoev.ru          *   return zero length and does not update a passed sockaddr
1190Sigor@sysoev.ru          *   buffer at all.
1200Sigor@sysoev.ru          *
1210Sigor@sysoev.ru          *   Linux returns length equal to 2, i.e. sockaddr_un without
1220Sigor@sysoev.ru          *   sun_path[], unix(7):
1230Sigor@sysoev.ru          *
1240Sigor@sysoev.ru          *     unnamed: A stream socket that has not been bound
1250Sigor@sysoev.ru          *     to a pathname using bind(2) has no name.  Likewise,
1260Sigor@sysoev.ru          *     the two sockets created by socketpair(2) are unnamed.
1270Sigor@sysoev.ru          *     When the address of an unnamed socket is returned by
1280Sigor@sysoev.ru          *     getsockname(2), getpeername(2), and accept(2), its
1290Sigor@sysoev.ru          *     length is sizeof(sa_family_t), and sun_path should
1300Sigor@sysoev.ru          *     not be inspected.
1310Sigor@sysoev.ru          */
1320Sigor@sysoev.ru         size = offsetof(struct sockaddr_un, sun_path) + 1;
1330Sigor@sysoev.ru 
1340Sigor@sysoev.ru #if !(NXT_LINUX)
1350Sigor@sysoev.ru 
1360Sigor@sysoev.ru     } else if (sockaddr->sa_family == AF_UNIX && sockaddr->sa_data[0] == '\0') {
1370Sigor@sysoev.ru         /*
1380Sigor@sysoev.ru          * Omit nonsignificant zeros of the unspecified Unix domain socket
1390Sigor@sysoev.ru          * address.  This test is disabled for Linux since Linux abstract
1400Sigor@sysoev.ru          * socket address also starts with zero.  However Linux unspecified
1410Sigor@sysoev.ru          * Unix domain socket address is short and is handled above.
1420Sigor@sysoev.ru          */
1430Sigor@sysoev.ru         size = offsetof(struct sockaddr_un, sun_path) + 1;
1440Sigor@sysoev.ru         copy = size;
1450Sigor@sysoev.ru 
1460Sigor@sysoev.ru #endif
1470Sigor@sysoev.ru     }
1480Sigor@sysoev.ru 
1490Sigor@sysoev.ru #endif  /* NXT_HAVE_UNIX_DOMAIN */
1500Sigor@sysoev.ru 
15113Sigor@sysoev.ru     sa = nxt_sockaddr_alloc(mp, size, address_length);
1520Sigor@sysoev.ru 
1530Sigor@sysoev.ru     if (nxt_fast_path(sa != NULL)) {
1540Sigor@sysoev.ru         nxt_memcpy(&sa->u.sockaddr, sockaddr, copy);
1550Sigor@sysoev.ru 
1560Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN && NXT_OPENBSD)
1570Sigor@sysoev.ru 
15810Sigor@sysoev.ru         if (length == 0) {
1590Sigor@sysoev.ru             sa->u.sockaddr.sa_family = AF_UNIX;
1600Sigor@sysoev.ru         }
1610Sigor@sysoev.ru 
1620Sigor@sysoev.ru #endif
1630Sigor@sysoev.ru     }
1640Sigor@sysoev.ru 
1650Sigor@sysoev.ru     return sa;
1660Sigor@sysoev.ru }
1670Sigor@sysoev.ru 
1680Sigor@sysoev.ru 
1690Sigor@sysoev.ru nxt_sockaddr_t *
nxt_sockaddr_copy(nxt_mp_t * mp,nxt_sockaddr_t * src)17065Sigor@sysoev.ru nxt_sockaddr_copy(nxt_mp_t *mp, nxt_sockaddr_t *src)
1710Sigor@sysoev.ru {
17210Sigor@sysoev.ru     size_t          length;
1730Sigor@sysoev.ru     nxt_sockaddr_t  *dst;
1740Sigor@sysoev.ru 
17513Sigor@sysoev.ru     length = offsetof(nxt_sockaddr_t, u) + src->socklen;
1760Sigor@sysoev.ru 
17765Sigor@sysoev.ru     dst = nxt_mp_alloc(mp, length);
1780Sigor@sysoev.ru 
1790Sigor@sysoev.ru     if (nxt_fast_path(dst != NULL)) {
18010Sigor@sysoev.ru         nxt_memcpy(dst, src, length);
1810Sigor@sysoev.ru     }
1820Sigor@sysoev.ru 
1830Sigor@sysoev.ru     return dst;
1840Sigor@sysoev.ru }
1850Sigor@sysoev.ru 
1860Sigor@sysoev.ru 
1870Sigor@sysoev.ru nxt_sockaddr_t *
nxt_getsockname(nxt_task_t * task,nxt_mp_t * mp,nxt_socket_t s)18865Sigor@sysoev.ru nxt_getsockname(nxt_task_t *task, nxt_mp_t *mp, nxt_socket_t s)
1890Sigor@sysoev.ru {
1900Sigor@sysoev.ru     int                 ret;
19113Sigor@sysoev.ru     size_t              length;
1920Sigor@sysoev.ru     socklen_t           socklen;
1930Sigor@sysoev.ru     nxt_sockaddr_buf_t  sockaddr;
1940Sigor@sysoev.ru 
1950Sigor@sysoev.ru     socklen = NXT_SOCKADDR_LEN;
1960Sigor@sysoev.ru 
1970Sigor@sysoev.ru     ret = getsockname(s, &sockaddr.buf, &socklen);
1980Sigor@sysoev.ru 
1990Sigor@sysoev.ru     if (nxt_fast_path(ret == 0)) {
20013Sigor@sysoev.ru 
20113Sigor@sysoev.ru         switch (sockaddr.buf.sa_family) {
20213Sigor@sysoev.ru #if (NXT_INET6)
20313Sigor@sysoev.ru         case AF_INET6:
2041008Szelenkov@nginx.com             length = NXT_INET6_ADDR_STR_LEN;
2051008Szelenkov@nginx.com             break;
20613Sigor@sysoev.ru #endif
20713Sigor@sysoev.ru 
20813Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
20913Sigor@sysoev.ru         case AF_UNIX:
2101008Szelenkov@nginx.com             length = nxt_length("unix:") + socklen;
21113Sigor@sysoev.ru #endif
2121008Szelenkov@nginx.com             break;
21313Sigor@sysoev.ru 
21413Sigor@sysoev.ru         case AF_INET:
2151008Szelenkov@nginx.com             length = NXT_INET_ADDR_STR_LEN;
2161008Szelenkov@nginx.com             break;
21713Sigor@sysoev.ru 
21813Sigor@sysoev.ru         default:
2191008Szelenkov@nginx.com             length = 0;
2201008Szelenkov@nginx.com             break;
22113Sigor@sysoev.ru         }
22213Sigor@sysoev.ru 
22313Sigor@sysoev.ru         return nxt_sockaddr_create(mp, &sockaddr.buf, socklen, length);
2240Sigor@sysoev.ru     }
2250Sigor@sysoev.ru 
22613Sigor@sysoev.ru     nxt_log(task, NXT_LOG_ERR, "getsockname(%d) failed %E", s, nxt_errno);
2270Sigor@sysoev.ru 
2280Sigor@sysoev.ru     return NULL;
2290Sigor@sysoev.ru }
2300Sigor@sysoev.ru 
2310Sigor@sysoev.ru 
23213Sigor@sysoev.ru void
nxt_sockaddr_text(nxt_sockaddr_t * sa)23313Sigor@sysoev.ru nxt_sockaddr_text(nxt_sockaddr_t *sa)
2340Sigor@sysoev.ru {
23513Sigor@sysoev.ru     size_t    offset;
23613Sigor@sysoev.ru     u_char    *p, *start, *end, *octet;
23713Sigor@sysoev.ru     uint32_t  port;
23813Sigor@sysoev.ru 
239102Sigor@sysoev.ru     offset = offsetof(nxt_sockaddr_t, u) + sa->socklen;
240102Sigor@sysoev.ru     sa->start = offset;
241110Sigor@sysoev.ru     sa->port_start = offset;
242102Sigor@sysoev.ru 
243102Sigor@sysoev.ru     start = nxt_pointer_to(sa, offset);
244358Sigor@sysoev.ru     end = start + sa->length;
24513Sigor@sysoev.ru 
24613Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
24713Sigor@sysoev.ru 
24813Sigor@sysoev.ru     case AF_INET:
24913Sigor@sysoev.ru         sa->address_start = offset;
25013Sigor@sysoev.ru 
25113Sigor@sysoev.ru         octet = (u_char *) &sa->u.sockaddr_in.sin_addr;
25213Sigor@sysoev.ru 
25313Sigor@sysoev.ru         p = nxt_sprintf(start, end, "%ud.%ud.%ud.%ud",
25413Sigor@sysoev.ru                         octet[0], octet[1], octet[2], octet[3]);
25513Sigor@sysoev.ru 
25613Sigor@sysoev.ru         sa->address_length = p - start;
257110Sigor@sysoev.ru         sa->port_start += sa->address_length + 1;
2580Sigor@sysoev.ru 
25913Sigor@sysoev.ru         port = sa->u.sockaddr_in.sin_port;
26013Sigor@sysoev.ru 
26113Sigor@sysoev.ru         break;
26213Sigor@sysoev.ru 
26313Sigor@sysoev.ru #if (NXT_INET6)
26413Sigor@sysoev.ru 
26513Sigor@sysoev.ru     case AF_INET6:
266101Sigor@sysoev.ru         sa->address_start = offset + 1;
26713Sigor@sysoev.ru 
26813Sigor@sysoev.ru         p = start;
26913Sigor@sysoev.ru         *p++ = '[';
27013Sigor@sysoev.ru 
27113Sigor@sysoev.ru         p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end);
27213Sigor@sysoev.ru 
27313Sigor@sysoev.ru         sa->address_length = p - (start + 1);
274110Sigor@sysoev.ru         sa->port_start += sa->address_length + 3;
27520Sigor@sysoev.ru 
27613Sigor@sysoev.ru         *p++ = ']';
2770Sigor@sysoev.ru 
27813Sigor@sysoev.ru         port = sa->u.sockaddr_in6.sin6_port;
27913Sigor@sysoev.ru 
28013Sigor@sysoev.ru         break;
28113Sigor@sysoev.ru 
28213Sigor@sysoev.ru #endif
28313Sigor@sysoev.ru 
28413Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
28513Sigor@sysoev.ru 
28613Sigor@sysoev.ru     case AF_UNIX:
28713Sigor@sysoev.ru         sa->address_start = offset;
28813Sigor@sysoev.ru 
289100Sigor@sysoev.ru         p = (u_char *) sa->u.sockaddr_un.sun_path;
2900Sigor@sysoev.ru 
29113Sigor@sysoev.ru #if (NXT_LINUX)
29213Sigor@sysoev.ru 
29313Sigor@sysoev.ru         if (p[0] == '\0') {
294493Spluknet@nginx.com             size_t  length;
2950Sigor@sysoev.ru 
29613Sigor@sysoev.ru             /* Linux abstract socket address has no trailing zero. */
29713Sigor@sysoev.ru             length = sa->socklen - offsetof(struct sockaddr_un, sun_path);
29813Sigor@sysoev.ru 
29913Sigor@sysoev.ru             p = nxt_sprintf(start, end, "unix:@%*s", length - 1, p + 1);
30013Sigor@sysoev.ru 
30113Sigor@sysoev.ru         } else {
30213Sigor@sysoev.ru             p = nxt_sprintf(start, end, "unix:%s", p);
30313Sigor@sysoev.ru         }
30413Sigor@sysoev.ru 
30513Sigor@sysoev.ru #else  /* !(NXT_LINUX) */
30613Sigor@sysoev.ru 
30713Sigor@sysoev.ru         p = nxt_sprintf(start, end, "unix:%s", p);
3080Sigor@sysoev.ru 
30913Sigor@sysoev.ru #endif
31013Sigor@sysoev.ru 
31113Sigor@sysoev.ru         sa->address_length = p - start;
312110Sigor@sysoev.ru         sa->port_start += sa->address_length;
31313Sigor@sysoev.ru         sa->length = p - start;
31413Sigor@sysoev.ru 
31513Sigor@sysoev.ru         return;
31613Sigor@sysoev.ru 
31713Sigor@sysoev.ru #endif  /* NXT_HAVE_UNIX_DOMAIN */
31813Sigor@sysoev.ru 
31913Sigor@sysoev.ru     default:
32013Sigor@sysoev.ru         return;
3210Sigor@sysoev.ru     }
3220Sigor@sysoev.ru 
32313Sigor@sysoev.ru     p = nxt_sprintf(p, end, ":%d", ntohs(port));
32413Sigor@sysoev.ru 
32513Sigor@sysoev.ru     sa->length = p - start;
3260Sigor@sysoev.ru }
3270Sigor@sysoev.ru 
3280Sigor@sysoev.ru 
3290Sigor@sysoev.ru uint32_t
nxt_sockaddr_port_number(nxt_sockaddr_t * sa)33013Sigor@sysoev.ru nxt_sockaddr_port_number(nxt_sockaddr_t *sa)
3310Sigor@sysoev.ru {
3320Sigor@sysoev.ru     uint32_t  port;
3330Sigor@sysoev.ru 
3340Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
3350Sigor@sysoev.ru 
3360Sigor@sysoev.ru #if (NXT_INET6)
3370Sigor@sysoev.ru 
3380Sigor@sysoev.ru     case AF_INET6:
3390Sigor@sysoev.ru         port = sa->u.sockaddr_in6.sin6_port;
3400Sigor@sysoev.ru         break;
3410Sigor@sysoev.ru 
3420Sigor@sysoev.ru #endif
3430Sigor@sysoev.ru 
3440Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
3450Sigor@sysoev.ru 
3460Sigor@sysoev.ru     case AF_UNIX:
3470Sigor@sysoev.ru         return 0;
3480Sigor@sysoev.ru 
3490Sigor@sysoev.ru #endif
3500Sigor@sysoev.ru 
3510Sigor@sysoev.ru     default:
3520Sigor@sysoev.ru         port = sa->u.sockaddr_in.sin_port;
3530Sigor@sysoev.ru         break;
3540Sigor@sysoev.ru     }
3550Sigor@sysoev.ru 
3560Sigor@sysoev.ru     return ntohs((uint16_t) port);
3570Sigor@sysoev.ru }
3580Sigor@sysoev.ru 
3590Sigor@sysoev.ru 
3600Sigor@sysoev.ru nxt_bool_t
nxt_sockaddr_cmp(nxt_sockaddr_t * sa1,nxt_sockaddr_t * sa2)3610Sigor@sysoev.ru nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, nxt_sockaddr_t *sa2)
3620Sigor@sysoev.ru {
36313Sigor@sysoev.ru     if (sa1->socklen != sa2->socklen) {
3640Sigor@sysoev.ru         return 0;
3650Sigor@sysoev.ru     }
3660Sigor@sysoev.ru 
3670Sigor@sysoev.ru     if (sa1->type != sa2->type) {
3680Sigor@sysoev.ru         return 0;
3690Sigor@sysoev.ru     }
3700Sigor@sysoev.ru 
3710Sigor@sysoev.ru     if (sa1->u.sockaddr.sa_family != sa2->u.sockaddr.sa_family) {
3720Sigor@sysoev.ru         return 0;
3730Sigor@sysoev.ru     }
3740Sigor@sysoev.ru 
3750Sigor@sysoev.ru     /*
3760Sigor@sysoev.ru      * sockaddr struct's cannot be compared in whole since kernel
3770Sigor@sysoev.ru      * may fill some fields in inherited sockaddr struct's.
3780Sigor@sysoev.ru      */
3790Sigor@sysoev.ru 
3800Sigor@sysoev.ru     switch (sa1->u.sockaddr.sa_family) {
3810Sigor@sysoev.ru 
3820Sigor@sysoev.ru #if (NXT_INET6)
3830Sigor@sysoev.ru 
3840Sigor@sysoev.ru     case AF_INET6:
3850Sigor@sysoev.ru         if (sa1->u.sockaddr_in6.sin6_port != sa2->u.sockaddr_in6.sin6_port) {
3860Sigor@sysoev.ru             return 0;
3870Sigor@sysoev.ru         }
3880Sigor@sysoev.ru 
3890Sigor@sysoev.ru         if (nxt_memcmp(&sa1->u.sockaddr_in6.sin6_addr,
3900Sigor@sysoev.ru                        &sa2->u.sockaddr_in6.sin6_addr, 16)
3910Sigor@sysoev.ru             != 0)
3920Sigor@sysoev.ru         {
3930Sigor@sysoev.ru             return 0;
3940Sigor@sysoev.ru         }
3950Sigor@sysoev.ru 
3960Sigor@sysoev.ru         return 1;
3970Sigor@sysoev.ru 
3980Sigor@sysoev.ru #endif
3990Sigor@sysoev.ru 
4000Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
4010Sigor@sysoev.ru 
4020Sigor@sysoev.ru     case AF_UNIX:
4030Sigor@sysoev.ru         {
40410Sigor@sysoev.ru             size_t  length;
4050Sigor@sysoev.ru 
40613Sigor@sysoev.ru             length = sa1->socklen - offsetof(struct sockaddr_un, sun_path);
4070Sigor@sysoev.ru 
4080Sigor@sysoev.ru             if (nxt_memcmp(&sa1->u.sockaddr_un.sun_path,
40910Sigor@sysoev.ru                            &sa2->u.sockaddr_un.sun_path, length)
4100Sigor@sysoev.ru                 != 0)
4110Sigor@sysoev.ru             {
4120Sigor@sysoev.ru                 return 0;
4130Sigor@sysoev.ru             }
4140Sigor@sysoev.ru 
4150Sigor@sysoev.ru             return 1;
4160Sigor@sysoev.ru         }
4170Sigor@sysoev.ru 
4180Sigor@sysoev.ru #endif
4190Sigor@sysoev.ru 
4200Sigor@sysoev.ru     default: /* AF_INET */
4210Sigor@sysoev.ru         if (sa1->u.sockaddr_in.sin_port != sa2->u.sockaddr_in.sin_port) {
4220Sigor@sysoev.ru             return 0;
4230Sigor@sysoev.ru         }
4240Sigor@sysoev.ru 
4250Sigor@sysoev.ru         if (sa1->u.sockaddr_in.sin_addr.s_addr
4260Sigor@sysoev.ru             != sa2->u.sockaddr_in.sin_addr.s_addr)
4270Sigor@sysoev.ru         {
4280Sigor@sysoev.ru             return 0;
4290Sigor@sysoev.ru         }
4300Sigor@sysoev.ru 
4310Sigor@sysoev.ru         return 1;
4320Sigor@sysoev.ru     }
4330Sigor@sysoev.ru }
4340Sigor@sysoev.ru 
4350Sigor@sysoev.ru 
4360Sigor@sysoev.ru size_t
nxt_sockaddr_ntop(nxt_sockaddr_t * sa,u_char * buf,u_char * end,nxt_bool_t port)4370Sigor@sysoev.ru nxt_sockaddr_ntop(nxt_sockaddr_t *sa, u_char *buf, u_char *end, nxt_bool_t port)
4380Sigor@sysoev.ru {
4390Sigor@sysoev.ru     u_char  *p;
4400Sigor@sysoev.ru 
4410Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
4420Sigor@sysoev.ru 
4430Sigor@sysoev.ru     case AF_INET:
4440Sigor@sysoev.ru         p = (u_char *) &sa->u.sockaddr_in.sin_addr;
4450Sigor@sysoev.ru 
4460Sigor@sysoev.ru         if (port) {
4470Sigor@sysoev.ru             p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud:%d",
4480Sigor@sysoev.ru                             p[0], p[1], p[2], p[3],
4490Sigor@sysoev.ru                             ntohs(sa->u.sockaddr_in.sin_port));
4500Sigor@sysoev.ru         } else {
4510Sigor@sysoev.ru             p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud",
4520Sigor@sysoev.ru                             p[0], p[1], p[2], p[3]);
4530Sigor@sysoev.ru         }
4540Sigor@sysoev.ru 
4550Sigor@sysoev.ru         return p - buf;
4560Sigor@sysoev.ru 
4570Sigor@sysoev.ru #if (NXT_INET6)
4580Sigor@sysoev.ru 
4590Sigor@sysoev.ru     case AF_INET6:
4600Sigor@sysoev.ru         p = buf;
4610Sigor@sysoev.ru 
4620Sigor@sysoev.ru         if (port) {
4630Sigor@sysoev.ru             *p++ = '[';
4640Sigor@sysoev.ru         }
4650Sigor@sysoev.ru 
4660Sigor@sysoev.ru         p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end);
4670Sigor@sysoev.ru 
4680Sigor@sysoev.ru         if (port) {
4690Sigor@sysoev.ru             p = nxt_sprintf(p, end, "]:%d",
4700Sigor@sysoev.ru                             ntohs(sa->u.sockaddr_in6.sin6_port));
4710Sigor@sysoev.ru         }
4720Sigor@sysoev.ru 
4730Sigor@sysoev.ru         return p - buf;
4740Sigor@sysoev.ru #endif
4750Sigor@sysoev.ru 
4760Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
4770Sigor@sysoev.ru 
4780Sigor@sysoev.ru     case AF_UNIX:
4790Sigor@sysoev.ru 
4800Sigor@sysoev.ru #if (NXT_LINUX)
4810Sigor@sysoev.ru 
4820Sigor@sysoev.ru         p = (u_char *) sa->u.sockaddr_un.sun_path;
4830Sigor@sysoev.ru 
4840Sigor@sysoev.ru         if (p[0] == '\0') {
485493Spluknet@nginx.com             size_t  length;
4860Sigor@sysoev.ru 
4870Sigor@sysoev.ru             /* Linux abstract socket address has no trailing zero. */
4880Sigor@sysoev.ru 
48913Sigor@sysoev.ru             length = sa->socklen - offsetof(struct sockaddr_un, sun_path) - 1;
49010Sigor@sysoev.ru             p = nxt_sprintf(buf, end, "unix:\\0%*s", length, p + 1);
4910Sigor@sysoev.ru 
4920Sigor@sysoev.ru         } else {
4930Sigor@sysoev.ru             p = nxt_sprintf(buf, end, "unix:%s", p);
4940Sigor@sysoev.ru         }
4950Sigor@sysoev.ru 
4960Sigor@sysoev.ru #else  /* !(NXT_LINUX) */
4970Sigor@sysoev.ru 
4980Sigor@sysoev.ru         p = nxt_sprintf(buf, end, "unix:%s", sa->u.sockaddr_un.sun_path);
4990Sigor@sysoev.ru 
5000Sigor@sysoev.ru #endif
5010Sigor@sysoev.ru 
5020Sigor@sysoev.ru         return p - buf;
5030Sigor@sysoev.ru 
5040Sigor@sysoev.ru #endif  /* NXT_HAVE_UNIX_DOMAIN */
5050Sigor@sysoev.ru 
5060Sigor@sysoev.ru     default:
5070Sigor@sysoev.ru         return 0;
5080Sigor@sysoev.ru     }
5090Sigor@sysoev.ru }
5100Sigor@sysoev.ru 
5110Sigor@sysoev.ru 
5120Sigor@sysoev.ru #if (NXT_INET6)
5130Sigor@sysoev.ru 
5140Sigor@sysoev.ru static u_char *
nxt_inet6_ntop(u_char * addr,u_char * buf,u_char * end)5150Sigor@sysoev.ru nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end)
5160Sigor@sysoev.ru {
517101Sigor@sysoev.ru     u_char       *p;
518101Sigor@sysoev.ru     size_t       zero_groups, last_zero_groups, ipv6_bytes;
519101Sigor@sysoev.ru     nxt_uint_t   i, zero_start, last_zero_start;
5200Sigor@sysoev.ru 
521101Sigor@sysoev.ru     const size_t  max_inet6_length =
522703Svbart@nginx.com                         nxt_length("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
523101Sigor@sysoev.ru 
524101Sigor@sysoev.ru     if (buf + max_inet6_length > end) {
5250Sigor@sysoev.ru         return buf;
5260Sigor@sysoev.ru     }
5270Sigor@sysoev.ru 
5281909So.canty@f5.com     zero_start = 16;
5290Sigor@sysoev.ru     zero_groups = 0;
5301909So.canty@f5.com     last_zero_start = 16;
5310Sigor@sysoev.ru     last_zero_groups = 0;
5320Sigor@sysoev.ru 
5330Sigor@sysoev.ru     for (i = 0; i < 16; i += 2) {
5340Sigor@sysoev.ru 
5350Sigor@sysoev.ru         if (addr[i] == 0 && addr[i + 1] == 0) {
5360Sigor@sysoev.ru 
5370Sigor@sysoev.ru             if (last_zero_groups == 0) {
5380Sigor@sysoev.ru                 last_zero_start = i;
5390Sigor@sysoev.ru             }
5400Sigor@sysoev.ru 
5410Sigor@sysoev.ru             last_zero_groups++;
5420Sigor@sysoev.ru 
5430Sigor@sysoev.ru         } else {
5440Sigor@sysoev.ru             if (zero_groups < last_zero_groups) {
5450Sigor@sysoev.ru                 zero_groups = last_zero_groups;
5460Sigor@sysoev.ru                 zero_start = last_zero_start;
5470Sigor@sysoev.ru             }
5480Sigor@sysoev.ru 
5490Sigor@sysoev.ru             last_zero_groups = 0;
5500Sigor@sysoev.ru         }
5510Sigor@sysoev.ru     }
5520Sigor@sysoev.ru 
5530Sigor@sysoev.ru     if (zero_groups < last_zero_groups) {
5540Sigor@sysoev.ru         zero_groups = last_zero_groups;
5550Sigor@sysoev.ru         zero_start = last_zero_start;
5560Sigor@sysoev.ru     }
5570Sigor@sysoev.ru 
5580Sigor@sysoev.ru     ipv6_bytes = 16;
5590Sigor@sysoev.ru     p = buf;
5600Sigor@sysoev.ru 
5610Sigor@sysoev.ru     if (zero_start == 0) {
5620Sigor@sysoev.ru 
5630Sigor@sysoev.ru                /* IPv4-mapped address */
564611Svbart@nginx.com         if ((zero_groups == 5 && addr[10] == 0xFF && addr[11] == 0xFF)
5650Sigor@sysoev.ru                /* IPv4-compatible address */
5660Sigor@sysoev.ru             || (zero_groups == 6)
5670Sigor@sysoev.ru                /* not IPv6 loopback address */
5680Sigor@sysoev.ru             || (zero_groups == 7 && addr[14] != 0 && addr[15] != 1))
5690Sigor@sysoev.ru         {
5700Sigor@sysoev.ru             ipv6_bytes = 12;
5710Sigor@sysoev.ru         }
5720Sigor@sysoev.ru 
5730Sigor@sysoev.ru         *p++ = ':';
5740Sigor@sysoev.ru     }
5750Sigor@sysoev.ru 
5760Sigor@sysoev.ru     for (i = 0; i < ipv6_bytes; i += 2) {
5770Sigor@sysoev.ru 
5780Sigor@sysoev.ru         if (i == zero_start) {
5790Sigor@sysoev.ru             /* Output maximum number of consecutive zero groups as "::". */
5800Sigor@sysoev.ru             i += (zero_groups - 1) * 2;
5810Sigor@sysoev.ru             *p++ = ':';
5820Sigor@sysoev.ru             continue;
5830Sigor@sysoev.ru         }
5840Sigor@sysoev.ru 
5850Sigor@sysoev.ru         p = nxt_sprintf(p, end, "%uxd", (addr[i] << 8) + addr[i + 1]);
5860Sigor@sysoev.ru 
5870Sigor@sysoev.ru         if (i < 14) {
5880Sigor@sysoev.ru             *p++ = ':';
5890Sigor@sysoev.ru         }
5900Sigor@sysoev.ru     }
5910Sigor@sysoev.ru 
5920Sigor@sysoev.ru     if (ipv6_bytes == 12) {
5930Sigor@sysoev.ru         p = nxt_sprintf(p, end, "%ud.%ud.%ud.%ud",
5940Sigor@sysoev.ru                         addr[12], addr[13], addr[14], addr[15]);
5950Sigor@sysoev.ru     }
5960Sigor@sysoev.ru 
5970Sigor@sysoev.ru     return p;
5980Sigor@sysoev.ru }
5990Sigor@sysoev.ru 
6000Sigor@sysoev.ru #endif
6010Sigor@sysoev.ru 
6020Sigor@sysoev.ru 
60399Sigor@sysoev.ru nxt_sockaddr_t *
nxt_sockaddr_parse(nxt_mp_t * mp,nxt_str_t * addr)60499Sigor@sysoev.ru nxt_sockaddr_parse(nxt_mp_t *mp, nxt_str_t *addr)
60599Sigor@sysoev.ru {
60699Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
60799Sigor@sysoev.ru 
6081935So.canty@f5.com     sa = nxt_sockaddr_parse_optport(mp, addr);
6091935So.canty@f5.com 
6101935So.canty@f5.com     if (sa != NULL
6111935So.canty@f5.com         && sa->u.sockaddr.sa_family != AF_UNIX
6121935So.canty@f5.com         && nxt_sockaddr_port_number(sa) == 0)
6131935So.canty@f5.com     {
6141935So.canty@f5.com         nxt_thread_log_error(NXT_LOG_ERR,
6151935So.canty@f5.com                              "The address \"%V\" must specify a port.", addr);
6161935So.canty@f5.com         return NULL;
6171935So.canty@f5.com     }
6181935So.canty@f5.com 
6191935So.canty@f5.com     return sa;
6201935So.canty@f5.com }
6211935So.canty@f5.com 
6221935So.canty@f5.com 
6231935So.canty@f5.com nxt_sockaddr_t *
nxt_sockaddr_parse_optport(nxt_mp_t * mp,nxt_str_t * addr)6241935So.canty@f5.com nxt_sockaddr_parse_optport(nxt_mp_t *mp, nxt_str_t *addr)
6251935So.canty@f5.com {
6261935So.canty@f5.com     nxt_sockaddr_t  *sa;
6271935So.canty@f5.com 
6281935So.canty@f5.com     if (addr->length == 0) {
6291935So.canty@f5.com         nxt_thread_log_error(NXT_LOG_ERR, "socket address cannot be empty");
6301935So.canty@f5.com         return NULL;
6311935So.canty@f5.com     }
6321935So.canty@f5.com 
63399Sigor@sysoev.ru     if (addr->length > 6 && nxt_memcmp(addr->start, "unix:", 5) == 0) {
63499Sigor@sysoev.ru         sa = nxt_sockaddr_unix_parse(mp, addr);
63599Sigor@sysoev.ru 
6361935So.canty@f5.com     } else if (addr->start[0] == '[' || nxt_inet6_probe(addr)) {
63799Sigor@sysoev.ru         sa = nxt_sockaddr_inet6_parse(mp, addr);
63899Sigor@sysoev.ru 
63999Sigor@sysoev.ru     } else {
64099Sigor@sysoev.ru         sa = nxt_sockaddr_inet_parse(mp, addr);
64199Sigor@sysoev.ru     }
64299Sigor@sysoev.ru 
64399Sigor@sysoev.ru     if (nxt_fast_path(sa != NULL)) {
64499Sigor@sysoev.ru         nxt_sockaddr_text(sa);
64599Sigor@sysoev.ru     }
64699Sigor@sysoev.ru 
64799Sigor@sysoev.ru     return sa;
64899Sigor@sysoev.ru }
64999Sigor@sysoev.ru 
65099Sigor@sysoev.ru 
65199Sigor@sysoev.ru static nxt_sockaddr_t *
nxt_sockaddr_unix_parse(nxt_mp_t * mp,nxt_str_t * addr)65299Sigor@sysoev.ru nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr)
65399Sigor@sysoev.ru {
65499Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
65599Sigor@sysoev.ru     size_t          length, socklen;
65699Sigor@sysoev.ru     u_char          *path;
65799Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
65899Sigor@sysoev.ru 
65999Sigor@sysoev.ru     /*
66099Sigor@sysoev.ru      * Actual sockaddr_un length can be lesser or even larger than defined
661211Sru@nginx.com      * struct sockaddr_un length (see comment in nxt_socket.h).  So
66299Sigor@sysoev.ru      * limit maximum Unix domain socket address length by defined sun_path[]
66399Sigor@sysoev.ru      * length because some OSes accept addresses twice larger than defined
66499Sigor@sysoev.ru      * struct sockaddr_un.  Also reserve space for a trailing zero to avoid
66599Sigor@sysoev.ru      * ambiguity, since many OSes accept Unix domain socket addresses
66699Sigor@sysoev.ru      * without a trailing zero.
66799Sigor@sysoev.ru      */
66899Sigor@sysoev.ru     const size_t max_len = sizeof(struct sockaddr_un)
66999Sigor@sysoev.ru                            - offsetof(struct sockaddr_un, sun_path) - 1;
67099Sigor@sysoev.ru 
67199Sigor@sysoev.ru     /* Cutting "unix:". */
67299Sigor@sysoev.ru     length = addr->length - 5;
67399Sigor@sysoev.ru     path = addr->start + 5;
67499Sigor@sysoev.ru 
67599Sigor@sysoev.ru     if (length > max_len) {
67699Sigor@sysoev.ru         nxt_thread_log_error(NXT_LOG_ERR,
67799Sigor@sysoev.ru                              "unix domain socket \"%V\" name is too long",
67899Sigor@sysoev.ru                              addr);
67999Sigor@sysoev.ru         return NULL;
68099Sigor@sysoev.ru     }
68199Sigor@sysoev.ru 
68299Sigor@sysoev.ru     socklen = offsetof(struct sockaddr_un, sun_path) + length + 1;
68399Sigor@sysoev.ru 
68499Sigor@sysoev.ru #if (NXT_LINUX)
68599Sigor@sysoev.ru 
68699Sigor@sysoev.ru     /*
68799Sigor@sysoev.ru      * Linux unix(7):
68899Sigor@sysoev.ru      *
68999Sigor@sysoev.ru      *   abstract: an abstract socket address is distinguished by the fact
69099Sigor@sysoev.ru      *   that sun_path[0] is a null byte ('\0').  The socket's address in
69199Sigor@sysoev.ru      *   this namespace is given by the additional bytes in sun_path that
69299Sigor@sysoev.ru      *   are covered by the specified length of the address structure.
69399Sigor@sysoev.ru      *   (Null bytes in the name have no special significance.)
69499Sigor@sysoev.ru      */
69599Sigor@sysoev.ru     if (path[0] == '@') {
69699Sigor@sysoev.ru         path[0] = '\0';
69799Sigor@sysoev.ru         socklen--;
69899Sigor@sysoev.ru     }
69999Sigor@sysoev.ru 
70099Sigor@sysoev.ru #endif
70199Sigor@sysoev.ru 
70299Sigor@sysoev.ru     sa = nxt_sockaddr_alloc(mp, socklen, addr->length);
70399Sigor@sysoev.ru 
70499Sigor@sysoev.ru     if (nxt_fast_path(sa != NULL)) {
70599Sigor@sysoev.ru         sa->u.sockaddr_un.sun_family = AF_UNIX;
70699Sigor@sysoev.ru         nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length);
70799Sigor@sysoev.ru     }
70899Sigor@sysoev.ru 
70999Sigor@sysoev.ru     return sa;
71099Sigor@sysoev.ru 
71199Sigor@sysoev.ru #else  /* !(NXT_HAVE_UNIX_DOMAIN) */
71299Sigor@sysoev.ru 
71399Sigor@sysoev.ru     nxt_thread_log_error(NXT_LOG_ERR,
71499Sigor@sysoev.ru                          "unix domain socket \"%V\" is not supported", addr);
71599Sigor@sysoev.ru 
71699Sigor@sysoev.ru     return NULL;
71799Sigor@sysoev.ru 
71899Sigor@sysoev.ru #endif
71999Sigor@sysoev.ru }
72099Sigor@sysoev.ru 
72199Sigor@sysoev.ru 
72299Sigor@sysoev.ru static nxt_sockaddr_t *
nxt_sockaddr_inet6_parse(nxt_mp_t * mp,nxt_str_t * addr)72399Sigor@sysoev.ru nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr)
72499Sigor@sysoev.ru {
72599Sigor@sysoev.ru #if (NXT_INET6)
72699Sigor@sysoev.ru     u_char          *p, *start, *end;
72799Sigor@sysoev.ru     size_t          length;
72899Sigor@sysoev.ru     nxt_int_t       ret, port;
72999Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
73099Sigor@sysoev.ru 
7311935So.canty@f5.com     if (addr->start[0] == '[') {
7321935So.canty@f5.com         length = addr->length - 1;
7331935So.canty@f5.com         start = addr->start + 1;
73499Sigor@sysoev.ru 
7351935So.canty@f5.com         end = nxt_memchr(start, ']', length);
7361935So.canty@f5.com         if (nxt_slow_path(end == NULL)) {
73799Sigor@sysoev.ru             return NULL;
73899Sigor@sysoev.ru         }
73999Sigor@sysoev.ru 
7401935So.canty@f5.com         p = end + 1;
74199Sigor@sysoev.ru 
7421935So.canty@f5.com     } else {
7431935So.canty@f5.com         length = addr->length;
7441935So.canty@f5.com         start = addr->start;
7451935So.canty@f5.com         end = addr->start + addr->length;
7461935So.canty@f5.com         p = NULL;
7471935So.canty@f5.com     }
74899Sigor@sysoev.ru 
7491935So.canty@f5.com     port = 0;
75099Sigor@sysoev.ru 
7511935So.canty@f5.com     if (p != NULL) {
7521935So.canty@f5.com         length = (start + length) - p;
75399Sigor@sysoev.ru 
7541935So.canty@f5.com         if (length < 2 || *p != ':') {
7551935So.canty@f5.com             nxt_thread_log_error(NXT_LOG_ERR, "invalid IPv6 address in \"%V\"",
7561935So.canty@f5.com                                  addr);
7571935So.canty@f5.com             return NULL;
7581935So.canty@f5.com         }
75999Sigor@sysoev.ru 
7601935So.canty@f5.com         port = nxt_int_parse(p + 1, length - 1);
7611935So.canty@f5.com 
7621935So.canty@f5.com         if (port < 1 || port > 65535) {
76399Sigor@sysoev.ru             nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr);
76499Sigor@sysoev.ru             return NULL;
76599Sigor@sysoev.ru         }
76699Sigor@sysoev.ru     }
76799Sigor@sysoev.ru 
7681935So.canty@f5.com     sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6),
7691935So.canty@f5.com                             NXT_INET6_ADDR_STR_LEN);
7701935So.canty@f5.com     if (nxt_slow_path(sa == NULL)) {
7711935So.canty@f5.com         return NULL;
7721935So.canty@f5.com     }
77399Sigor@sysoev.ru 
7741935So.canty@f5.com     ret = nxt_inet6_addr(&sa->u.sockaddr_in6.sin6_addr, start, end - start);
7751935So.canty@f5.com     if (nxt_slow_path(ret != NXT_OK)) {
7761935So.canty@f5.com         nxt_thread_log_error(NXT_LOG_ERR, "invalid IPv6 address in \"%V\"",
7771935So.canty@f5.com                              addr);
7781935So.canty@f5.com         return NULL;
7791935So.canty@f5.com     }
7801935So.canty@f5.com 
7811935So.canty@f5.com     sa->u.sockaddr_in6.sin6_family = AF_INET6;
7821935So.canty@f5.com     sa->u.sockaddr_in6.sin6_port = htons((in_port_t) port);
7831935So.canty@f5.com 
7841935So.canty@f5.com     return sa;
78599Sigor@sysoev.ru 
78699Sigor@sysoev.ru #else  /* !(NXT_INET6) */
78799Sigor@sysoev.ru 
78899Sigor@sysoev.ru     nxt_thread_log_error(NXT_LOG_ERR, "IPv6 socket \"%V\" is not supported",
78999Sigor@sysoev.ru                          addr);
79099Sigor@sysoev.ru     return NULL;
79199Sigor@sysoev.ru 
79299Sigor@sysoev.ru #endif
79399Sigor@sysoev.ru }
79499Sigor@sysoev.ru 
79599Sigor@sysoev.ru 
79699Sigor@sysoev.ru static nxt_sockaddr_t *
nxt_sockaddr_inet_parse(nxt_mp_t * mp,nxt_str_t * addr)79799Sigor@sysoev.ru nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr)
79899Sigor@sysoev.ru {
79999Sigor@sysoev.ru     u_char          *p;
80099Sigor@sysoev.ru     size_t          length;
80199Sigor@sysoev.ru     nxt_int_t       port;
80299Sigor@sysoev.ru     in_addr_t       inaddr;
80399Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
80499Sigor@sysoev.ru 
80599Sigor@sysoev.ru     p = nxt_memchr(addr->start, ':', addr->length);
80699Sigor@sysoev.ru 
8071935So.canty@f5.com     if (p == NULL) {
8081935So.canty@f5.com         length = addr->length;
80999Sigor@sysoev.ru 
8101935So.canty@f5.com     } else {
8111935So.canty@f5.com         length = p - addr->start;
8121935So.canty@f5.com     }
81399Sigor@sysoev.ru 
8141935So.canty@f5.com     inaddr = INADDR_ANY;
81599Sigor@sysoev.ru 
8161935So.canty@f5.com     if (length != 1 || addr->start[0] != '*') {
8171935So.canty@f5.com         inaddr = nxt_inet_addr(addr->start, length);
8181935So.canty@f5.com         if (nxt_slow_path(inaddr == INADDR_NONE)) {
8191935So.canty@f5.com             nxt_thread_log_error(NXT_LOG_ERR, "invalid address \"%V\"", addr);
8201935So.canty@f5.com             return NULL;
82199Sigor@sysoev.ru         }
82299Sigor@sysoev.ru     }
82399Sigor@sysoev.ru 
8241935So.canty@f5.com     port = 0;
8251935So.canty@f5.com 
8261935So.canty@f5.com     if (p != NULL) {
8271935So.canty@f5.com         p++;
8281935So.canty@f5.com         length = (addr->start + addr->length) - p;
8291935So.canty@f5.com 
8301935So.canty@f5.com         port = nxt_int_parse(p, length);
83199Sigor@sysoev.ru 
8321935So.canty@f5.com         if (port < 1 || port > 65535) {
8331935So.canty@f5.com             nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr);
8341935So.canty@f5.com             return NULL;
8351935So.canty@f5.com         }
8361935So.canty@f5.com     }
8371935So.canty@f5.com 
8381935So.canty@f5.com     sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in),
8391935So.canty@f5.com                             NXT_INET_ADDR_STR_LEN);
8401935So.canty@f5.com     if (nxt_slow_path(sa == NULL)) {
8411935So.canty@f5.com         return NULL;
8421935So.canty@f5.com     }
8431935So.canty@f5.com 
8441935So.canty@f5.com     sa->u.sockaddr_in.sin_family = AF_INET;
8451935So.canty@f5.com     sa->u.sockaddr_in.sin_addr.s_addr = inaddr;
8461935So.canty@f5.com     sa->u.sockaddr_in.sin_port = htons((in_port_t) port);
8471935So.canty@f5.com 
8481935So.canty@f5.com     return sa;
84999Sigor@sysoev.ru }
85099Sigor@sysoev.ru 
85199Sigor@sysoev.ru 
8520Sigor@sysoev.ru void
nxt_job_sockaddr_parse(nxt_job_sockaddr_parse_t * jbs)8530Sigor@sysoev.ru nxt_job_sockaddr_parse(nxt_job_sockaddr_parse_t *jbs)
8540Sigor@sysoev.ru {
8550Sigor@sysoev.ru     u_char              *p;
85610Sigor@sysoev.ru     size_t              length;
8570Sigor@sysoev.ru     nxt_int_t           ret;
8580Sigor@sysoev.ru     nxt_work_handler_t  handler;
8590Sigor@sysoev.ru 
8600Sigor@sysoev.ru     nxt_job_set_name(&jbs->resolve.job, "job sockaddr parse");
8610Sigor@sysoev.ru 
86210Sigor@sysoev.ru     length = jbs->addr.length;
86310Sigor@sysoev.ru     p = jbs->addr.start;
8640Sigor@sysoev.ru 
86571Svbart@nginx.com     if (length > 6 && nxt_memcmp(p, "unix:", 5) == 0) {
8660Sigor@sysoev.ru         ret = nxt_job_sockaddr_unix_parse(jbs);
8670Sigor@sysoev.ru 
86810Sigor@sysoev.ru     } else if (length != 0 && *p == '[') {
8690Sigor@sysoev.ru         ret = nxt_job_sockaddr_inet6_parse(jbs);
8700Sigor@sysoev.ru 
8710Sigor@sysoev.ru     } else {
8720Sigor@sysoev.ru         ret = nxt_job_sockaddr_inet_parse(jbs);
8730Sigor@sysoev.ru     }
8740Sigor@sysoev.ru 
8750Sigor@sysoev.ru     switch (ret) {
8760Sigor@sysoev.ru 
8770Sigor@sysoev.ru     case NXT_OK:
8780Sigor@sysoev.ru         handler = jbs->resolve.ready_handler;
8790Sigor@sysoev.ru         break;
8800Sigor@sysoev.ru 
8810Sigor@sysoev.ru     case NXT_ERROR:
8820Sigor@sysoev.ru         handler = jbs->resolve.error_handler;
8830Sigor@sysoev.ru         break;
8840Sigor@sysoev.ru 
8850Sigor@sysoev.ru     default: /* NXT_AGAIN */
8860Sigor@sysoev.ru         return;
8870Sigor@sysoev.ru     }
8880Sigor@sysoev.ru 
8894Sigor@sysoev.ru     nxt_job_return(jbs->resolve.job.task, &jbs->resolve.job, handler);
8900Sigor@sysoev.ru }
8910Sigor@sysoev.ru 
8920Sigor@sysoev.ru 
8930Sigor@sysoev.ru static nxt_int_t
nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t * jbs)8940Sigor@sysoev.ru nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs)
8950Sigor@sysoev.ru {
8960Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
89710Sigor@sysoev.ru     size_t          length, socklen;
8980Sigor@sysoev.ru     u_char          *path;
89965Sigor@sysoev.ru     nxt_mp_t        *mp;
9000Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
9010Sigor@sysoev.ru 
9020Sigor@sysoev.ru     /*
9030Sigor@sysoev.ru      * Actual sockaddr_un length can be lesser or even larger than defined
904211Sru@nginx.com      * struct sockaddr_un length (see comment in nxt_socket.h).  So
9050Sigor@sysoev.ru      * limit maximum Unix domain socket address length by defined sun_path[]
9060Sigor@sysoev.ru      * length because some OSes accept addresses twice larger than defined
9070Sigor@sysoev.ru      * struct sockaddr_un.  Also reserve space for a trailing zero to avoid
9080Sigor@sysoev.ru      * ambiguity, since many OSes accept Unix domain socket addresses
9090Sigor@sysoev.ru      * without a trailing zero.
9100Sigor@sysoev.ru      */
9110Sigor@sysoev.ru     const size_t max_len = sizeof(struct sockaddr_un)
9120Sigor@sysoev.ru                            - offsetof(struct sockaddr_un, sun_path) - 1;
9130Sigor@sysoev.ru 
9140Sigor@sysoev.ru     /* cutting "unix:" */
91510Sigor@sysoev.ru     length = jbs->addr.length - 5;
91610Sigor@sysoev.ru     path = jbs->addr.start + 5;
9170Sigor@sysoev.ru 
91810Sigor@sysoev.ru     if (length > max_len) {
9190Sigor@sysoev.ru         nxt_thread_log_error(jbs->resolve.log_level,
9200Sigor@sysoev.ru                              "unix domain socket \"%V\" name is too long",
9210Sigor@sysoev.ru                              &jbs->addr);
9220Sigor@sysoev.ru         return NXT_ERROR;
9230Sigor@sysoev.ru     }
9240Sigor@sysoev.ru 
92510Sigor@sysoev.ru     socklen = offsetof(struct sockaddr_un, sun_path) + length + 1;
9260Sigor@sysoev.ru 
9270Sigor@sysoev.ru #if (NXT_LINUX)
9280Sigor@sysoev.ru 
9290Sigor@sysoev.ru     /*
9300Sigor@sysoev.ru      * Linux unix(7):
9310Sigor@sysoev.ru      *
9320Sigor@sysoev.ru      *   abstract: an abstract socket address is distinguished by the fact
9330Sigor@sysoev.ru      *   that sun_path[0] is a null byte ('\0').  The socket's address in
9340Sigor@sysoev.ru      *   this namespace is given by the additional bytes in sun_path that
9350Sigor@sysoev.ru      *   are covered by the specified length of the address structure.
9360Sigor@sysoev.ru      *   (Null bytes in the name have no special significance.)
9370Sigor@sysoev.ru      */
9380Sigor@sysoev.ru     if (path[0] == '\0') {
9390Sigor@sysoev.ru         socklen--;
9400Sigor@sysoev.ru     }
9410Sigor@sysoev.ru 
9420Sigor@sysoev.ru #endif
9430Sigor@sysoev.ru 
9440Sigor@sysoev.ru     mp = jbs->resolve.job.mem_pool;
9450Sigor@sysoev.ru 
94665Sigor@sysoev.ru     jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *));
9470Sigor@sysoev.ru 
9480Sigor@sysoev.ru     if (nxt_fast_path(jbs->resolve.sockaddrs != NULL)) {
94913Sigor@sysoev.ru         sa = nxt_sockaddr_alloc(mp, socklen, jbs->addr.length);
9500Sigor@sysoev.ru 
9510Sigor@sysoev.ru         if (nxt_fast_path(sa != NULL)) {
9520Sigor@sysoev.ru             jbs->resolve.count = 1;
9530Sigor@sysoev.ru             jbs->resolve.sockaddrs[0] = sa;
9540Sigor@sysoev.ru 
9550Sigor@sysoev.ru             sa->u.sockaddr_un.sun_family = AF_UNIX;
95610Sigor@sysoev.ru             nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length);
9570Sigor@sysoev.ru 
9580Sigor@sysoev.ru             return NXT_OK;
9590Sigor@sysoev.ru         }
9600Sigor@sysoev.ru     }
9610Sigor@sysoev.ru 
9620Sigor@sysoev.ru     return NXT_ERROR;
9630Sigor@sysoev.ru 
9640Sigor@sysoev.ru #else  /* !(NXT_HAVE_UNIX_DOMAIN) */
9650Sigor@sysoev.ru 
9660Sigor@sysoev.ru     nxt_thread_log_error(jbs->resolve.log_level,
9670Sigor@sysoev.ru                          "unix domain socket \"%V\" is not supported",
9680Sigor@sysoev.ru                          &jbs->addr);
9690Sigor@sysoev.ru     return NXT_ERROR;
9700Sigor@sysoev.ru 
9710Sigor@sysoev.ru #endif
9720Sigor@sysoev.ru }
9730Sigor@sysoev.ru 
9740Sigor@sysoev.ru 
9750Sigor@sysoev.ru static nxt_int_t
nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t * jbs)9760Sigor@sysoev.ru nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs)
9770Sigor@sysoev.ru {
9780Sigor@sysoev.ru #if (NXT_INET6)
9790Sigor@sysoev.ru     u_char           *p, *addr, *addr_end;
98010Sigor@sysoev.ru     size_t           length;
98165Sigor@sysoev.ru     nxt_mp_t         *mp;
9820Sigor@sysoev.ru     nxt_int_t        port;
9830Sigor@sysoev.ru     nxt_sockaddr_t   *sa;
9840Sigor@sysoev.ru     struct in6_addr  *in6_addr;
9850Sigor@sysoev.ru 
98610Sigor@sysoev.ru     length = jbs->addr.length - 1;
98710Sigor@sysoev.ru     addr = jbs->addr.start + 1;
9880Sigor@sysoev.ru 
98910Sigor@sysoev.ru     addr_end = nxt_memchr(addr, ']', length);
9900Sigor@sysoev.ru 
9910Sigor@sysoev.ru     if (addr_end == NULL) {
9920Sigor@sysoev.ru         goto invalid_address;
9930Sigor@sysoev.ru     }
9940Sigor@sysoev.ru 
9950Sigor@sysoev.ru     mp = jbs->resolve.job.mem_pool;
9960Sigor@sysoev.ru 
99765Sigor@sysoev.ru     jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *));
9980Sigor@sysoev.ru 
9990Sigor@sysoev.ru     if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) {
10000Sigor@sysoev.ru         return NXT_ERROR;
10010Sigor@sysoev.ru     }
10020Sigor@sysoev.ru 
100399Sigor@sysoev.ru     sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6),
100499Sigor@sysoev.ru                             NXT_INET6_ADDR_STR_LEN);
10050Sigor@sysoev.ru 
10060Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
10070Sigor@sysoev.ru         return NXT_ERROR;
10080Sigor@sysoev.ru     }
10090Sigor@sysoev.ru 
10100Sigor@sysoev.ru     jbs->resolve.count = 1;
10110Sigor@sysoev.ru     jbs->resolve.sockaddrs[0] = sa;
10120Sigor@sysoev.ru 
10130Sigor@sysoev.ru     in6_addr = &sa->u.sockaddr_in6.sin6_addr;
10140Sigor@sysoev.ru 
10150Sigor@sysoev.ru     if (nxt_inet6_addr(in6_addr, addr, addr_end - addr) != NXT_OK) {
10160Sigor@sysoev.ru         goto invalid_address;
10170Sigor@sysoev.ru     }
10180Sigor@sysoev.ru 
10190Sigor@sysoev.ru     p = addr_end + 1;
102010Sigor@sysoev.ru     length = (addr + length) - p;
10210Sigor@sysoev.ru 
102210Sigor@sysoev.ru     if (length == 0) {
10230Sigor@sysoev.ru         jbs->no_port = 1;
10240Sigor@sysoev.ru         port = jbs->resolve.port;
10250Sigor@sysoev.ru         goto found;
10260Sigor@sysoev.ru     }
10270Sigor@sysoev.ru 
10280Sigor@sysoev.ru     if (*p == ':') {
102910Sigor@sysoev.ru         port = nxt_int_parse(p + 1, length - 1);
10300Sigor@sysoev.ru 
10310Sigor@sysoev.ru         if (port >= 1 && port <= 65535) {
10320Sigor@sysoev.ru             port = htons((in_port_t) port);
10330Sigor@sysoev.ru             goto found;
10340Sigor@sysoev.ru         }
10350Sigor@sysoev.ru     }
10360Sigor@sysoev.ru 
10370Sigor@sysoev.ru     nxt_thread_log_error(jbs->resolve.log_level,
10380Sigor@sysoev.ru                          "invalid port in \"%V\"", &jbs->addr);
10390Sigor@sysoev.ru 
10400Sigor@sysoev.ru     return NXT_ERROR;
10410Sigor@sysoev.ru 
10420Sigor@sysoev.ru found:
10430Sigor@sysoev.ru 
10440Sigor@sysoev.ru     sa->u.sockaddr_in6.sin6_family = AF_INET6;
10450Sigor@sysoev.ru     sa->u.sockaddr_in6.sin6_port = (in_port_t) port;
10460Sigor@sysoev.ru 
10470Sigor@sysoev.ru     if (IN6_IS_ADDR_UNSPECIFIED(in6_addr)) {
10480Sigor@sysoev.ru         jbs->wildcard = 1;
10490Sigor@sysoev.ru     }
10500Sigor@sysoev.ru 
10510Sigor@sysoev.ru     return NXT_OK;
10520Sigor@sysoev.ru 
10530Sigor@sysoev.ru invalid_address:
10540Sigor@sysoev.ru 
10550Sigor@sysoev.ru     nxt_thread_log_error(jbs->resolve.log_level,
10560Sigor@sysoev.ru                          "invalid IPv6 address in \"%V\"", &jbs->addr);
10570Sigor@sysoev.ru     return NXT_ERROR;
10580Sigor@sysoev.ru 
10590Sigor@sysoev.ru #else
10600Sigor@sysoev.ru 
10610Sigor@sysoev.ru     nxt_thread_log_error(jbs->resolve.log_level,
10620Sigor@sysoev.ru                          "IPv6 socket \"%V\" is not supported", &jbs->addr);
10630Sigor@sysoev.ru     return NXT_ERROR;
10640Sigor@sysoev.ru 
10650Sigor@sysoev.ru #endif
10660Sigor@sysoev.ru }
10670Sigor@sysoev.ru 
10680Sigor@sysoev.ru 
10690Sigor@sysoev.ru static nxt_int_t
nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t * jbs)10700Sigor@sysoev.ru nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs)
10710Sigor@sysoev.ru {
10720Sigor@sysoev.ru     u_char          *p, *host;
107310Sigor@sysoev.ru     size_t          length;
107465Sigor@sysoev.ru     nxt_mp_t        *mp;
10750Sigor@sysoev.ru     nxt_int_t       port;
107665Sigor@sysoev.ru     in_addr_t       addr;
10770Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
10780Sigor@sysoev.ru 
10790Sigor@sysoev.ru     addr = INADDR_ANY;
10800Sigor@sysoev.ru 
108110Sigor@sysoev.ru     length = jbs->addr.length;
108210Sigor@sysoev.ru     host = jbs->addr.start;
10830Sigor@sysoev.ru 
108410Sigor@sysoev.ru     p = nxt_memchr(host, ':', length);
10850Sigor@sysoev.ru 
10860Sigor@sysoev.ru     if (p == NULL) {
10870Sigor@sysoev.ru 
10880Sigor@sysoev.ru         /* single value port, address, or host name */
10890Sigor@sysoev.ru 
109010Sigor@sysoev.ru         port = nxt_int_parse(host, length);
10910Sigor@sysoev.ru 
10920Sigor@sysoev.ru         if (port > 0) {
1093*2141Sandrew@digital-domain.net             if (port > 65535) {
10940Sigor@sysoev.ru                 goto invalid_port;
10950Sigor@sysoev.ru             }
10960Sigor@sysoev.ru 
10970Sigor@sysoev.ru             /* "*:XX" */
10980Sigor@sysoev.ru             port = htons((in_port_t) port);
10990Sigor@sysoev.ru             jbs->resolve.port = (in_port_t) port;
11000Sigor@sysoev.ru 
11010Sigor@sysoev.ru         } else {
11020Sigor@sysoev.ru             jbs->no_port = 1;
11030Sigor@sysoev.ru 
110410Sigor@sysoev.ru             addr = nxt_inet_addr(host, length);
11050Sigor@sysoev.ru 
11060Sigor@sysoev.ru             if (addr == INADDR_NONE) {
110710Sigor@sysoev.ru                 jbs->resolve.name.length = length;
110810Sigor@sysoev.ru                 jbs->resolve.name.start = host;
11090Sigor@sysoev.ru 
11100Sigor@sysoev.ru                 nxt_job_resolve(&jbs->resolve);
11110Sigor@sysoev.ru                 return NXT_AGAIN;
11120Sigor@sysoev.ru             }
11130Sigor@sysoev.ru 
11140Sigor@sysoev.ru             /* "x.x.x.x" */
11150Sigor@sysoev.ru             port = jbs->resolve.port;
11160Sigor@sysoev.ru         }
11170Sigor@sysoev.ru 
11180Sigor@sysoev.ru     } else {
11190Sigor@sysoev.ru 
11200Sigor@sysoev.ru         /* x.x.x.x:XX or host:XX */
11210Sigor@sysoev.ru 
11220Sigor@sysoev.ru         p++;
112310Sigor@sysoev.ru         length = (host + length) - p;
112410Sigor@sysoev.ru         port = nxt_int_parse(p, length);
11250Sigor@sysoev.ru 
11260Sigor@sysoev.ru         if (port < 1 || port > 65535) {
11270Sigor@sysoev.ru             goto invalid_port;
11280Sigor@sysoev.ru         }
11290Sigor@sysoev.ru 
11300Sigor@sysoev.ru         port = htons((in_port_t) port);
11310Sigor@sysoev.ru 
113210Sigor@sysoev.ru         length = (p - 1) - host;
11330Sigor@sysoev.ru 
113410Sigor@sysoev.ru         if (length != 1 || host[0] != '*') {
113510Sigor@sysoev.ru             addr = nxt_inet_addr(host, length);
11360Sigor@sysoev.ru 
11370Sigor@sysoev.ru             if (addr == INADDR_NONE) {
113810Sigor@sysoev.ru                 jbs->resolve.name.length = length;
113910Sigor@sysoev.ru                 jbs->resolve.name.start = host;
11400Sigor@sysoev.ru                 jbs->resolve.port = (in_port_t) port;
11410Sigor@sysoev.ru 
11420Sigor@sysoev.ru                 nxt_job_resolve(&jbs->resolve);
11430Sigor@sysoev.ru                 return NXT_AGAIN;
11440Sigor@sysoev.ru             }
11450Sigor@sysoev.ru 
11460Sigor@sysoev.ru             /* "x.x.x.x:XX" */
11470Sigor@sysoev.ru         }
11480Sigor@sysoev.ru     }
11490Sigor@sysoev.ru 
11500Sigor@sysoev.ru     mp = jbs->resolve.job.mem_pool;
11510Sigor@sysoev.ru 
115265Sigor@sysoev.ru     jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *));
11530Sigor@sysoev.ru     if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) {
11540Sigor@sysoev.ru         return NXT_ERROR;
11550Sigor@sysoev.ru     }
11560Sigor@sysoev.ru 
115713Sigor@sysoev.ru     sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in),
115813Sigor@sysoev.ru                             NXT_INET_ADDR_STR_LEN);
11590Sigor@sysoev.ru 
11600Sigor@sysoev.ru     if (nxt_fast_path(sa != NULL)) {
11610Sigor@sysoev.ru         jbs->resolve.count = 1;
11620Sigor@sysoev.ru         jbs->resolve.sockaddrs[0] = sa;
11630Sigor@sysoev.ru 
11640Sigor@sysoev.ru         jbs->wildcard = (addr == INADDR_ANY);
11650Sigor@sysoev.ru 
11660Sigor@sysoev.ru         sa->u.sockaddr_in.sin_family = AF_INET;
11670Sigor@sysoev.ru         sa->u.sockaddr_in.sin_port = (in_port_t) port;
11680Sigor@sysoev.ru         sa->u.sockaddr_in.sin_addr.s_addr = addr;
11690Sigor@sysoev.ru 
11700Sigor@sysoev.ru         return NXT_OK;
11710Sigor@sysoev.ru     }
11720Sigor@sysoev.ru 
11730Sigor@sysoev.ru     return NXT_ERROR;
11740Sigor@sysoev.ru 
11750Sigor@sysoev.ru invalid_port:
11760Sigor@sysoev.ru 
11770Sigor@sysoev.ru     nxt_thread_log_error(jbs->resolve.log_level,
11780Sigor@sysoev.ru                          "invalid port in \"%V\"", &jbs->addr);
11790Sigor@sysoev.ru 
11800Sigor@sysoev.ru     return NXT_ERROR;
11810Sigor@sysoev.ru }
11820Sigor@sysoev.ru 
11830S