xref: /unit/src/nxt_sockaddr.c (revision 65)
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 
140Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs);
150Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs);
160Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs);
170Sigor@sysoev.ru 
180Sigor@sysoev.ru 
190Sigor@sysoev.ru nxt_sockaddr_t *
20*65Sigor@sysoev.ru nxt_sockaddr_alloc(nxt_mp_t *mp, socklen_t socklen, size_t address_length)
210Sigor@sysoev.ru {
2213Sigor@sysoev.ru     size_t          size;
230Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
240Sigor@sysoev.ru 
2513Sigor@sysoev.ru     size = offsetof(nxt_sockaddr_t, u) + socklen + address_length;
2613Sigor@sysoev.ru 
270Sigor@sysoev.ru     /*
280Sigor@sysoev.ru      * The current struct sockaddr's define 32-bit fields at maximum
290Sigor@sysoev.ru      * and may define 64-bit AF_INET6 fields in the future.  Alignment
30*65Sigor@sysoev.ru      * of memory allocated by nxt_mp_zalloc() is enough for these fields.
310Sigor@sysoev.ru      * If 128-bit alignment will be required then nxt_mem_malloc() and
320Sigor@sysoev.ru      * nxt_memzero() should be used instead.
330Sigor@sysoev.ru      */
3413Sigor@sysoev.ru 
35*65Sigor@sysoev.ru     sa = nxt_mp_zalloc(mp, size);
360Sigor@sysoev.ru 
370Sigor@sysoev.ru     if (nxt_fast_path(sa != NULL)) {
3813Sigor@sysoev.ru         sa->socklen = socklen;
3913Sigor@sysoev.ru         sa->length = address_length;
4013Sigor@sysoev.ru         sa->sockaddr_size = size;
410Sigor@sysoev.ru     }
420Sigor@sysoev.ru 
430Sigor@sysoev.ru     return sa;
440Sigor@sysoev.ru }
450Sigor@sysoev.ru 
460Sigor@sysoev.ru 
470Sigor@sysoev.ru nxt_sockaddr_t *
48*65Sigor@sysoev.ru nxt_sockaddr_create(nxt_mp_t *mp, struct sockaddr *sockaddr, socklen_t length,
49*65Sigor@sysoev.ru     size_t address_length)
500Sigor@sysoev.ru {
510Sigor@sysoev.ru     size_t          size, copy;
520Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
530Sigor@sysoev.ru 
5410Sigor@sysoev.ru     size = length;
5510Sigor@sysoev.ru     copy = length;
560Sigor@sysoev.ru 
570Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
580Sigor@sysoev.ru 
590Sigor@sysoev.ru     /*
600Sigor@sysoev.ru      * Unspecified Unix domain sockaddr_un form and length are very
610Sigor@sysoev.ru      * platform depended (see comment in unix/socket.h).  Here they are
620Sigor@sysoev.ru      * normalized to the sockaddr_un with single zero byte sun_path[].
630Sigor@sysoev.ru      */
640Sigor@sysoev.ru 
650Sigor@sysoev.ru     if (size <= offsetof(struct sockaddr_un, sun_path)) {
660Sigor@sysoev.ru         /*
670Sigor@sysoev.ru          * Small socket length means a short unspecified Unix domain
680Sigor@sysoev.ru          * socket address:
690Sigor@sysoev.ru          *
700Sigor@sysoev.ru          *   getsockname() and getpeername() on OpenBSD prior to 5.3
710Sigor@sysoev.ru          *   return zero length and does not update a passed sockaddr
720Sigor@sysoev.ru          *   buffer at all.
730Sigor@sysoev.ru          *
740Sigor@sysoev.ru          *   Linux returns length equal to 2, i.e. sockaddr_un without
750Sigor@sysoev.ru          *   sun_path[], unix(7):
760Sigor@sysoev.ru          *
770Sigor@sysoev.ru          *     unnamed: A stream socket that has not been bound
780Sigor@sysoev.ru          *     to a pathname using bind(2) has no name.  Likewise,
790Sigor@sysoev.ru          *     the two sockets created by socketpair(2) are unnamed.
800Sigor@sysoev.ru          *     When the address of an unnamed socket is returned by
810Sigor@sysoev.ru          *     getsockname(2), getpeername(2), and accept(2), its
820Sigor@sysoev.ru          *     length is sizeof(sa_family_t), and sun_path should
830Sigor@sysoev.ru          *     not be inspected.
840Sigor@sysoev.ru          */
850Sigor@sysoev.ru         size = offsetof(struct sockaddr_un, sun_path) + 1;
860Sigor@sysoev.ru 
870Sigor@sysoev.ru #if !(NXT_LINUX)
880Sigor@sysoev.ru 
890Sigor@sysoev.ru     } else if (sockaddr->sa_family == AF_UNIX && sockaddr->sa_data[0] == '\0') {
900Sigor@sysoev.ru         /*
910Sigor@sysoev.ru          * Omit nonsignificant zeros of the unspecified Unix domain socket
920Sigor@sysoev.ru          * address.  This test is disabled for Linux since Linux abstract
930Sigor@sysoev.ru          * socket address also starts with zero.  However Linux unspecified
940Sigor@sysoev.ru          * Unix domain socket address is short and is handled above.
950Sigor@sysoev.ru          */
960Sigor@sysoev.ru         size = offsetof(struct sockaddr_un, sun_path) + 1;
970Sigor@sysoev.ru         copy = size;
980Sigor@sysoev.ru 
990Sigor@sysoev.ru #endif
1000Sigor@sysoev.ru     }
1010Sigor@sysoev.ru 
1020Sigor@sysoev.ru #endif  /* NXT_HAVE_UNIX_DOMAIN */
1030Sigor@sysoev.ru 
10413Sigor@sysoev.ru     sa = nxt_sockaddr_alloc(mp, size, address_length);
1050Sigor@sysoev.ru 
1060Sigor@sysoev.ru     if (nxt_fast_path(sa != NULL)) {
1070Sigor@sysoev.ru         nxt_memcpy(&sa->u.sockaddr, sockaddr, copy);
1080Sigor@sysoev.ru 
1090Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN && NXT_OPENBSD)
1100Sigor@sysoev.ru 
11110Sigor@sysoev.ru         if (length == 0) {
1120Sigor@sysoev.ru             sa->u.sockaddr.sa_family = AF_UNIX;
1130Sigor@sysoev.ru         }
1140Sigor@sysoev.ru 
1150Sigor@sysoev.ru #endif
1160Sigor@sysoev.ru     }
1170Sigor@sysoev.ru 
1180Sigor@sysoev.ru     return sa;
1190Sigor@sysoev.ru }
1200Sigor@sysoev.ru 
1210Sigor@sysoev.ru 
1220Sigor@sysoev.ru nxt_sockaddr_t *
123*65Sigor@sysoev.ru nxt_sockaddr_copy(nxt_mp_t *mp, nxt_sockaddr_t *src)
1240Sigor@sysoev.ru {
12510Sigor@sysoev.ru     size_t          length;
1260Sigor@sysoev.ru     nxt_sockaddr_t  *dst;
1270Sigor@sysoev.ru 
12813Sigor@sysoev.ru     length = offsetof(nxt_sockaddr_t, u) + src->socklen;
1290Sigor@sysoev.ru 
130*65Sigor@sysoev.ru     dst = nxt_mp_alloc(mp, length);
1310Sigor@sysoev.ru 
1320Sigor@sysoev.ru     if (nxt_fast_path(dst != NULL)) {
13310Sigor@sysoev.ru         nxt_memcpy(dst, src, length);
1340Sigor@sysoev.ru     }
1350Sigor@sysoev.ru 
1360Sigor@sysoev.ru     return dst;
1370Sigor@sysoev.ru }
1380Sigor@sysoev.ru 
1390Sigor@sysoev.ru 
1400Sigor@sysoev.ru nxt_sockaddr_t *
141*65Sigor@sysoev.ru nxt_getsockname(nxt_task_t *task, nxt_mp_t *mp, nxt_socket_t s)
1420Sigor@sysoev.ru {
1430Sigor@sysoev.ru     int                 ret;
14413Sigor@sysoev.ru     size_t              length;
1450Sigor@sysoev.ru     socklen_t           socklen;
1460Sigor@sysoev.ru     nxt_sockaddr_buf_t  sockaddr;
1470Sigor@sysoev.ru 
1480Sigor@sysoev.ru     socklen = NXT_SOCKADDR_LEN;
1490Sigor@sysoev.ru 
1500Sigor@sysoev.ru     ret = getsockname(s, &sockaddr.buf, &socklen);
1510Sigor@sysoev.ru 
1520Sigor@sysoev.ru     if (nxt_fast_path(ret == 0)) {
15313Sigor@sysoev.ru 
15413Sigor@sysoev.ru         switch (sockaddr.buf.sa_family) {
15513Sigor@sysoev.ru #if (NXT_INET6)
15613Sigor@sysoev.ru         case AF_INET6:
15713Sigor@sysoev.ru              length = NXT_INET6_ADDR_STR_LEN;
15813Sigor@sysoev.ru              break;
15913Sigor@sysoev.ru #endif
16013Sigor@sysoev.ru 
16113Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
16213Sigor@sysoev.ru         case AF_UNIX:
16313Sigor@sysoev.ru              length = sizeof("unix:") - 1 + socklen;
16413Sigor@sysoev.ru #endif
16513Sigor@sysoev.ru              break;
16613Sigor@sysoev.ru 
16713Sigor@sysoev.ru         case AF_INET:
16813Sigor@sysoev.ru              length = NXT_INET_ADDR_STR_LEN;
16913Sigor@sysoev.ru              break;
17013Sigor@sysoev.ru 
17113Sigor@sysoev.ru         default:
17213Sigor@sysoev.ru              length = 0;
17313Sigor@sysoev.ru              break;
17413Sigor@sysoev.ru         }
17513Sigor@sysoev.ru 
17613Sigor@sysoev.ru         return nxt_sockaddr_create(mp, &sockaddr.buf, socklen, length);
1770Sigor@sysoev.ru     }
1780Sigor@sysoev.ru 
17913Sigor@sysoev.ru     nxt_log(task, NXT_LOG_ERR, "getsockname(%d) failed %E", s, nxt_errno);
1800Sigor@sysoev.ru 
1810Sigor@sysoev.ru     return NULL;
1820Sigor@sysoev.ru }
1830Sigor@sysoev.ru 
1840Sigor@sysoev.ru 
18513Sigor@sysoev.ru void
18613Sigor@sysoev.ru nxt_sockaddr_text(nxt_sockaddr_t *sa)
1870Sigor@sysoev.ru {
18813Sigor@sysoev.ru     size_t    offset;
18913Sigor@sysoev.ru     u_char    *p, *start, *end, *octet;
19013Sigor@sysoev.ru     uint32_t  port;
19113Sigor@sysoev.ru 
19213Sigor@sysoev.ru     end = (u_char *) sa + sa->sockaddr_size;
19313Sigor@sysoev.ru 
19413Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
19513Sigor@sysoev.ru 
19613Sigor@sysoev.ru     case AF_INET:
19713Sigor@sysoev.ru         offset = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in);
19813Sigor@sysoev.ru 
19913Sigor@sysoev.ru         sa->start = offset;
20013Sigor@sysoev.ru         sa->address_start = offset;
20113Sigor@sysoev.ru 
20213Sigor@sysoev.ru         start = (u_char *) sa + offset;
20313Sigor@sysoev.ru         octet = (u_char *) &sa->u.sockaddr_in.sin_addr;
20413Sigor@sysoev.ru 
20513Sigor@sysoev.ru         p = nxt_sprintf(start, end, "%ud.%ud.%ud.%ud",
20613Sigor@sysoev.ru                         octet[0], octet[1], octet[2], octet[3]);
20713Sigor@sysoev.ru 
20813Sigor@sysoev.ru         sa->address_length = p - start;
20913Sigor@sysoev.ru         sa->port_start = sa->address_length + 1;
2100Sigor@sysoev.ru 
21113Sigor@sysoev.ru         port = sa->u.sockaddr_in.sin_port;
21213Sigor@sysoev.ru 
21313Sigor@sysoev.ru         break;
21413Sigor@sysoev.ru 
21513Sigor@sysoev.ru #if (NXT_INET6)
21613Sigor@sysoev.ru 
21713Sigor@sysoev.ru     case AF_INET6:
21813Sigor@sysoev.ru         offset = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in6);
21913Sigor@sysoev.ru 
22013Sigor@sysoev.ru         sa->start = offset;
22113Sigor@sysoev.ru         sa->address_start = offset;
22213Sigor@sysoev.ru 
22313Sigor@sysoev.ru         start = (u_char *) sa + offset;
22413Sigor@sysoev.ru         p = start;
22513Sigor@sysoev.ru 
22613Sigor@sysoev.ru         *p++ = '[';
22713Sigor@sysoev.ru 
22813Sigor@sysoev.ru         p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end);
22913Sigor@sysoev.ru 
23013Sigor@sysoev.ru         sa->address_length = p - (start + 1);
23113Sigor@sysoev.ru         sa->port_start = sa->address_length + 2;
23220Sigor@sysoev.ru 
23313Sigor@sysoev.ru         *p++ = ']';
2340Sigor@sysoev.ru 
23513Sigor@sysoev.ru         port = sa->u.sockaddr_in6.sin6_port;
23613Sigor@sysoev.ru 
23713Sigor@sysoev.ru         break;
23813Sigor@sysoev.ru 
23913Sigor@sysoev.ru #endif
24013Sigor@sysoev.ru 
24113Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
24213Sigor@sysoev.ru 
24313Sigor@sysoev.ru     case AF_UNIX:
24413Sigor@sysoev.ru 
24513Sigor@sysoev.ru         offset = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_un);
2460Sigor@sysoev.ru 
24713Sigor@sysoev.ru         sa->start = offset;
24813Sigor@sysoev.ru         sa->address_start = offset;
24913Sigor@sysoev.ru 
25013Sigor@sysoev.ru         start = (u_char *) sa + offset;
25113Sigor@sysoev.ru         p = start;
2520Sigor@sysoev.ru 
25313Sigor@sysoev.ru #if (NXT_LINUX)
25413Sigor@sysoev.ru 
25513Sigor@sysoev.ru         p = (u_char *) sa->u.sockaddr_un.sun_path;
25613Sigor@sysoev.ru 
25713Sigor@sysoev.ru         if (p[0] == '\0') {
25813Sigor@sysoev.ru             int  length;
2590Sigor@sysoev.ru 
26013Sigor@sysoev.ru             /* Linux abstract socket address has no trailing zero. */
26113Sigor@sysoev.ru             length = sa->socklen - offsetof(struct sockaddr_un, sun_path);
26213Sigor@sysoev.ru 
26313Sigor@sysoev.ru             p = nxt_sprintf(start, end, "unix:@%*s", length - 1, p + 1);
26413Sigor@sysoev.ru 
26513Sigor@sysoev.ru         } else {
26613Sigor@sysoev.ru             p = nxt_sprintf(start, end, "unix:%s", p);
26713Sigor@sysoev.ru         }
26813Sigor@sysoev.ru 
26913Sigor@sysoev.ru #else  /* !(NXT_LINUX) */
27013Sigor@sysoev.ru 
27113Sigor@sysoev.ru         p = nxt_sprintf(start, end, "unix:%s", p);
2720Sigor@sysoev.ru 
27313Sigor@sysoev.ru #endif
27413Sigor@sysoev.ru 
27513Sigor@sysoev.ru         sa->address_length = p - start;
27613Sigor@sysoev.ru         sa->port_start = sa->address_length;
27713Sigor@sysoev.ru         sa->length = p - start;
27813Sigor@sysoev.ru 
27913Sigor@sysoev.ru         return;
28013Sigor@sysoev.ru 
28113Sigor@sysoev.ru #endif  /* NXT_HAVE_UNIX_DOMAIN */
28213Sigor@sysoev.ru 
28313Sigor@sysoev.ru     default:
28413Sigor@sysoev.ru         return;
2850Sigor@sysoev.ru     }
2860Sigor@sysoev.ru 
28713Sigor@sysoev.ru     p = nxt_sprintf(p, end, ":%d", ntohs(port));
28813Sigor@sysoev.ru 
28913Sigor@sysoev.ru     sa->length = p - start;
2900Sigor@sysoev.ru }
2910Sigor@sysoev.ru 
2920Sigor@sysoev.ru 
2930Sigor@sysoev.ru uint32_t
29413Sigor@sysoev.ru nxt_sockaddr_port_number(nxt_sockaddr_t *sa)
2950Sigor@sysoev.ru {
2960Sigor@sysoev.ru     uint32_t  port;
2970Sigor@sysoev.ru 
2980Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
2990Sigor@sysoev.ru 
3000Sigor@sysoev.ru #if (NXT_INET6)
3010Sigor@sysoev.ru 
3020Sigor@sysoev.ru     case AF_INET6:
3030Sigor@sysoev.ru         port = sa->u.sockaddr_in6.sin6_port;
3040Sigor@sysoev.ru         break;
3050Sigor@sysoev.ru 
3060Sigor@sysoev.ru #endif
3070Sigor@sysoev.ru 
3080Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
3090Sigor@sysoev.ru 
3100Sigor@sysoev.ru     case AF_UNIX:
3110Sigor@sysoev.ru         return 0;
3120Sigor@sysoev.ru 
3130Sigor@sysoev.ru #endif
3140Sigor@sysoev.ru 
3150Sigor@sysoev.ru     default:
3160Sigor@sysoev.ru         port = sa->u.sockaddr_in.sin_port;
3170Sigor@sysoev.ru         break;
3180Sigor@sysoev.ru     }
3190Sigor@sysoev.ru 
3200Sigor@sysoev.ru     return ntohs((uint16_t) port);
3210Sigor@sysoev.ru }
3220Sigor@sysoev.ru 
3230Sigor@sysoev.ru 
3240Sigor@sysoev.ru nxt_bool_t
3250Sigor@sysoev.ru nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, nxt_sockaddr_t *sa2)
3260Sigor@sysoev.ru {
32713Sigor@sysoev.ru     if (sa1->socklen != sa2->socklen) {
3280Sigor@sysoev.ru         return 0;
3290Sigor@sysoev.ru     }
3300Sigor@sysoev.ru 
3310Sigor@sysoev.ru     if (sa1->type != sa2->type) {
3320Sigor@sysoev.ru         return 0;
3330Sigor@sysoev.ru     }
3340Sigor@sysoev.ru 
3350Sigor@sysoev.ru     if (sa1->u.sockaddr.sa_family != sa2->u.sockaddr.sa_family) {
3360Sigor@sysoev.ru         return 0;
3370Sigor@sysoev.ru     }
3380Sigor@sysoev.ru 
3390Sigor@sysoev.ru     /*
3400Sigor@sysoev.ru      * sockaddr struct's cannot be compared in whole since kernel
3410Sigor@sysoev.ru      * may fill some fields in inherited sockaddr struct's.
3420Sigor@sysoev.ru      */
3430Sigor@sysoev.ru 
3440Sigor@sysoev.ru     switch (sa1->u.sockaddr.sa_family) {
3450Sigor@sysoev.ru 
3460Sigor@sysoev.ru #if (NXT_INET6)
3470Sigor@sysoev.ru 
3480Sigor@sysoev.ru     case AF_INET6:
3490Sigor@sysoev.ru         if (sa1->u.sockaddr_in6.sin6_port != sa2->u.sockaddr_in6.sin6_port) {
3500Sigor@sysoev.ru             return 0;
3510Sigor@sysoev.ru         }
3520Sigor@sysoev.ru 
3530Sigor@sysoev.ru         if (nxt_memcmp(&sa1->u.sockaddr_in6.sin6_addr,
3540Sigor@sysoev.ru                        &sa2->u.sockaddr_in6.sin6_addr, 16)
3550Sigor@sysoev.ru             != 0)
3560Sigor@sysoev.ru         {
3570Sigor@sysoev.ru             return 0;
3580Sigor@sysoev.ru         }
3590Sigor@sysoev.ru 
3600Sigor@sysoev.ru         return 1;
3610Sigor@sysoev.ru 
3620Sigor@sysoev.ru #endif
3630Sigor@sysoev.ru 
3640Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
3650Sigor@sysoev.ru 
3660Sigor@sysoev.ru     case AF_UNIX:
3670Sigor@sysoev.ru         {
36810Sigor@sysoev.ru             size_t  length;
3690Sigor@sysoev.ru 
37013Sigor@sysoev.ru             length = sa1->socklen - offsetof(struct sockaddr_un, sun_path);
3710Sigor@sysoev.ru 
3720Sigor@sysoev.ru             if (nxt_memcmp(&sa1->u.sockaddr_un.sun_path,
37310Sigor@sysoev.ru                            &sa2->u.sockaddr_un.sun_path, length)
3740Sigor@sysoev.ru                 != 0)
3750Sigor@sysoev.ru             {
3760Sigor@sysoev.ru                 return 0;
3770Sigor@sysoev.ru             }
3780Sigor@sysoev.ru 
3790Sigor@sysoev.ru             return 1;
3800Sigor@sysoev.ru         }
3810Sigor@sysoev.ru 
3820Sigor@sysoev.ru #endif
3830Sigor@sysoev.ru 
3840Sigor@sysoev.ru     default: /* AF_INET */
3850Sigor@sysoev.ru         if (sa1->u.sockaddr_in.sin_port != sa2->u.sockaddr_in.sin_port) {
3860Sigor@sysoev.ru             return 0;
3870Sigor@sysoev.ru         }
3880Sigor@sysoev.ru 
3890Sigor@sysoev.ru         if (sa1->u.sockaddr_in.sin_addr.s_addr
3900Sigor@sysoev.ru             != sa2->u.sockaddr_in.sin_addr.s_addr)
3910Sigor@sysoev.ru         {
3920Sigor@sysoev.ru             return 0;
3930Sigor@sysoev.ru         }
3940Sigor@sysoev.ru 
3950Sigor@sysoev.ru         return 1;
3960Sigor@sysoev.ru     }
3970Sigor@sysoev.ru }
3980Sigor@sysoev.ru 
3990Sigor@sysoev.ru 
4000Sigor@sysoev.ru size_t
4010Sigor@sysoev.ru nxt_sockaddr_ntop(nxt_sockaddr_t *sa, u_char *buf, u_char *end, nxt_bool_t port)
4020Sigor@sysoev.ru {
4030Sigor@sysoev.ru     u_char  *p;
4040Sigor@sysoev.ru 
4050Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
4060Sigor@sysoev.ru 
4070Sigor@sysoev.ru     case AF_INET:
4080Sigor@sysoev.ru         p = (u_char *) &sa->u.sockaddr_in.sin_addr;
4090Sigor@sysoev.ru 
4100Sigor@sysoev.ru         if (port) {
4110Sigor@sysoev.ru             p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud:%d",
4120Sigor@sysoev.ru                             p[0], p[1], p[2], p[3],
4130Sigor@sysoev.ru                             ntohs(sa->u.sockaddr_in.sin_port));
4140Sigor@sysoev.ru         } else {
4150Sigor@sysoev.ru             p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud",
4160Sigor@sysoev.ru                             p[0], p[1], p[2], p[3]);
4170Sigor@sysoev.ru         }
4180Sigor@sysoev.ru 
4190Sigor@sysoev.ru         return p - buf;
4200Sigor@sysoev.ru 
4210Sigor@sysoev.ru #if (NXT_INET6)
4220Sigor@sysoev.ru 
4230Sigor@sysoev.ru     case AF_INET6:
4240Sigor@sysoev.ru         p = buf;
4250Sigor@sysoev.ru 
4260Sigor@sysoev.ru         if (port) {
4270Sigor@sysoev.ru             *p++ = '[';
4280Sigor@sysoev.ru         }
4290Sigor@sysoev.ru 
4300Sigor@sysoev.ru         p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end);
4310Sigor@sysoev.ru 
4320Sigor@sysoev.ru         if (port) {
4330Sigor@sysoev.ru             p = nxt_sprintf(p, end, "]:%d",
4340Sigor@sysoev.ru                             ntohs(sa->u.sockaddr_in6.sin6_port));
4350Sigor@sysoev.ru         }
4360Sigor@sysoev.ru 
4370Sigor@sysoev.ru         return p - buf;
4380Sigor@sysoev.ru #endif
4390Sigor@sysoev.ru 
4400Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
4410Sigor@sysoev.ru 
4420Sigor@sysoev.ru     case AF_UNIX:
4430Sigor@sysoev.ru 
4440Sigor@sysoev.ru #if (NXT_LINUX)
4450Sigor@sysoev.ru 
4460Sigor@sysoev.ru         p = (u_char *) sa->u.sockaddr_un.sun_path;
4470Sigor@sysoev.ru 
4480Sigor@sysoev.ru         if (p[0] == '\0') {
44910Sigor@sysoev.ru             int  length;
4500Sigor@sysoev.ru 
4510Sigor@sysoev.ru             /* Linux abstract socket address has no trailing zero. */
4520Sigor@sysoev.ru 
45313Sigor@sysoev.ru             length = sa->socklen - offsetof(struct sockaddr_un, sun_path) - 1;
45410Sigor@sysoev.ru             p = nxt_sprintf(buf, end, "unix:\\0%*s", length, p + 1);
4550Sigor@sysoev.ru 
4560Sigor@sysoev.ru         } else {
4570Sigor@sysoev.ru             p = nxt_sprintf(buf, end, "unix:%s", p);
4580Sigor@sysoev.ru         }
4590Sigor@sysoev.ru 
4600Sigor@sysoev.ru #else  /* !(NXT_LINUX) */
4610Sigor@sysoev.ru 
4620Sigor@sysoev.ru         p = nxt_sprintf(buf, end, "unix:%s", sa->u.sockaddr_un.sun_path);
4630Sigor@sysoev.ru 
4640Sigor@sysoev.ru #endif
4650Sigor@sysoev.ru 
4660Sigor@sysoev.ru         return p - buf;
4670Sigor@sysoev.ru 
4680Sigor@sysoev.ru #endif  /* NXT_HAVE_UNIX_DOMAIN */
4690Sigor@sysoev.ru 
4700Sigor@sysoev.ru     default:
4710Sigor@sysoev.ru         return 0;
4720Sigor@sysoev.ru     }
4730Sigor@sysoev.ru }
4740Sigor@sysoev.ru 
4750Sigor@sysoev.ru 
4760Sigor@sysoev.ru #if (NXT_INET6)
4770Sigor@sysoev.ru 
4780Sigor@sysoev.ru static u_char *
4790Sigor@sysoev.ru nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end)
4800Sigor@sysoev.ru {
4810Sigor@sysoev.ru     u_char      *p;
4820Sigor@sysoev.ru     size_t      zero_groups, last_zero_groups, ipv6_bytes;
4830Sigor@sysoev.ru     nxt_uint_t  i, zero_start, last_zero_start;
4840Sigor@sysoev.ru 
4850Sigor@sysoev.ru     if (buf + NXT_INET6_ADDR_STR_LEN > end) {
4860Sigor@sysoev.ru         return buf;
4870Sigor@sysoev.ru     }
4880Sigor@sysoev.ru 
4890Sigor@sysoev.ru     zero_start = 8;
4900Sigor@sysoev.ru     zero_groups = 0;
4910Sigor@sysoev.ru     last_zero_start = 8;
4920Sigor@sysoev.ru     last_zero_groups = 0;
4930Sigor@sysoev.ru 
4940Sigor@sysoev.ru     for (i = 0; i < 16; i += 2) {
4950Sigor@sysoev.ru 
4960Sigor@sysoev.ru         if (addr[i] == 0 && addr[i + 1] == 0) {
4970Sigor@sysoev.ru 
4980Sigor@sysoev.ru             if (last_zero_groups == 0) {
4990Sigor@sysoev.ru                 last_zero_start = i;
5000Sigor@sysoev.ru             }
5010Sigor@sysoev.ru 
5020Sigor@sysoev.ru             last_zero_groups++;
5030Sigor@sysoev.ru 
5040Sigor@sysoev.ru         } else {
5050Sigor@sysoev.ru             if (zero_groups < last_zero_groups) {
5060Sigor@sysoev.ru                 zero_groups = last_zero_groups;
5070Sigor@sysoev.ru                 zero_start = last_zero_start;
5080Sigor@sysoev.ru             }
5090Sigor@sysoev.ru 
5100Sigor@sysoev.ru             last_zero_groups = 0;
5110Sigor@sysoev.ru         }
5120Sigor@sysoev.ru     }
5130Sigor@sysoev.ru 
5140Sigor@sysoev.ru     if (zero_groups < last_zero_groups) {
5150Sigor@sysoev.ru         zero_groups = last_zero_groups;
5160Sigor@sysoev.ru         zero_start = last_zero_start;
5170Sigor@sysoev.ru     }
5180Sigor@sysoev.ru 
5190Sigor@sysoev.ru     ipv6_bytes = 16;
5200Sigor@sysoev.ru     p = buf;
5210Sigor@sysoev.ru 
5220Sigor@sysoev.ru     if (zero_start == 0) {
5230Sigor@sysoev.ru 
5240Sigor@sysoev.ru                /* IPv4-mapped address */
5250Sigor@sysoev.ru         if ((zero_groups == 5 && addr[10] == 0xff && addr[11] == 0xff)
5260Sigor@sysoev.ru                /* IPv4-compatible address */
5270Sigor@sysoev.ru             || (zero_groups == 6)
5280Sigor@sysoev.ru                /* not IPv6 loopback address */
5290Sigor@sysoev.ru             || (zero_groups == 7 && addr[14] != 0 && addr[15] != 1))
5300Sigor@sysoev.ru         {
5310Sigor@sysoev.ru             ipv6_bytes = 12;
5320Sigor@sysoev.ru         }
5330Sigor@sysoev.ru 
5340Sigor@sysoev.ru         *p++ = ':';
5350Sigor@sysoev.ru     }
5360Sigor@sysoev.ru 
5370Sigor@sysoev.ru     for (i = 0; i < ipv6_bytes; i += 2) {
5380Sigor@sysoev.ru 
5390Sigor@sysoev.ru         if (i == zero_start) {
5400Sigor@sysoev.ru             /* Output maximum number of consecutive zero groups as "::". */
5410Sigor@sysoev.ru             i += (zero_groups - 1) * 2;
5420Sigor@sysoev.ru             *p++ = ':';
5430Sigor@sysoev.ru             continue;
5440Sigor@sysoev.ru         }
5450Sigor@sysoev.ru 
5460Sigor@sysoev.ru         p = nxt_sprintf(p, end, "%uxd", (addr[i] << 8) + addr[i + 1]);
5470Sigor@sysoev.ru 
5480Sigor@sysoev.ru         if (i < 14) {
5490Sigor@sysoev.ru             *p++ = ':';
5500Sigor@sysoev.ru         }
5510Sigor@sysoev.ru     }
5520Sigor@sysoev.ru 
5530Sigor@sysoev.ru     if (ipv6_bytes == 12) {
5540Sigor@sysoev.ru         p = nxt_sprintf(p, end, "%ud.%ud.%ud.%ud",
5550Sigor@sysoev.ru                         addr[12], addr[13], addr[14], addr[15]);
5560Sigor@sysoev.ru     }
5570Sigor@sysoev.ru 
5580Sigor@sysoev.ru     return p;
5590Sigor@sysoev.ru }
5600Sigor@sysoev.ru 
5610Sigor@sysoev.ru #endif
5620Sigor@sysoev.ru 
5630Sigor@sysoev.ru 
5640Sigor@sysoev.ru void
5650Sigor@sysoev.ru nxt_job_sockaddr_parse(nxt_job_sockaddr_parse_t *jbs)
5660Sigor@sysoev.ru {
5670Sigor@sysoev.ru     u_char              *p;
56810Sigor@sysoev.ru     size_t              length;
5690Sigor@sysoev.ru     nxt_int_t           ret;
5700Sigor@sysoev.ru     nxt_work_handler_t  handler;
5710Sigor@sysoev.ru 
5720Sigor@sysoev.ru     nxt_job_set_name(&jbs->resolve.job, "job sockaddr parse");
5730Sigor@sysoev.ru 
57410Sigor@sysoev.ru     length = jbs->addr.length;
57510Sigor@sysoev.ru     p = jbs->addr.start;
5760Sigor@sysoev.ru 
57710Sigor@sysoev.ru     if (length > 6 && nxt_memcmp(p, (u_char *) "unix:", 5) == 0) {
5780Sigor@sysoev.ru         ret = nxt_job_sockaddr_unix_parse(jbs);
5790Sigor@sysoev.ru 
58010Sigor@sysoev.ru     } else if (length != 0 && *p == '[') {
5810Sigor@sysoev.ru         ret = nxt_job_sockaddr_inet6_parse(jbs);
5820Sigor@sysoev.ru 
5830Sigor@sysoev.ru     } else {
5840Sigor@sysoev.ru         ret = nxt_job_sockaddr_inet_parse(jbs);
5850Sigor@sysoev.ru     }
5860Sigor@sysoev.ru 
5870Sigor@sysoev.ru     switch (ret) {
5880Sigor@sysoev.ru 
5890Sigor@sysoev.ru     case NXT_OK:
5900Sigor@sysoev.ru         handler = jbs->resolve.ready_handler;
5910Sigor@sysoev.ru         break;
5920Sigor@sysoev.ru 
5930Sigor@sysoev.ru     case NXT_ERROR:
5940Sigor@sysoev.ru         handler = jbs->resolve.error_handler;
5950Sigor@sysoev.ru         break;
5960Sigor@sysoev.ru 
5970Sigor@sysoev.ru     default: /* NXT_AGAIN */
5980Sigor@sysoev.ru         return;
5990Sigor@sysoev.ru     }
6000Sigor@sysoev.ru 
6014Sigor@sysoev.ru     nxt_job_return(jbs->resolve.job.task, &jbs->resolve.job, handler);
6020Sigor@sysoev.ru }
6030Sigor@sysoev.ru 
6040Sigor@sysoev.ru 
6050Sigor@sysoev.ru static nxt_int_t
6060Sigor@sysoev.ru nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs)
6070Sigor@sysoev.ru {
6080Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
60910Sigor@sysoev.ru     size_t          length, socklen;
6100Sigor@sysoev.ru     u_char          *path;
611*65Sigor@sysoev.ru     nxt_mp_t        *mp;
6120Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
6130Sigor@sysoev.ru 
6140Sigor@sysoev.ru     /*
6150Sigor@sysoev.ru      * Actual sockaddr_un length can be lesser or even larger than defined
6160Sigor@sysoev.ru      * struct sockaddr_un length (see comment in unix/nxt_socket.h).  So
6170Sigor@sysoev.ru      * limit maximum Unix domain socket address length by defined sun_path[]
6180Sigor@sysoev.ru      * length because some OSes accept addresses twice larger than defined
6190Sigor@sysoev.ru      * struct sockaddr_un.  Also reserve space for a trailing zero to avoid
6200Sigor@sysoev.ru      * ambiguity, since many OSes accept Unix domain socket addresses
6210Sigor@sysoev.ru      * without a trailing zero.
6220Sigor@sysoev.ru      */
6230Sigor@sysoev.ru     const size_t max_len = sizeof(struct sockaddr_un)
6240Sigor@sysoev.ru                            - offsetof(struct sockaddr_un, sun_path) - 1;
6250Sigor@sysoev.ru 
6260Sigor@sysoev.ru     /* cutting "unix:" */
62710Sigor@sysoev.ru     length = jbs->addr.length - 5;
62810Sigor@sysoev.ru     path = jbs->addr.start + 5;
6290Sigor@sysoev.ru 
63010Sigor@sysoev.ru     if (length > max_len) {
6310Sigor@sysoev.ru         nxt_thread_log_error(jbs->resolve.log_level,
6320Sigor@sysoev.ru                              "unix domain socket \"%V\" name is too long",
6330Sigor@sysoev.ru                              &jbs->addr);
6340Sigor@sysoev.ru         return NXT_ERROR;
6350Sigor@sysoev.ru     }
6360Sigor@sysoev.ru 
63710Sigor@sysoev.ru     socklen = offsetof(struct sockaddr_un, sun_path) + length + 1;
6380Sigor@sysoev.ru 
6390Sigor@sysoev.ru #if (NXT_LINUX)
6400Sigor@sysoev.ru 
6410Sigor@sysoev.ru     /*
6420Sigor@sysoev.ru      * Linux unix(7):
6430Sigor@sysoev.ru      *
6440Sigor@sysoev.ru      *   abstract: an abstract socket address is distinguished by the fact
6450Sigor@sysoev.ru      *   that sun_path[0] is a null byte ('\0').  The socket's address in
6460Sigor@sysoev.ru      *   this namespace is given by the additional bytes in sun_path that
6470Sigor@sysoev.ru      *   are covered by the specified length of the address structure.
6480Sigor@sysoev.ru      *   (Null bytes in the name have no special significance.)
6490Sigor@sysoev.ru      */
6500Sigor@sysoev.ru     if (path[0] == '\0') {
6510Sigor@sysoev.ru         socklen--;
6520Sigor@sysoev.ru     }
6530Sigor@sysoev.ru 
6540Sigor@sysoev.ru #endif
6550Sigor@sysoev.ru 
6560Sigor@sysoev.ru     mp = jbs->resolve.job.mem_pool;
6570Sigor@sysoev.ru 
658*65Sigor@sysoev.ru     jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *));
6590Sigor@sysoev.ru 
6600Sigor@sysoev.ru     if (nxt_fast_path(jbs->resolve.sockaddrs != NULL)) {
66113Sigor@sysoev.ru         sa = nxt_sockaddr_alloc(mp, socklen, jbs->addr.length);
6620Sigor@sysoev.ru 
6630Sigor@sysoev.ru         if (nxt_fast_path(sa != NULL)) {
6640Sigor@sysoev.ru             jbs->resolve.count = 1;
6650Sigor@sysoev.ru             jbs->resolve.sockaddrs[0] = sa;
6660Sigor@sysoev.ru 
6670Sigor@sysoev.ru             sa->u.sockaddr_un.sun_family = AF_UNIX;
66810Sigor@sysoev.ru             nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length);
6690Sigor@sysoev.ru 
6700Sigor@sysoev.ru             return NXT_OK;
6710Sigor@sysoev.ru         }
6720Sigor@sysoev.ru     }
6730Sigor@sysoev.ru 
6740Sigor@sysoev.ru     return NXT_ERROR;
6750Sigor@sysoev.ru 
6760Sigor@sysoev.ru #else  /* !(NXT_HAVE_UNIX_DOMAIN) */
6770Sigor@sysoev.ru 
6780Sigor@sysoev.ru     nxt_thread_log_error(jbs->resolve.log_level,
6790Sigor@sysoev.ru                          "unix domain socket \"%V\" is not supported",
6800Sigor@sysoev.ru                          &jbs->addr);
6810Sigor@sysoev.ru     return NXT_ERROR;
6820Sigor@sysoev.ru 
6830Sigor@sysoev.ru #endif
6840Sigor@sysoev.ru }
6850Sigor@sysoev.ru 
6860Sigor@sysoev.ru 
6870Sigor@sysoev.ru static nxt_int_t
6880Sigor@sysoev.ru nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs)
6890Sigor@sysoev.ru {
6900Sigor@sysoev.ru #if (NXT_INET6)
6910Sigor@sysoev.ru     u_char           *p, *addr, *addr_end;
69210Sigor@sysoev.ru     size_t           length;
693*65Sigor@sysoev.ru     nxt_mp_t         *mp;
6940Sigor@sysoev.ru     nxt_int_t        port;
6950Sigor@sysoev.ru     nxt_sockaddr_t   *sa;
6960Sigor@sysoev.ru     struct in6_addr  *in6_addr;
6970Sigor@sysoev.ru 
69810Sigor@sysoev.ru     length = jbs->addr.length - 1;
69910Sigor@sysoev.ru     addr = jbs->addr.start + 1;
7000Sigor@sysoev.ru 
70110Sigor@sysoev.ru     addr_end = nxt_memchr(addr, ']', length);
7020Sigor@sysoev.ru 
7030Sigor@sysoev.ru     if (addr_end == NULL) {
7040Sigor@sysoev.ru         goto invalid_address;
7050Sigor@sysoev.ru     }
7060Sigor@sysoev.ru 
7070Sigor@sysoev.ru     mp = jbs->resolve.job.mem_pool;
7080Sigor@sysoev.ru 
709*65Sigor@sysoev.ru     jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *));
7100Sigor@sysoev.ru 
7110Sigor@sysoev.ru     if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) {
7120Sigor@sysoev.ru         return NXT_ERROR;
7130Sigor@sysoev.ru     }
7140Sigor@sysoev.ru 
7150Sigor@sysoev.ru     sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6));
7160Sigor@sysoev.ru 
7170Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
7180Sigor@sysoev.ru         return NXT_ERROR;
7190Sigor@sysoev.ru     }
7200Sigor@sysoev.ru 
7210Sigor@sysoev.ru     jbs->resolve.count = 1;
7220Sigor@sysoev.ru     jbs->resolve.sockaddrs[0] = sa;
7230Sigor@sysoev.ru 
7240Sigor@sysoev.ru     in6_addr = &sa->u.sockaddr_in6.sin6_addr;
7250Sigor@sysoev.ru 
7260Sigor@sysoev.ru     if (nxt_inet6_addr(in6_addr, addr, addr_end - addr) != NXT_OK) {
7270Sigor@sysoev.ru         goto invalid_address;
7280Sigor@sysoev.ru     }
7290Sigor@sysoev.ru 
7300Sigor@sysoev.ru     p = addr_end + 1;
73110Sigor@sysoev.ru     length = (addr + length) - p;
7320Sigor@sysoev.ru 
73310Sigor@sysoev.ru     if (length == 0) {
7340Sigor@sysoev.ru         jbs->no_port = 1;
7350Sigor@sysoev.ru         port = jbs->resolve.port;
7360Sigor@sysoev.ru         goto found;
7370Sigor@sysoev.ru     }
7380Sigor@sysoev.ru 
7390Sigor@sysoev.ru     if (*p == ':') {
74010Sigor@sysoev.ru         port = nxt_int_parse(p + 1, length - 1);
7410Sigor@sysoev.ru 
7420Sigor@sysoev.ru         if (port >= 1 && port <= 65535) {
7430Sigor@sysoev.ru             port = htons((in_port_t) port);
7440Sigor@sysoev.ru             goto found;
7450Sigor@sysoev.ru         }
7460Sigor@sysoev.ru     }
7470Sigor@sysoev.ru 
7480Sigor@sysoev.ru     nxt_thread_log_error(jbs->resolve.log_level,
7490Sigor@sysoev.ru                          "invalid port in \"%V\"", &jbs->addr);
7500Sigor@sysoev.ru 
7510Sigor@sysoev.ru     return NXT_ERROR;
7520Sigor@sysoev.ru 
7530Sigor@sysoev.ru found:
7540Sigor@sysoev.ru 
7550Sigor@sysoev.ru     sa->u.sockaddr_in6.sin6_family = AF_INET6;
7560Sigor@sysoev.ru     sa->u.sockaddr_in6.sin6_port = (in_port_t) port;
7570Sigor@sysoev.ru 
7580Sigor@sysoev.ru     if (IN6_IS_ADDR_UNSPECIFIED(in6_addr)) {
7590Sigor@sysoev.ru         jbs->wildcard = 1;
7600Sigor@sysoev.ru     }
7610Sigor@sysoev.ru 
7620Sigor@sysoev.ru     return NXT_OK;
7630Sigor@sysoev.ru 
7640Sigor@sysoev.ru invalid_address:
7650Sigor@sysoev.ru 
7660Sigor@sysoev.ru     nxt_thread_log_error(jbs->resolve.log_level,
7670Sigor@sysoev.ru                          "invalid IPv6 address in \"%V\"", &jbs->addr);
7680Sigor@sysoev.ru     return NXT_ERROR;
7690Sigor@sysoev.ru 
7700Sigor@sysoev.ru #else
7710Sigor@sysoev.ru 
7720Sigor@sysoev.ru     nxt_thread_log_error(jbs->resolve.log_level,
7730Sigor@sysoev.ru                          "IPv6 socket \"%V\" is not supported", &jbs->addr);
7740Sigor@sysoev.ru     return NXT_ERROR;
7750Sigor@sysoev.ru 
7760Sigor@sysoev.ru #endif
7770Sigor@sysoev.ru }
7780Sigor@sysoev.ru 
7790Sigor@sysoev.ru 
7800Sigor@sysoev.ru static nxt_int_t
7810Sigor@sysoev.ru nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs)
7820Sigor@sysoev.ru {
7830Sigor@sysoev.ru     u_char          *p, *host;
78410Sigor@sysoev.ru     size_t          length;
785*65Sigor@sysoev.ru     nxt_mp_t        *mp;
7860Sigor@sysoev.ru     nxt_int_t       port;
787*65Sigor@sysoev.ru     in_addr_t       addr;
7880Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
7890Sigor@sysoev.ru 
7900Sigor@sysoev.ru     addr = INADDR_ANY;
7910Sigor@sysoev.ru 
79210Sigor@sysoev.ru     length = jbs->addr.length;
79310Sigor@sysoev.ru     host = jbs->addr.start;
7940Sigor@sysoev.ru 
79510Sigor@sysoev.ru     p = nxt_memchr(host, ':', length);
7960Sigor@sysoev.ru 
7970Sigor@sysoev.ru     if (p == NULL) {
7980Sigor@sysoev.ru 
7990Sigor@sysoev.ru         /* single value port, address, or host name */
8000Sigor@sysoev.ru 
80110Sigor@sysoev.ru         port = nxt_int_parse(host, length);
8020Sigor@sysoev.ru 
8030Sigor@sysoev.ru         if (port > 0) {
8040Sigor@sysoev.ru             if (port < 1 || port > 65535) {
8050Sigor@sysoev.ru                 goto invalid_port;
8060Sigor@sysoev.ru             }
8070Sigor@sysoev.ru 
8080Sigor@sysoev.ru             /* "*:XX" */
8090Sigor@sysoev.ru             port = htons((in_port_t) port);
8100Sigor@sysoev.ru             jbs->resolve.port = (in_port_t) port;
8110Sigor@sysoev.ru 
8120Sigor@sysoev.ru         } else {
8130Sigor@sysoev.ru             jbs->no_port = 1;
8140Sigor@sysoev.ru 
81510Sigor@sysoev.ru             addr = nxt_inet_addr(host, length);
8160Sigor@sysoev.ru 
8170Sigor@sysoev.ru             if (addr == INADDR_NONE) {
81810Sigor@sysoev.ru                 jbs->resolve.name.length = length;
81910Sigor@sysoev.ru                 jbs->resolve.name.start = host;
8200Sigor@sysoev.ru 
8210Sigor@sysoev.ru                 nxt_job_resolve(&jbs->resolve);
8220Sigor@sysoev.ru                 return NXT_AGAIN;
8230Sigor@sysoev.ru             }
8240Sigor@sysoev.ru 
8250Sigor@sysoev.ru             /* "x.x.x.x" */
8260Sigor@sysoev.ru             port = jbs->resolve.port;
8270Sigor@sysoev.ru         }
8280Sigor@sysoev.ru 
8290Sigor@sysoev.ru     } else {
8300Sigor@sysoev.ru 
8310Sigor@sysoev.ru         /* x.x.x.x:XX or host:XX */
8320Sigor@sysoev.ru 
8330Sigor@sysoev.ru         p++;
83410Sigor@sysoev.ru         length = (host + length) - p;
83510Sigor@sysoev.ru         port = nxt_int_parse(p, length);
8360Sigor@sysoev.ru 
8370Sigor@sysoev.ru         if (port < 1 || port > 65535) {
8380Sigor@sysoev.ru             goto invalid_port;
8390Sigor@sysoev.ru         }
8400Sigor@sysoev.ru 
8410Sigor@sysoev.ru         port = htons((in_port_t) port);
8420Sigor@sysoev.ru 
84310Sigor@sysoev.ru         length = (p - 1) - host;
8440Sigor@sysoev.ru 
84510Sigor@sysoev.ru         if (length != 1 || host[0] != '*') {
84610Sigor@sysoev.ru             addr = nxt_inet_addr(host, length);
8470Sigor@sysoev.ru 
8480Sigor@sysoev.ru             if (addr == INADDR_NONE) {
84910Sigor@sysoev.ru                 jbs->resolve.name.length = length;
85010Sigor@sysoev.ru                 jbs->resolve.name.start = host;
8510Sigor@sysoev.ru                 jbs->resolve.port = (in_port_t) port;
8520Sigor@sysoev.ru 
8530Sigor@sysoev.ru                 nxt_job_resolve(&jbs->resolve);
8540Sigor@sysoev.ru                 return NXT_AGAIN;
8550Sigor@sysoev.ru             }
8560Sigor@sysoev.ru 
8570Sigor@sysoev.ru             /* "x.x.x.x:XX" */
8580Sigor@sysoev.ru         }
8590Sigor@sysoev.ru     }
8600Sigor@sysoev.ru 
8610Sigor@sysoev.ru     mp = jbs->resolve.job.mem_pool;
8620Sigor@sysoev.ru 
863*65Sigor@sysoev.ru     jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *));
8640Sigor@sysoev.ru     if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) {
8650Sigor@sysoev.ru         return NXT_ERROR;
8660Sigor@sysoev.ru     }
8670Sigor@sysoev.ru 
86813Sigor@sysoev.ru     sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in),
86913Sigor@sysoev.ru                             NXT_INET_ADDR_STR_LEN);
8700Sigor@sysoev.ru 
8710Sigor@sysoev.ru     if (nxt_fast_path(sa != NULL)) {
8720Sigor@sysoev.ru         jbs->resolve.count = 1;
8730Sigor@sysoev.ru         jbs->resolve.sockaddrs[0] = sa;
8740Sigor@sysoev.ru 
8750Sigor@sysoev.ru         jbs->wildcard = (addr == INADDR_ANY);
8760Sigor@sysoev.ru 
8770Sigor@sysoev.ru         sa->u.sockaddr_in.sin_family = AF_INET;
8780Sigor@sysoev.ru         sa->u.sockaddr_in.sin_port = (in_port_t) port;
8790Sigor@sysoev.ru         sa->u.sockaddr_in.sin_addr.s_addr = addr;
8800Sigor@sysoev.ru 
8810Sigor@sysoev.ru         return NXT_OK;
8820Sigor@sysoev.ru     }
8830Sigor@sysoev.ru 
8840Sigor@sysoev.ru     return NXT_ERROR;
8850Sigor@sysoev.ru 
8860Sigor@sysoev.ru invalid_port:
8870Sigor@sysoev.ru 
8880Sigor@sysoev.ru     nxt_thread_log_error(jbs->resolve.log_level,
8890Sigor@sysoev.ru                          "invalid port in \"%V\"", &jbs->addr);
8900Sigor@sysoev.ru 
8910Sigor@sysoev.ru     return NXT_ERROR;
8920Sigor@sysoev.ru }
8930Sigor@sysoev.ru 
8940Sigor@sysoev.ru 
8950Sigor@sysoev.ru in_addr_t
89610Sigor@sysoev.ru nxt_inet_addr(u_char *buf, size_t length)
8970Sigor@sysoev.ru {
8980Sigor@sysoev.ru     u_char      c, *end;
8990Sigor@sysoev.ru     in_addr_t   addr;
9000Sigor@sysoev.ru     nxt_uint_t  digit, octet, dots;
9010Sigor@sysoev.ru 
9020Sigor@sysoev.ru     addr = 0;
9030Sigor@sysoev.ru     octet = 0;
9040Sigor@sysoev.ru     dots = 0;
9050Sigor@sysoev.ru 
90610Sigor@sysoev.ru     end = buf + length;
9070Sigor@sysoev.ru 
9080Sigor@sysoev.ru     while (buf < end) {
9090Sigor@sysoev.ru 
9100Sigor@sysoev.ru         c = *buf++;
9110Sigor@sysoev.ru 
9120Sigor@sysoev.ru         digit = c - '0';
9130Sigor@sysoev.ru         /* values below '0' become large unsigned integers */
9140Sigor@sysoev.ru 
9150Sigor@sysoev.ru         if (digit < 10) {
9160Sigor@sysoev.ru             octet = octet * 10 + digit;
9170Sigor@sysoev.ru             continue;
9180Sigor@sysoev.ru         }
9190Sigor@sysoev.ru 
9200Sigor@sysoev.ru         if (c == '.' && octet < 256) {
9210Sigor@sysoev.ru             addr = (addr << 8) + octet;
9220Sigor@sysoev.ru             octet = 0;
9230Sigor@sysoev.ru             dots++;
9240Sigor@sysoev.ru             continue;
9250Sigor@sysoev.ru         }
9260Sigor@sysoev.ru 
9270Sigor@sysoev.ru         return INADDR_NONE;
9280Sigor@sysoev.ru     }
9290Sigor@sysoev.ru 
9300Sigor@sysoev.ru     if (dots == 3 && octet < 256) {
9310Sigor@sysoev.ru         addr = (addr << 8) + octet;
9320Sigor@sysoev.ru         return htonl(addr);
9330Sigor@sysoev.ru     }
9340Sigor@sysoev.ru 
9350Sigor@sysoev.ru     return INADDR_NONE;
9360Sigor@sysoev.ru }
9370Sigor@sysoev.ru 
9380Sigor@sysoev.ru 
9390Sigor@sysoev.ru #if (NXT_INET6)
9400Sigor@sysoev.ru 
9410Sigor@sysoev.ru nxt_int_t
94210Sigor@sysoev.ru nxt_inet6_addr(struct in6_addr *in6_addr, u_char *buf, size_t length)
9430Sigor@sysoev.ru {
9440Sigor@sysoev.ru     u_char      c, *addr, *zero_start, *ipv4, *dst, *src, *end;
9450Sigor@sysoev.ru     nxt_uint_t  digit, group, nibbles, groups_left;
9460Sigor@sysoev.ru 
94710Sigor@sysoev.ru     if (length == 0) {
9480Sigor@sysoev.ru         return NXT_ERROR;
9490Sigor@sysoev.ru     }
9500Sigor@sysoev.ru 
95110Sigor@sysoev.ru     end = buf + length;
9520Sigor@sysoev.ru 
9530Sigor@sysoev.ru     if (buf[0] == ':') {
9540Sigor@sysoev.ru         buf++;
9550Sigor@sysoev.ru     }
9560Sigor@sysoev.ru 
9570Sigor@sysoev.ru     addr = in6_addr->s6_addr;
9580Sigor@sysoev.ru     zero_start = NULL;
9590Sigor@sysoev.ru     groups_left = 8;
9600Sigor@sysoev.ru     nibbles = 0;
9610Sigor@sysoev.ru     group = 0;
9620Sigor@sysoev.ru     ipv4 = NULL;
9630Sigor@sysoev.ru 
9640Sigor@sysoev.ru     while (buf < end) {
9650Sigor@sysoev.ru         c = *buf++;
9660Sigor@sysoev.ru 
9670Sigor@sysoev.ru         if (c == ':') {
9680Sigor@sysoev.ru             if (nibbles != 0) {
9690Sigor@sysoev.ru                 ipv4 = buf;
9700Sigor@sysoev.ru 
9710Sigor@sysoev.ru                 *addr++ = (u_char) (group >> 8);
9720Sigor@sysoev.ru                 *addr++ = (u_char) (group & 0xff);
9730Sigor@sysoev.ru                 groups_left--;
9740Sigor@sysoev.ru 
9750Sigor@sysoev.ru                 if (groups_left != 0) {
9760Sigor@sysoev.ru                     nibbles = 0;
9770Sigor@sysoev.ru                     group = 0;
9780Sigor@sysoev.ru                     continue;
9790Sigor@sysoev.ru                 }
9800Sigor@sysoev.ru 
9810Sigor@sysoev.ru             } else {
9820Sigor@sysoev.ru                 if (zero_start == NULL) {
9830Sigor@sysoev.ru                     ipv4 = buf;
9840Sigor@sysoev.ru                     zero_start = addr;
9850Sigor@sysoev.ru                     continue;
9860Sigor@sysoev.ru                 }
9870Sigor@sysoev.ru             }
9880Sigor@sysoev.ru 
9890Sigor@sysoev.ru             return NXT_ERROR;
9900Sigor@sysoev.ru         }
9910Sigor@sysoev.ru 
9920Sigor@sysoev.ru         if (c == '.' && nibbles != 0) {
9930Sigor@sysoev.ru 
9940Sigor@sysoev.ru             if (groups_left < 2 || ipv4 == NULL) {
9950Sigor@sysoev.ru                 return NXT_ERROR;
9960Sigor@sysoev.ru             }
9970Sigor@sysoev.ru 
9980Sigor@sysoev.ru             group = nxt_inet_addr(ipv4, end - ipv4);
9990Sigor@sysoev.ru             if (group == INADDR_NONE) {
10000Sigor@sysoev.ru                 return NXT_ERROR;
10010Sigor@sysoev.ru             }
10020Sigor@sysoev.ru 
10030Sigor@sysoev.ru             group = ntohl(group);
10040Sigor@sysoev.ru 
10050Sigor@sysoev.ru             *addr++ = (u_char) ((group >> 24) & 0xff);
10060Sigor@sysoev.ru             *addr++ = (u_char) ((group >> 16) & 0xff);
10070Sigor@sysoev.ru             groups_left--;
10080Sigor@sysoev.ru 
10090Sigor@sysoev.ru             /* the low 16-bit are copied below */
10100Sigor@sysoev.ru             break;
10110Sigor@sysoev.ru         }
10120Sigor@sysoev.ru 
10130Sigor@sysoev.ru         nibbles++;
10140Sigor@sysoev.ru 
10150Sigor@sysoev.ru         if (nibbles > 4) {
10160Sigor@sysoev.ru             return NXT_ERROR;
10170Sigor@sysoev.ru         }
10180Sigor@sysoev.ru 
10190Sigor@sysoev.ru         group <<= 4;
10200Sigor@sysoev.ru 
10210Sigor@sysoev.ru         digit = c - '0';
10220Sigor@sysoev.ru         /* values below '0' become large unsigned integers */
10230Sigor@sysoev.ru 
10240Sigor@sysoev.ru         if (digit < 10) {
10250Sigor@sysoev.ru             group += digit;
10260Sigor@sysoev.ru             continue;
10270Sigor@sysoev.ru         }
10280Sigor@sysoev.ru 
10290Sigor@sysoev.ru         c |= 0x20;
10300Sigor@sysoev.ru         digit = c - 'a';
10310Sigor@sysoev.ru         /* values below 'a' become large unsigned integers */
10320Sigor@sysoev.ru 
10330Sigor@sysoev.ru         if (digit < 6) {
10340Sigor@sysoev.ru             group += 10 + digit;
10350Sigor@sysoev.ru             continue;
10360Sigor@sysoev.ru         }
10370Sigor@sysoev.ru 
10380Sigor@sysoev.ru         return NXT_ERROR;
10390Sigor@sysoev.ru     }
10400Sigor@sysoev.ru 
10410Sigor@sysoev.ru     if (nibbles == 0 && zero_start == NULL) {
10420Sigor@sysoev.ru         return NXT_ERROR;
10430Sigor@sysoev.ru     }
10440Sigor@sysoev.ru 
10450Sigor@sysoev.ru     *addr++ = (u_char) (group >> 8);
10460Sigor@sysoev.ru     *addr++ = (u_char) (group & 0xff);
10470Sigor@sysoev.ru     groups_left--;
10480Sigor@sysoev.ru 
10490Sigor@sysoev.ru     if (groups_left != 0) {
10500Sigor@sysoev.ru 
10510Sigor@sysoev.ru         if (zero_start != NULL) {
10520Sigor@sysoev.ru 
10530Sigor@sysoev.ru             /* moving part before consecutive zero groups to the end */
10540Sigor@sysoev.ru 
10550Sigor@sysoev.ru             groups_left *= 2;
10560Sigor@sysoev.ru             src = addr - 1;
10570Sigor@sysoev.ru             dst = src + groups_left;
10580Sigor@sysoev.ru 
10590Sigor@sysoev.ru             while (src >= zero_start) {
10600Sigor@sysoev.ru                 *dst-- = *src--;
10610Sigor@sysoev.ru             }
10620Sigor@sysoev.ru 
10630Sigor@sysoev.ru             nxt_memzero(zero_start, groups_left);
10640Sigor@sysoev.ru 
10650Sigor@sysoev.ru             return NXT_OK;
10660Sigor@sysoev.ru         }
10670Sigor@sysoev.ru 
10680Sigor@sysoev.ru     } else {
10690Sigor@sysoev.ru         if (zero_start == NULL) {
10700Sigor@sysoev.ru             return NXT_OK;
10710Sigor@sysoev.ru         }
10720Sigor@sysoev.ru     }
10730Sigor@sysoev.ru 
10740Sigor@sysoev.ru     return NXT_ERROR;
10750Sigor@sysoev.ru }
10760Sigor@sysoev.ru 
10770Sigor@sysoev.ru #endif
1078