xref: /unit/src/nxt_sockaddr.c (revision 0)
1*0Sigor@sysoev.ru 
2*0Sigor@sysoev.ru /*
3*0Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
4*0Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
5*0Sigor@sysoev.ru  */
6*0Sigor@sysoev.ru 
7*0Sigor@sysoev.ru #include <nxt_main.h>
8*0Sigor@sysoev.ru 
9*0Sigor@sysoev.ru 
10*0Sigor@sysoev.ru #if (NXT_INET6)
11*0Sigor@sysoev.ru static u_char *nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end);
12*0Sigor@sysoev.ru #endif
13*0Sigor@sysoev.ru 
14*0Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs);
15*0Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs);
16*0Sigor@sysoev.ru static nxt_int_t nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs);
17*0Sigor@sysoev.ru 
18*0Sigor@sysoev.ru 
19*0Sigor@sysoev.ru nxt_sockaddr_t *
20*0Sigor@sysoev.ru nxt_sockaddr_alloc(nxt_mem_pool_t *mp, socklen_t len)
21*0Sigor@sysoev.ru {
22*0Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
23*0Sigor@sysoev.ru 
24*0Sigor@sysoev.ru     /*
25*0Sigor@sysoev.ru      * The current struct sockaddr's define 32-bit fields at maximum
26*0Sigor@sysoev.ru      * and may define 64-bit AF_INET6 fields in the future.  Alignment
27*0Sigor@sysoev.ru      * of memory allocated by nxt_mem_zalloc() is enough for these fields.
28*0Sigor@sysoev.ru      * If 128-bit alignment will be required then nxt_mem_malloc() and
29*0Sigor@sysoev.ru      * nxt_memzero() should be used instead.
30*0Sigor@sysoev.ru      */
31*0Sigor@sysoev.ru     sa = nxt_mem_zalloc(mp, offsetof(nxt_sockaddr_t, u) + len);
32*0Sigor@sysoev.ru 
33*0Sigor@sysoev.ru     if (nxt_fast_path(sa != NULL)) {
34*0Sigor@sysoev.ru         nxt_socklen_set(sa, len);
35*0Sigor@sysoev.ru     }
36*0Sigor@sysoev.ru 
37*0Sigor@sysoev.ru     return sa;
38*0Sigor@sysoev.ru }
39*0Sigor@sysoev.ru 
40*0Sigor@sysoev.ru 
41*0Sigor@sysoev.ru nxt_sockaddr_t *
42*0Sigor@sysoev.ru nxt_sockaddr_create(nxt_mem_pool_t *mp, struct sockaddr *sockaddr,
43*0Sigor@sysoev.ru     socklen_t len)
44*0Sigor@sysoev.ru {
45*0Sigor@sysoev.ru     size_t          size, copy;
46*0Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
47*0Sigor@sysoev.ru 
48*0Sigor@sysoev.ru     size = len;
49*0Sigor@sysoev.ru     copy = len;
50*0Sigor@sysoev.ru 
51*0Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
52*0Sigor@sysoev.ru 
53*0Sigor@sysoev.ru     /*
54*0Sigor@sysoev.ru      * Unspecified Unix domain sockaddr_un form and length are very
55*0Sigor@sysoev.ru      * platform depended (see comment in unix/socket.h).  Here they are
56*0Sigor@sysoev.ru      * normalized to the sockaddr_un with single zero byte sun_path[].
57*0Sigor@sysoev.ru      */
58*0Sigor@sysoev.ru 
59*0Sigor@sysoev.ru     if (size <= offsetof(struct sockaddr_un, sun_path)) {
60*0Sigor@sysoev.ru         /*
61*0Sigor@sysoev.ru          * Small socket length means a short unspecified Unix domain
62*0Sigor@sysoev.ru          * socket address:
63*0Sigor@sysoev.ru          *
64*0Sigor@sysoev.ru          *   getsockname() and getpeername() on OpenBSD prior to 5.3
65*0Sigor@sysoev.ru          *   return zero length and does not update a passed sockaddr
66*0Sigor@sysoev.ru          *   buffer at all.
67*0Sigor@sysoev.ru          *
68*0Sigor@sysoev.ru          *   Linux returns length equal to 2, i.e. sockaddr_un without
69*0Sigor@sysoev.ru          *   sun_path[], unix(7):
70*0Sigor@sysoev.ru          *
71*0Sigor@sysoev.ru          *     unnamed: A stream socket that has not been bound
72*0Sigor@sysoev.ru          *     to a pathname using bind(2) has no name.  Likewise,
73*0Sigor@sysoev.ru          *     the two sockets created by socketpair(2) are unnamed.
74*0Sigor@sysoev.ru          *     When the address of an unnamed socket is returned by
75*0Sigor@sysoev.ru          *     getsockname(2), getpeername(2), and accept(2), its
76*0Sigor@sysoev.ru          *     length is sizeof(sa_family_t), and sun_path should
77*0Sigor@sysoev.ru          *     not be inspected.
78*0Sigor@sysoev.ru          */
79*0Sigor@sysoev.ru         size = offsetof(struct sockaddr_un, sun_path) + 1;
80*0Sigor@sysoev.ru 
81*0Sigor@sysoev.ru #if !(NXT_LINUX)
82*0Sigor@sysoev.ru 
83*0Sigor@sysoev.ru     } else if (sockaddr->sa_family == AF_UNIX && sockaddr->sa_data[0] == '\0') {
84*0Sigor@sysoev.ru         /*
85*0Sigor@sysoev.ru          * Omit nonsignificant zeros of the unspecified Unix domain socket
86*0Sigor@sysoev.ru          * address.  This test is disabled for Linux since Linux abstract
87*0Sigor@sysoev.ru          * socket address also starts with zero.  However Linux unspecified
88*0Sigor@sysoev.ru          * Unix domain socket address is short and is handled above.
89*0Sigor@sysoev.ru          */
90*0Sigor@sysoev.ru         size = offsetof(struct sockaddr_un, sun_path) + 1;
91*0Sigor@sysoev.ru         copy = size;
92*0Sigor@sysoev.ru 
93*0Sigor@sysoev.ru #endif
94*0Sigor@sysoev.ru     }
95*0Sigor@sysoev.ru 
96*0Sigor@sysoev.ru #endif  /* NXT_HAVE_UNIX_DOMAIN */
97*0Sigor@sysoev.ru 
98*0Sigor@sysoev.ru     sa = nxt_sockaddr_alloc(mp, size);
99*0Sigor@sysoev.ru 
100*0Sigor@sysoev.ru     if (nxt_fast_path(sa != NULL)) {
101*0Sigor@sysoev.ru 
102*0Sigor@sysoev.ru         nxt_memcpy(&sa->u.sockaddr, sockaddr, copy);
103*0Sigor@sysoev.ru 
104*0Sigor@sysoev.ru #if (NXT_SOCKADDR_SA_LEN)
105*0Sigor@sysoev.ru 
106*0Sigor@sysoev.ru         /* Update shortcut sockaddr length overwritten by nxt_memcpy(). */
107*0Sigor@sysoev.ru         nxt_socklen_set(sa, size);
108*0Sigor@sysoev.ru 
109*0Sigor@sysoev.ru #endif
110*0Sigor@sysoev.ru 
111*0Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN && NXT_OPENBSD)
112*0Sigor@sysoev.ru 
113*0Sigor@sysoev.ru         if (len == 0) {
114*0Sigor@sysoev.ru             sa->u.sockaddr.sa_family = AF_UNIX;
115*0Sigor@sysoev.ru         }
116*0Sigor@sysoev.ru 
117*0Sigor@sysoev.ru #endif
118*0Sigor@sysoev.ru     }
119*0Sigor@sysoev.ru 
120*0Sigor@sysoev.ru     return sa;
121*0Sigor@sysoev.ru }
122*0Sigor@sysoev.ru 
123*0Sigor@sysoev.ru 
124*0Sigor@sysoev.ru nxt_sockaddr_t *
125*0Sigor@sysoev.ru nxt_sockaddr_copy(nxt_mem_pool_t *mp, nxt_sockaddr_t *src)
126*0Sigor@sysoev.ru {
127*0Sigor@sysoev.ru     size_t          len;
128*0Sigor@sysoev.ru     nxt_sockaddr_t  *dst;
129*0Sigor@sysoev.ru 
130*0Sigor@sysoev.ru     len = offsetof(nxt_sockaddr_t, u) + nxt_socklen(src);
131*0Sigor@sysoev.ru 
132*0Sigor@sysoev.ru     dst = nxt_mem_alloc(mp, len);
133*0Sigor@sysoev.ru 
134*0Sigor@sysoev.ru     if (nxt_fast_path(dst != NULL)) {
135*0Sigor@sysoev.ru         nxt_memcpy(dst, src, len);
136*0Sigor@sysoev.ru     }
137*0Sigor@sysoev.ru 
138*0Sigor@sysoev.ru     return dst;
139*0Sigor@sysoev.ru }
140*0Sigor@sysoev.ru 
141*0Sigor@sysoev.ru 
142*0Sigor@sysoev.ru nxt_sockaddr_t *
143*0Sigor@sysoev.ru nxt_getsockname(nxt_mem_pool_t *mp, nxt_socket_t s)
144*0Sigor@sysoev.ru {
145*0Sigor@sysoev.ru     int                 ret;
146*0Sigor@sysoev.ru     socklen_t           socklen;
147*0Sigor@sysoev.ru     nxt_sockaddr_buf_t  sockaddr;
148*0Sigor@sysoev.ru 
149*0Sigor@sysoev.ru     socklen = NXT_SOCKADDR_LEN;
150*0Sigor@sysoev.ru 
151*0Sigor@sysoev.ru     ret = getsockname(s, &sockaddr.buf, &socklen);
152*0Sigor@sysoev.ru 
153*0Sigor@sysoev.ru     if (nxt_fast_path(ret == 0)) {
154*0Sigor@sysoev.ru         return nxt_sockaddr_create(mp, &sockaddr.buf, socklen);
155*0Sigor@sysoev.ru     }
156*0Sigor@sysoev.ru 
157*0Sigor@sysoev.ru     nxt_thread_log_error(NXT_LOG_ERR, "getsockname(%d) failed %E",
158*0Sigor@sysoev.ru                          s, nxt_errno);
159*0Sigor@sysoev.ru 
160*0Sigor@sysoev.ru     return NULL;
161*0Sigor@sysoev.ru }
162*0Sigor@sysoev.ru 
163*0Sigor@sysoev.ru 
164*0Sigor@sysoev.ru nxt_int_t
165*0Sigor@sysoev.ru nxt_sockaddr_text(nxt_mem_pool_t *mp, nxt_sockaddr_t *sa, nxt_bool_t port)
166*0Sigor@sysoev.ru {
167*0Sigor@sysoev.ru     size_t  len;
168*0Sigor@sysoev.ru     u_char  *p;
169*0Sigor@sysoev.ru     u_char  buf[NXT_SOCKADDR_STR_LEN + NXT_SOCKPORT_STR_LEN];
170*0Sigor@sysoev.ru 
171*0Sigor@sysoev.ru     len = NXT_SOCKADDR_STR_LEN + NXT_SOCKPORT_STR_LEN;
172*0Sigor@sysoev.ru 
173*0Sigor@sysoev.ru     len = nxt_sockaddr_ntop(sa, buf, buf + len, port);
174*0Sigor@sysoev.ru 
175*0Sigor@sysoev.ru     p = nxt_mem_alloc(mp, len);
176*0Sigor@sysoev.ru 
177*0Sigor@sysoev.ru     if (nxt_fast_path(p != NULL)) {
178*0Sigor@sysoev.ru 
179*0Sigor@sysoev.ru         sa->text = p;
180*0Sigor@sysoev.ru         sa->text_len = len;
181*0Sigor@sysoev.ru         nxt_memcpy(p, buf, len);
182*0Sigor@sysoev.ru 
183*0Sigor@sysoev.ru         return NXT_OK;
184*0Sigor@sysoev.ru     }
185*0Sigor@sysoev.ru 
186*0Sigor@sysoev.ru     return NXT_ERROR;
187*0Sigor@sysoev.ru }
188*0Sigor@sysoev.ru 
189*0Sigor@sysoev.ru 
190*0Sigor@sysoev.ru uint32_t
191*0Sigor@sysoev.ru nxt_sockaddr_port(nxt_sockaddr_t *sa)
192*0Sigor@sysoev.ru {
193*0Sigor@sysoev.ru     uint32_t  port;
194*0Sigor@sysoev.ru 
195*0Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
196*0Sigor@sysoev.ru 
197*0Sigor@sysoev.ru #if (NXT_INET6)
198*0Sigor@sysoev.ru 
199*0Sigor@sysoev.ru     case AF_INET6:
200*0Sigor@sysoev.ru         port = sa->u.sockaddr_in6.sin6_port;
201*0Sigor@sysoev.ru         break;
202*0Sigor@sysoev.ru 
203*0Sigor@sysoev.ru #endif
204*0Sigor@sysoev.ru 
205*0Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
206*0Sigor@sysoev.ru 
207*0Sigor@sysoev.ru     case AF_UNIX:
208*0Sigor@sysoev.ru         return 0;
209*0Sigor@sysoev.ru 
210*0Sigor@sysoev.ru #endif
211*0Sigor@sysoev.ru 
212*0Sigor@sysoev.ru     default:
213*0Sigor@sysoev.ru         port = sa->u.sockaddr_in.sin_port;
214*0Sigor@sysoev.ru         break;
215*0Sigor@sysoev.ru     }
216*0Sigor@sysoev.ru 
217*0Sigor@sysoev.ru     return ntohs((uint16_t) port);
218*0Sigor@sysoev.ru }
219*0Sigor@sysoev.ru 
220*0Sigor@sysoev.ru 
221*0Sigor@sysoev.ru nxt_bool_t
222*0Sigor@sysoev.ru nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, nxt_sockaddr_t *sa2)
223*0Sigor@sysoev.ru {
224*0Sigor@sysoev.ru     if (nxt_socklen(sa1) != nxt_socklen(sa2)) {
225*0Sigor@sysoev.ru         return 0;
226*0Sigor@sysoev.ru     }
227*0Sigor@sysoev.ru 
228*0Sigor@sysoev.ru     if (sa1->type != sa2->type) {
229*0Sigor@sysoev.ru         return 0;
230*0Sigor@sysoev.ru     }
231*0Sigor@sysoev.ru 
232*0Sigor@sysoev.ru     if (sa1->u.sockaddr.sa_family != sa2->u.sockaddr.sa_family) {
233*0Sigor@sysoev.ru         return 0;
234*0Sigor@sysoev.ru     }
235*0Sigor@sysoev.ru 
236*0Sigor@sysoev.ru     /*
237*0Sigor@sysoev.ru      * sockaddr struct's cannot be compared in whole since kernel
238*0Sigor@sysoev.ru      * may fill some fields in inherited sockaddr struct's.
239*0Sigor@sysoev.ru      */
240*0Sigor@sysoev.ru 
241*0Sigor@sysoev.ru     switch (sa1->u.sockaddr.sa_family) {
242*0Sigor@sysoev.ru 
243*0Sigor@sysoev.ru #if (NXT_INET6)
244*0Sigor@sysoev.ru 
245*0Sigor@sysoev.ru     case AF_INET6:
246*0Sigor@sysoev.ru         if (sa1->u.sockaddr_in6.sin6_port != sa2->u.sockaddr_in6.sin6_port) {
247*0Sigor@sysoev.ru             return 0;
248*0Sigor@sysoev.ru         }
249*0Sigor@sysoev.ru 
250*0Sigor@sysoev.ru         if (nxt_memcmp(&sa1->u.sockaddr_in6.sin6_addr,
251*0Sigor@sysoev.ru                        &sa2->u.sockaddr_in6.sin6_addr, 16)
252*0Sigor@sysoev.ru             != 0)
253*0Sigor@sysoev.ru         {
254*0Sigor@sysoev.ru             return 0;
255*0Sigor@sysoev.ru         }
256*0Sigor@sysoev.ru 
257*0Sigor@sysoev.ru         return 1;
258*0Sigor@sysoev.ru 
259*0Sigor@sysoev.ru #endif
260*0Sigor@sysoev.ru 
261*0Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
262*0Sigor@sysoev.ru 
263*0Sigor@sysoev.ru     case AF_UNIX:
264*0Sigor@sysoev.ru         {
265*0Sigor@sysoev.ru             size_t  len;
266*0Sigor@sysoev.ru 
267*0Sigor@sysoev.ru             len = nxt_socklen(sa1) - offsetof(struct sockaddr_un, sun_path);
268*0Sigor@sysoev.ru 
269*0Sigor@sysoev.ru             if (nxt_memcmp(&sa1->u.sockaddr_un.sun_path,
270*0Sigor@sysoev.ru                            &sa2->u.sockaddr_un.sun_path, len)
271*0Sigor@sysoev.ru                 != 0)
272*0Sigor@sysoev.ru             {
273*0Sigor@sysoev.ru                 return 0;
274*0Sigor@sysoev.ru             }
275*0Sigor@sysoev.ru 
276*0Sigor@sysoev.ru             return 1;
277*0Sigor@sysoev.ru         }
278*0Sigor@sysoev.ru 
279*0Sigor@sysoev.ru #endif
280*0Sigor@sysoev.ru 
281*0Sigor@sysoev.ru     default: /* AF_INET */
282*0Sigor@sysoev.ru         if (sa1->u.sockaddr_in.sin_port != sa2->u.sockaddr_in.sin_port) {
283*0Sigor@sysoev.ru             return 0;
284*0Sigor@sysoev.ru         }
285*0Sigor@sysoev.ru 
286*0Sigor@sysoev.ru         if (sa1->u.sockaddr_in.sin_addr.s_addr
287*0Sigor@sysoev.ru             != sa2->u.sockaddr_in.sin_addr.s_addr)
288*0Sigor@sysoev.ru         {
289*0Sigor@sysoev.ru             return 0;
290*0Sigor@sysoev.ru         }
291*0Sigor@sysoev.ru 
292*0Sigor@sysoev.ru         return 1;
293*0Sigor@sysoev.ru     }
294*0Sigor@sysoev.ru }
295*0Sigor@sysoev.ru 
296*0Sigor@sysoev.ru 
297*0Sigor@sysoev.ru size_t
298*0Sigor@sysoev.ru nxt_sockaddr_ntop(nxt_sockaddr_t *sa, u_char *buf, u_char *end, nxt_bool_t port)
299*0Sigor@sysoev.ru {
300*0Sigor@sysoev.ru     u_char  *p;
301*0Sigor@sysoev.ru 
302*0Sigor@sysoev.ru     switch (sa->u.sockaddr.sa_family) {
303*0Sigor@sysoev.ru 
304*0Sigor@sysoev.ru     case AF_INET:
305*0Sigor@sysoev.ru         p = (u_char *) &sa->u.sockaddr_in.sin_addr;
306*0Sigor@sysoev.ru 
307*0Sigor@sysoev.ru         if (port) {
308*0Sigor@sysoev.ru             p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud:%d",
309*0Sigor@sysoev.ru                             p[0], p[1], p[2], p[3],
310*0Sigor@sysoev.ru                             ntohs(sa->u.sockaddr_in.sin_port));
311*0Sigor@sysoev.ru         } else {
312*0Sigor@sysoev.ru             p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud",
313*0Sigor@sysoev.ru                             p[0], p[1], p[2], p[3]);
314*0Sigor@sysoev.ru         }
315*0Sigor@sysoev.ru 
316*0Sigor@sysoev.ru         return p - buf;
317*0Sigor@sysoev.ru 
318*0Sigor@sysoev.ru #if (NXT_INET6)
319*0Sigor@sysoev.ru 
320*0Sigor@sysoev.ru     case AF_INET6:
321*0Sigor@sysoev.ru         p = buf;
322*0Sigor@sysoev.ru 
323*0Sigor@sysoev.ru         if (port) {
324*0Sigor@sysoev.ru             *p++ = '[';
325*0Sigor@sysoev.ru         }
326*0Sigor@sysoev.ru 
327*0Sigor@sysoev.ru         p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end);
328*0Sigor@sysoev.ru 
329*0Sigor@sysoev.ru         if (port) {
330*0Sigor@sysoev.ru             p = nxt_sprintf(p, end, "]:%d",
331*0Sigor@sysoev.ru                             ntohs(sa->u.sockaddr_in6.sin6_port));
332*0Sigor@sysoev.ru         }
333*0Sigor@sysoev.ru 
334*0Sigor@sysoev.ru         return p - buf;
335*0Sigor@sysoev.ru #endif
336*0Sigor@sysoev.ru 
337*0Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
338*0Sigor@sysoev.ru 
339*0Sigor@sysoev.ru     case AF_UNIX:
340*0Sigor@sysoev.ru 
341*0Sigor@sysoev.ru #if (NXT_LINUX)
342*0Sigor@sysoev.ru 
343*0Sigor@sysoev.ru         p = (u_char *) sa->u.sockaddr_un.sun_path;
344*0Sigor@sysoev.ru 
345*0Sigor@sysoev.ru         if (p[0] == '\0') {
346*0Sigor@sysoev.ru             int  len;
347*0Sigor@sysoev.ru 
348*0Sigor@sysoev.ru             /* Linux abstract socket address has no trailing zero. */
349*0Sigor@sysoev.ru 
350*0Sigor@sysoev.ru             len = nxt_socklen(sa) - offsetof(struct sockaddr_un, sun_path) - 1;
351*0Sigor@sysoev.ru             p = nxt_sprintf(buf, end, "unix:\\0%*s", len, p + 1);
352*0Sigor@sysoev.ru 
353*0Sigor@sysoev.ru         } else {
354*0Sigor@sysoev.ru             p = nxt_sprintf(buf, end, "unix:%s", p);
355*0Sigor@sysoev.ru         }
356*0Sigor@sysoev.ru 
357*0Sigor@sysoev.ru #else  /* !(NXT_LINUX) */
358*0Sigor@sysoev.ru 
359*0Sigor@sysoev.ru         p = nxt_sprintf(buf, end, "unix:%s", sa->u.sockaddr_un.sun_path);
360*0Sigor@sysoev.ru 
361*0Sigor@sysoev.ru #endif
362*0Sigor@sysoev.ru 
363*0Sigor@sysoev.ru         return p - buf;
364*0Sigor@sysoev.ru 
365*0Sigor@sysoev.ru #endif  /* NXT_HAVE_UNIX_DOMAIN */
366*0Sigor@sysoev.ru 
367*0Sigor@sysoev.ru     default:
368*0Sigor@sysoev.ru         return 0;
369*0Sigor@sysoev.ru     }
370*0Sigor@sysoev.ru }
371*0Sigor@sysoev.ru 
372*0Sigor@sysoev.ru 
373*0Sigor@sysoev.ru #if (NXT_INET6)
374*0Sigor@sysoev.ru 
375*0Sigor@sysoev.ru static u_char *
376*0Sigor@sysoev.ru nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end)
377*0Sigor@sysoev.ru {
378*0Sigor@sysoev.ru     u_char      *p;
379*0Sigor@sysoev.ru     size_t      zero_groups, last_zero_groups, ipv6_bytes;
380*0Sigor@sysoev.ru     nxt_uint_t  i, zero_start, last_zero_start;
381*0Sigor@sysoev.ru 
382*0Sigor@sysoev.ru     if (buf + NXT_INET6_ADDR_STR_LEN > end) {
383*0Sigor@sysoev.ru         return buf;
384*0Sigor@sysoev.ru     }
385*0Sigor@sysoev.ru 
386*0Sigor@sysoev.ru     zero_start = 8;
387*0Sigor@sysoev.ru     zero_groups = 0;
388*0Sigor@sysoev.ru     last_zero_start = 8;
389*0Sigor@sysoev.ru     last_zero_groups = 0;
390*0Sigor@sysoev.ru 
391*0Sigor@sysoev.ru     for (i = 0; i < 16; i += 2) {
392*0Sigor@sysoev.ru 
393*0Sigor@sysoev.ru         if (addr[i] == 0 && addr[i + 1] == 0) {
394*0Sigor@sysoev.ru 
395*0Sigor@sysoev.ru             if (last_zero_groups == 0) {
396*0Sigor@sysoev.ru                 last_zero_start = i;
397*0Sigor@sysoev.ru             }
398*0Sigor@sysoev.ru 
399*0Sigor@sysoev.ru             last_zero_groups++;
400*0Sigor@sysoev.ru 
401*0Sigor@sysoev.ru         } else {
402*0Sigor@sysoev.ru             if (zero_groups < last_zero_groups) {
403*0Sigor@sysoev.ru                 zero_groups = last_zero_groups;
404*0Sigor@sysoev.ru                 zero_start = last_zero_start;
405*0Sigor@sysoev.ru             }
406*0Sigor@sysoev.ru 
407*0Sigor@sysoev.ru             last_zero_groups = 0;
408*0Sigor@sysoev.ru         }
409*0Sigor@sysoev.ru     }
410*0Sigor@sysoev.ru 
411*0Sigor@sysoev.ru     if (zero_groups < last_zero_groups) {
412*0Sigor@sysoev.ru         zero_groups = last_zero_groups;
413*0Sigor@sysoev.ru         zero_start = last_zero_start;
414*0Sigor@sysoev.ru     }
415*0Sigor@sysoev.ru 
416*0Sigor@sysoev.ru     ipv6_bytes = 16;
417*0Sigor@sysoev.ru     p = buf;
418*0Sigor@sysoev.ru 
419*0Sigor@sysoev.ru     if (zero_start == 0) {
420*0Sigor@sysoev.ru 
421*0Sigor@sysoev.ru                /* IPv4-mapped address */
422*0Sigor@sysoev.ru         if ((zero_groups == 5 && addr[10] == 0xff && addr[11] == 0xff)
423*0Sigor@sysoev.ru                /* IPv4-compatible address */
424*0Sigor@sysoev.ru             || (zero_groups == 6)
425*0Sigor@sysoev.ru                /* not IPv6 loopback address */
426*0Sigor@sysoev.ru             || (zero_groups == 7 && addr[14] != 0 && addr[15] != 1))
427*0Sigor@sysoev.ru         {
428*0Sigor@sysoev.ru             ipv6_bytes = 12;
429*0Sigor@sysoev.ru         }
430*0Sigor@sysoev.ru 
431*0Sigor@sysoev.ru         *p++ = ':';
432*0Sigor@sysoev.ru     }
433*0Sigor@sysoev.ru 
434*0Sigor@sysoev.ru     for (i = 0; i < ipv6_bytes; i += 2) {
435*0Sigor@sysoev.ru 
436*0Sigor@sysoev.ru         if (i == zero_start) {
437*0Sigor@sysoev.ru             /* Output maximum number of consecutive zero groups as "::". */
438*0Sigor@sysoev.ru             i += (zero_groups - 1) * 2;
439*0Sigor@sysoev.ru             *p++ = ':';
440*0Sigor@sysoev.ru             continue;
441*0Sigor@sysoev.ru         }
442*0Sigor@sysoev.ru 
443*0Sigor@sysoev.ru         p = nxt_sprintf(p, end, "%uxd", (addr[i] << 8) + addr[i + 1]);
444*0Sigor@sysoev.ru 
445*0Sigor@sysoev.ru         if (i < 14) {
446*0Sigor@sysoev.ru             *p++ = ':';
447*0Sigor@sysoev.ru         }
448*0Sigor@sysoev.ru     }
449*0Sigor@sysoev.ru 
450*0Sigor@sysoev.ru     if (ipv6_bytes == 12) {
451*0Sigor@sysoev.ru         p = nxt_sprintf(p, end, "%ud.%ud.%ud.%ud",
452*0Sigor@sysoev.ru                         addr[12], addr[13], addr[14], addr[15]);
453*0Sigor@sysoev.ru     }
454*0Sigor@sysoev.ru 
455*0Sigor@sysoev.ru     return p;
456*0Sigor@sysoev.ru }
457*0Sigor@sysoev.ru 
458*0Sigor@sysoev.ru #endif
459*0Sigor@sysoev.ru 
460*0Sigor@sysoev.ru 
461*0Sigor@sysoev.ru void
462*0Sigor@sysoev.ru nxt_job_sockaddr_parse(nxt_job_sockaddr_parse_t *jbs)
463*0Sigor@sysoev.ru {
464*0Sigor@sysoev.ru     u_char              *p;
465*0Sigor@sysoev.ru     size_t              len;
466*0Sigor@sysoev.ru     nxt_int_t           ret;
467*0Sigor@sysoev.ru     nxt_work_handler_t  handler;
468*0Sigor@sysoev.ru 
469*0Sigor@sysoev.ru     nxt_job_set_name(&jbs->resolve.job, "job sockaddr parse");
470*0Sigor@sysoev.ru 
471*0Sigor@sysoev.ru     len = jbs->addr.len;
472*0Sigor@sysoev.ru     p = jbs->addr.data;
473*0Sigor@sysoev.ru 
474*0Sigor@sysoev.ru     if (len > 6 && nxt_memcmp(p, (u_char *) "unix:", 5) == 0) {
475*0Sigor@sysoev.ru         ret = nxt_job_sockaddr_unix_parse(jbs);
476*0Sigor@sysoev.ru 
477*0Sigor@sysoev.ru     } else if (len != 0 && *p == '[') {
478*0Sigor@sysoev.ru         ret = nxt_job_sockaddr_inet6_parse(jbs);
479*0Sigor@sysoev.ru 
480*0Sigor@sysoev.ru     } else {
481*0Sigor@sysoev.ru         ret = nxt_job_sockaddr_inet_parse(jbs);
482*0Sigor@sysoev.ru     }
483*0Sigor@sysoev.ru 
484*0Sigor@sysoev.ru     switch (ret) {
485*0Sigor@sysoev.ru 
486*0Sigor@sysoev.ru     case NXT_OK:
487*0Sigor@sysoev.ru         handler = jbs->resolve.ready_handler;
488*0Sigor@sysoev.ru         break;
489*0Sigor@sysoev.ru 
490*0Sigor@sysoev.ru     case NXT_ERROR:
491*0Sigor@sysoev.ru         handler = jbs->resolve.error_handler;
492*0Sigor@sysoev.ru         break;
493*0Sigor@sysoev.ru 
494*0Sigor@sysoev.ru     default: /* NXT_AGAIN */
495*0Sigor@sysoev.ru         return;
496*0Sigor@sysoev.ru     }
497*0Sigor@sysoev.ru 
498*0Sigor@sysoev.ru     nxt_job_return(nxt_thread(), &jbs->resolve.job, handler);
499*0Sigor@sysoev.ru }
500*0Sigor@sysoev.ru 
501*0Sigor@sysoev.ru 
502*0Sigor@sysoev.ru static nxt_int_t
503*0Sigor@sysoev.ru nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs)
504*0Sigor@sysoev.ru {
505*0Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
506*0Sigor@sysoev.ru     size_t          len, socklen;
507*0Sigor@sysoev.ru     u_char          *path;
508*0Sigor@sysoev.ru     nxt_mem_pool_t  *mp;
509*0Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
510*0Sigor@sysoev.ru 
511*0Sigor@sysoev.ru     /*
512*0Sigor@sysoev.ru      * Actual sockaddr_un length can be lesser or even larger than defined
513*0Sigor@sysoev.ru      * struct sockaddr_un length (see comment in unix/nxt_socket.h).  So
514*0Sigor@sysoev.ru      * limit maximum Unix domain socket address length by defined sun_path[]
515*0Sigor@sysoev.ru      * length because some OSes accept addresses twice larger than defined
516*0Sigor@sysoev.ru      * struct sockaddr_un.  Also reserve space for a trailing zero to avoid
517*0Sigor@sysoev.ru      * ambiguity, since many OSes accept Unix domain socket addresses
518*0Sigor@sysoev.ru      * without a trailing zero.
519*0Sigor@sysoev.ru      */
520*0Sigor@sysoev.ru     const size_t max_len = sizeof(struct sockaddr_un)
521*0Sigor@sysoev.ru                            - offsetof(struct sockaddr_un, sun_path) - 1;
522*0Sigor@sysoev.ru 
523*0Sigor@sysoev.ru     /* cutting "unix:" */
524*0Sigor@sysoev.ru     len = jbs->addr.len - 5;
525*0Sigor@sysoev.ru     path = jbs->addr.data + 5;
526*0Sigor@sysoev.ru 
527*0Sigor@sysoev.ru     if (len > max_len) {
528*0Sigor@sysoev.ru         nxt_thread_log_error(jbs->resolve.log_level,
529*0Sigor@sysoev.ru                              "unix domain socket \"%V\" name is too long",
530*0Sigor@sysoev.ru                              &jbs->addr);
531*0Sigor@sysoev.ru         return NXT_ERROR;
532*0Sigor@sysoev.ru     }
533*0Sigor@sysoev.ru 
534*0Sigor@sysoev.ru     socklen = offsetof(struct sockaddr_un, sun_path) + len + 1;
535*0Sigor@sysoev.ru 
536*0Sigor@sysoev.ru #if (NXT_LINUX)
537*0Sigor@sysoev.ru 
538*0Sigor@sysoev.ru     /*
539*0Sigor@sysoev.ru      * Linux unix(7):
540*0Sigor@sysoev.ru      *
541*0Sigor@sysoev.ru      *   abstract: an abstract socket address is distinguished by the fact
542*0Sigor@sysoev.ru      *   that sun_path[0] is a null byte ('\0').  The socket's address in
543*0Sigor@sysoev.ru      *   this namespace is given by the additional bytes in sun_path that
544*0Sigor@sysoev.ru      *   are covered by the specified length of the address structure.
545*0Sigor@sysoev.ru      *   (Null bytes in the name have no special significance.)
546*0Sigor@sysoev.ru      */
547*0Sigor@sysoev.ru     if (path[0] == '\0') {
548*0Sigor@sysoev.ru         socklen--;
549*0Sigor@sysoev.ru     }
550*0Sigor@sysoev.ru 
551*0Sigor@sysoev.ru #endif
552*0Sigor@sysoev.ru 
553*0Sigor@sysoev.ru     mp = jbs->resolve.job.mem_pool;
554*0Sigor@sysoev.ru 
555*0Sigor@sysoev.ru     jbs->resolve.sockaddrs = nxt_mem_alloc(mp, sizeof(void *));
556*0Sigor@sysoev.ru 
557*0Sigor@sysoev.ru     if (nxt_fast_path(jbs->resolve.sockaddrs != NULL)) {
558*0Sigor@sysoev.ru         sa = nxt_sockaddr_alloc(mp, socklen);
559*0Sigor@sysoev.ru 
560*0Sigor@sysoev.ru         if (nxt_fast_path(sa != NULL)) {
561*0Sigor@sysoev.ru             jbs->resolve.count = 1;
562*0Sigor@sysoev.ru             jbs->resolve.sockaddrs[0] = sa;
563*0Sigor@sysoev.ru 
564*0Sigor@sysoev.ru             sa->u.sockaddr_un.sun_family = AF_UNIX;
565*0Sigor@sysoev.ru             nxt_memcpy(sa->u.sockaddr_un.sun_path, path, len);
566*0Sigor@sysoev.ru 
567*0Sigor@sysoev.ru             return NXT_OK;
568*0Sigor@sysoev.ru         }
569*0Sigor@sysoev.ru     }
570*0Sigor@sysoev.ru 
571*0Sigor@sysoev.ru     return NXT_ERROR;
572*0Sigor@sysoev.ru 
573*0Sigor@sysoev.ru #else  /* !(NXT_HAVE_UNIX_DOMAIN) */
574*0Sigor@sysoev.ru 
575*0Sigor@sysoev.ru     nxt_thread_log_error(jbs->resolve.log_level,
576*0Sigor@sysoev.ru                          "unix domain socket \"%V\" is not supported",
577*0Sigor@sysoev.ru                          &jbs->addr);
578*0Sigor@sysoev.ru     return NXT_ERROR;
579*0Sigor@sysoev.ru 
580*0Sigor@sysoev.ru #endif
581*0Sigor@sysoev.ru }
582*0Sigor@sysoev.ru 
583*0Sigor@sysoev.ru 
584*0Sigor@sysoev.ru static nxt_int_t
585*0Sigor@sysoev.ru nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs)
586*0Sigor@sysoev.ru {
587*0Sigor@sysoev.ru #if (NXT_INET6)
588*0Sigor@sysoev.ru     u_char           *p, *addr, *addr_end;
589*0Sigor@sysoev.ru     size_t           len;
590*0Sigor@sysoev.ru     nxt_int_t        port;
591*0Sigor@sysoev.ru     nxt_mem_pool_t   *mp;
592*0Sigor@sysoev.ru     nxt_sockaddr_t   *sa;
593*0Sigor@sysoev.ru     struct in6_addr  *in6_addr;
594*0Sigor@sysoev.ru 
595*0Sigor@sysoev.ru     len = jbs->addr.len - 1;
596*0Sigor@sysoev.ru     addr = jbs->addr.data + 1;
597*0Sigor@sysoev.ru 
598*0Sigor@sysoev.ru     addr_end = nxt_memchr(addr, ']', len);
599*0Sigor@sysoev.ru 
600*0Sigor@sysoev.ru     if (addr_end == NULL) {
601*0Sigor@sysoev.ru         goto invalid_address;
602*0Sigor@sysoev.ru     }
603*0Sigor@sysoev.ru 
604*0Sigor@sysoev.ru     mp = jbs->resolve.job.mem_pool;
605*0Sigor@sysoev.ru 
606*0Sigor@sysoev.ru     jbs->resolve.sockaddrs = nxt_mem_alloc(mp, sizeof(void *));
607*0Sigor@sysoev.ru 
608*0Sigor@sysoev.ru     if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) {
609*0Sigor@sysoev.ru         return NXT_ERROR;
610*0Sigor@sysoev.ru     }
611*0Sigor@sysoev.ru 
612*0Sigor@sysoev.ru     sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6));
613*0Sigor@sysoev.ru 
614*0Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
615*0Sigor@sysoev.ru         return NXT_ERROR;
616*0Sigor@sysoev.ru     }
617*0Sigor@sysoev.ru 
618*0Sigor@sysoev.ru     jbs->resolve.count = 1;
619*0Sigor@sysoev.ru     jbs->resolve.sockaddrs[0] = sa;
620*0Sigor@sysoev.ru 
621*0Sigor@sysoev.ru     in6_addr = &sa->u.sockaddr_in6.sin6_addr;
622*0Sigor@sysoev.ru 
623*0Sigor@sysoev.ru     if (nxt_inet6_addr(in6_addr, addr, addr_end - addr) != NXT_OK) {
624*0Sigor@sysoev.ru         goto invalid_address;
625*0Sigor@sysoev.ru     }
626*0Sigor@sysoev.ru 
627*0Sigor@sysoev.ru     p = addr_end + 1;
628*0Sigor@sysoev.ru     len = (addr + len) - p;
629*0Sigor@sysoev.ru 
630*0Sigor@sysoev.ru     if (len == 0) {
631*0Sigor@sysoev.ru         jbs->no_port = 1;
632*0Sigor@sysoev.ru         port = jbs->resolve.port;
633*0Sigor@sysoev.ru         goto found;
634*0Sigor@sysoev.ru     }
635*0Sigor@sysoev.ru 
636*0Sigor@sysoev.ru     if (*p == ':') {
637*0Sigor@sysoev.ru         port = nxt_int_parse(p + 1, len - 1);
638*0Sigor@sysoev.ru 
639*0Sigor@sysoev.ru         if (port >= 1 && port <= 65535) {
640*0Sigor@sysoev.ru             port = htons((in_port_t) port);
641*0Sigor@sysoev.ru             goto found;
642*0Sigor@sysoev.ru         }
643*0Sigor@sysoev.ru     }
644*0Sigor@sysoev.ru 
645*0Sigor@sysoev.ru     nxt_thread_log_error(jbs->resolve.log_level,
646*0Sigor@sysoev.ru                          "invalid port in \"%V\"", &jbs->addr);
647*0Sigor@sysoev.ru 
648*0Sigor@sysoev.ru     return NXT_ERROR;
649*0Sigor@sysoev.ru 
650*0Sigor@sysoev.ru found:
651*0Sigor@sysoev.ru 
652*0Sigor@sysoev.ru     sa->u.sockaddr_in6.sin6_family = AF_INET6;
653*0Sigor@sysoev.ru     sa->u.sockaddr_in6.sin6_port = (in_port_t) port;
654*0Sigor@sysoev.ru 
655*0Sigor@sysoev.ru     if (IN6_IS_ADDR_UNSPECIFIED(in6_addr)) {
656*0Sigor@sysoev.ru         jbs->wildcard = 1;
657*0Sigor@sysoev.ru     }
658*0Sigor@sysoev.ru 
659*0Sigor@sysoev.ru     return NXT_OK;
660*0Sigor@sysoev.ru 
661*0Sigor@sysoev.ru invalid_address:
662*0Sigor@sysoev.ru 
663*0Sigor@sysoev.ru     nxt_thread_log_error(jbs->resolve.log_level,
664*0Sigor@sysoev.ru                          "invalid IPv6 address in \"%V\"", &jbs->addr);
665*0Sigor@sysoev.ru     return NXT_ERROR;
666*0Sigor@sysoev.ru 
667*0Sigor@sysoev.ru #else
668*0Sigor@sysoev.ru 
669*0Sigor@sysoev.ru     nxt_thread_log_error(jbs->resolve.log_level,
670*0Sigor@sysoev.ru                          "IPv6 socket \"%V\" is not supported", &jbs->addr);
671*0Sigor@sysoev.ru     return NXT_ERROR;
672*0Sigor@sysoev.ru 
673*0Sigor@sysoev.ru #endif
674*0Sigor@sysoev.ru }
675*0Sigor@sysoev.ru 
676*0Sigor@sysoev.ru 
677*0Sigor@sysoev.ru static nxt_int_t
678*0Sigor@sysoev.ru nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs)
679*0Sigor@sysoev.ru {
680*0Sigor@sysoev.ru     u_char          *p, *host;
681*0Sigor@sysoev.ru     size_t          len;
682*0Sigor@sysoev.ru     in_addr_t       addr;
683*0Sigor@sysoev.ru     nxt_int_t       port;
684*0Sigor@sysoev.ru     nxt_mem_pool_t  *mp;
685*0Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
686*0Sigor@sysoev.ru 
687*0Sigor@sysoev.ru     addr = INADDR_ANY;
688*0Sigor@sysoev.ru 
689*0Sigor@sysoev.ru     len = jbs->addr.len;
690*0Sigor@sysoev.ru     host = jbs->addr.data;
691*0Sigor@sysoev.ru 
692*0Sigor@sysoev.ru     p = nxt_memchr(host, ':', len);
693*0Sigor@sysoev.ru 
694*0Sigor@sysoev.ru     if (p == NULL) {
695*0Sigor@sysoev.ru 
696*0Sigor@sysoev.ru         /* single value port, address, or host name */
697*0Sigor@sysoev.ru 
698*0Sigor@sysoev.ru         port = nxt_int_parse(host, len);
699*0Sigor@sysoev.ru 
700*0Sigor@sysoev.ru         if (port > 0) {
701*0Sigor@sysoev.ru             if (port < 1 || port > 65535) {
702*0Sigor@sysoev.ru                 goto invalid_port;
703*0Sigor@sysoev.ru             }
704*0Sigor@sysoev.ru 
705*0Sigor@sysoev.ru             /* "*:XX" */
706*0Sigor@sysoev.ru             port = htons((in_port_t) port);
707*0Sigor@sysoev.ru             jbs->resolve.port = (in_port_t) port;
708*0Sigor@sysoev.ru 
709*0Sigor@sysoev.ru         } else {
710*0Sigor@sysoev.ru             jbs->no_port = 1;
711*0Sigor@sysoev.ru 
712*0Sigor@sysoev.ru             addr = nxt_inet_addr(host, len);
713*0Sigor@sysoev.ru 
714*0Sigor@sysoev.ru             if (addr == INADDR_NONE) {
715*0Sigor@sysoev.ru                 jbs->resolve.name.len = len;
716*0Sigor@sysoev.ru                 jbs->resolve.name.data = host;
717*0Sigor@sysoev.ru 
718*0Sigor@sysoev.ru                 nxt_job_resolve(&jbs->resolve);
719*0Sigor@sysoev.ru                 return NXT_AGAIN;
720*0Sigor@sysoev.ru             }
721*0Sigor@sysoev.ru 
722*0Sigor@sysoev.ru             /* "x.x.x.x" */
723*0Sigor@sysoev.ru             port = jbs->resolve.port;
724*0Sigor@sysoev.ru         }
725*0Sigor@sysoev.ru 
726*0Sigor@sysoev.ru     } else {
727*0Sigor@sysoev.ru 
728*0Sigor@sysoev.ru         /* x.x.x.x:XX or host:XX */
729*0Sigor@sysoev.ru 
730*0Sigor@sysoev.ru         p++;
731*0Sigor@sysoev.ru         len = (host + len) - p;
732*0Sigor@sysoev.ru         port = nxt_int_parse(p, len);
733*0Sigor@sysoev.ru 
734*0Sigor@sysoev.ru         if (port < 1 || port > 65535) {
735*0Sigor@sysoev.ru             goto invalid_port;
736*0Sigor@sysoev.ru         }
737*0Sigor@sysoev.ru 
738*0Sigor@sysoev.ru         port = htons((in_port_t) port);
739*0Sigor@sysoev.ru 
740*0Sigor@sysoev.ru         len = (p - 1) - host;
741*0Sigor@sysoev.ru 
742*0Sigor@sysoev.ru         if (len != 1 || host[0] != '*') {
743*0Sigor@sysoev.ru             addr = nxt_inet_addr(host, len);
744*0Sigor@sysoev.ru 
745*0Sigor@sysoev.ru             if (addr == INADDR_NONE) {
746*0Sigor@sysoev.ru                 jbs->resolve.name.len = len;
747*0Sigor@sysoev.ru                 jbs->resolve.name.data = host;
748*0Sigor@sysoev.ru                 jbs->resolve.port = (in_port_t) port;
749*0Sigor@sysoev.ru 
750*0Sigor@sysoev.ru                 nxt_job_resolve(&jbs->resolve);
751*0Sigor@sysoev.ru                 return NXT_AGAIN;
752*0Sigor@sysoev.ru             }
753*0Sigor@sysoev.ru 
754*0Sigor@sysoev.ru             /* "x.x.x.x:XX" */
755*0Sigor@sysoev.ru         }
756*0Sigor@sysoev.ru     }
757*0Sigor@sysoev.ru 
758*0Sigor@sysoev.ru     mp = jbs->resolve.job.mem_pool;
759*0Sigor@sysoev.ru 
760*0Sigor@sysoev.ru     jbs->resolve.sockaddrs = nxt_mem_alloc(mp, sizeof(void *));
761*0Sigor@sysoev.ru     if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) {
762*0Sigor@sysoev.ru         return NXT_ERROR;
763*0Sigor@sysoev.ru     }
764*0Sigor@sysoev.ru 
765*0Sigor@sysoev.ru     sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in));
766*0Sigor@sysoev.ru 
767*0Sigor@sysoev.ru     if (nxt_fast_path(sa != NULL)) {
768*0Sigor@sysoev.ru         jbs->resolve.count = 1;
769*0Sigor@sysoev.ru         jbs->resolve.sockaddrs[0] = sa;
770*0Sigor@sysoev.ru 
771*0Sigor@sysoev.ru         jbs->wildcard = (addr == INADDR_ANY);
772*0Sigor@sysoev.ru 
773*0Sigor@sysoev.ru         sa->u.sockaddr_in.sin_family = AF_INET;
774*0Sigor@sysoev.ru         sa->u.sockaddr_in.sin_port = (in_port_t) port;
775*0Sigor@sysoev.ru         sa->u.sockaddr_in.sin_addr.s_addr = addr;
776*0Sigor@sysoev.ru 
777*0Sigor@sysoev.ru         return NXT_OK;
778*0Sigor@sysoev.ru     }
779*0Sigor@sysoev.ru 
780*0Sigor@sysoev.ru     return NXT_ERROR;
781*0Sigor@sysoev.ru 
782*0Sigor@sysoev.ru invalid_port:
783*0Sigor@sysoev.ru 
784*0Sigor@sysoev.ru     nxt_thread_log_error(jbs->resolve.log_level,
785*0Sigor@sysoev.ru                          "invalid port in \"%V\"", &jbs->addr);
786*0Sigor@sysoev.ru 
787*0Sigor@sysoev.ru     return NXT_ERROR;
788*0Sigor@sysoev.ru }
789*0Sigor@sysoev.ru 
790*0Sigor@sysoev.ru 
791*0Sigor@sysoev.ru in_addr_t
792*0Sigor@sysoev.ru nxt_inet_addr(u_char *buf, size_t len)
793*0Sigor@sysoev.ru {
794*0Sigor@sysoev.ru     u_char      c, *end;
795*0Sigor@sysoev.ru     in_addr_t   addr;
796*0Sigor@sysoev.ru     nxt_uint_t  digit, octet, dots;
797*0Sigor@sysoev.ru 
798*0Sigor@sysoev.ru     addr = 0;
799*0Sigor@sysoev.ru     octet = 0;
800*0Sigor@sysoev.ru     dots = 0;
801*0Sigor@sysoev.ru 
802*0Sigor@sysoev.ru     end = buf + len;
803*0Sigor@sysoev.ru 
804*0Sigor@sysoev.ru     while (buf < end) {
805*0Sigor@sysoev.ru 
806*0Sigor@sysoev.ru         c = *buf++;
807*0Sigor@sysoev.ru 
808*0Sigor@sysoev.ru         digit = c - '0';
809*0Sigor@sysoev.ru         /* values below '0' become large unsigned integers */
810*0Sigor@sysoev.ru 
811*0Sigor@sysoev.ru         if (digit < 10) {
812*0Sigor@sysoev.ru             octet = octet * 10 + digit;
813*0Sigor@sysoev.ru             continue;
814*0Sigor@sysoev.ru         }
815*0Sigor@sysoev.ru 
816*0Sigor@sysoev.ru         if (c == '.' && octet < 256) {
817*0Sigor@sysoev.ru             addr = (addr << 8) + octet;
818*0Sigor@sysoev.ru             octet = 0;
819*0Sigor@sysoev.ru             dots++;
820*0Sigor@sysoev.ru             continue;
821*0Sigor@sysoev.ru         }
822*0Sigor@sysoev.ru 
823*0Sigor@sysoev.ru         return INADDR_NONE;
824*0Sigor@sysoev.ru     }
825*0Sigor@sysoev.ru 
826*0Sigor@sysoev.ru     if (dots == 3 && octet < 256) {
827*0Sigor@sysoev.ru         addr = (addr << 8) + octet;
828*0Sigor@sysoev.ru         return htonl(addr);
829*0Sigor@sysoev.ru     }
830*0Sigor@sysoev.ru 
831*0Sigor@sysoev.ru     return INADDR_NONE;
832*0Sigor@sysoev.ru }
833*0Sigor@sysoev.ru 
834*0Sigor@sysoev.ru 
835*0Sigor@sysoev.ru #if (NXT_INET6)
836*0Sigor@sysoev.ru 
837*0Sigor@sysoev.ru nxt_int_t
838*0Sigor@sysoev.ru nxt_inet6_addr(struct in6_addr *in6_addr, u_char *buf, size_t len)
839*0Sigor@sysoev.ru {
840*0Sigor@sysoev.ru     u_char      c, *addr, *zero_start, *ipv4, *dst, *src, *end;
841*0Sigor@sysoev.ru     nxt_uint_t  digit, group, nibbles, groups_left;
842*0Sigor@sysoev.ru 
843*0Sigor@sysoev.ru     if (len == 0) {
844*0Sigor@sysoev.ru         return NXT_ERROR;
845*0Sigor@sysoev.ru     }
846*0Sigor@sysoev.ru 
847*0Sigor@sysoev.ru     end = buf + len;
848*0Sigor@sysoev.ru 
849*0Sigor@sysoev.ru     if (buf[0] == ':') {
850*0Sigor@sysoev.ru         buf++;
851*0Sigor@sysoev.ru     }
852*0Sigor@sysoev.ru 
853*0Sigor@sysoev.ru     addr = in6_addr->s6_addr;
854*0Sigor@sysoev.ru     zero_start = NULL;
855*0Sigor@sysoev.ru     groups_left = 8;
856*0Sigor@sysoev.ru     nibbles = 0;
857*0Sigor@sysoev.ru     group = 0;
858*0Sigor@sysoev.ru     ipv4 = NULL;
859*0Sigor@sysoev.ru 
860*0Sigor@sysoev.ru     while (buf < end) {
861*0Sigor@sysoev.ru         c = *buf++;
862*0Sigor@sysoev.ru 
863*0Sigor@sysoev.ru         if (c == ':') {
864*0Sigor@sysoev.ru             if (nibbles != 0) {
865*0Sigor@sysoev.ru                 ipv4 = buf;
866*0Sigor@sysoev.ru 
867*0Sigor@sysoev.ru                 *addr++ = (u_char) (group >> 8);
868*0Sigor@sysoev.ru                 *addr++ = (u_char) (group & 0xff);
869*0Sigor@sysoev.ru                 groups_left--;
870*0Sigor@sysoev.ru 
871*0Sigor@sysoev.ru                 if (groups_left != 0) {
872*0Sigor@sysoev.ru                     nibbles = 0;
873*0Sigor@sysoev.ru                     group = 0;
874*0Sigor@sysoev.ru                     continue;
875*0Sigor@sysoev.ru                 }
876*0Sigor@sysoev.ru 
877*0Sigor@sysoev.ru             } else {
878*0Sigor@sysoev.ru                 if (zero_start == NULL) {
879*0Sigor@sysoev.ru                     ipv4 = buf;
880*0Sigor@sysoev.ru                     zero_start = addr;
881*0Sigor@sysoev.ru                     continue;
882*0Sigor@sysoev.ru                 }
883*0Sigor@sysoev.ru             }
884*0Sigor@sysoev.ru 
885*0Sigor@sysoev.ru             return NXT_ERROR;
886*0Sigor@sysoev.ru         }
887*0Sigor@sysoev.ru 
888*0Sigor@sysoev.ru         if (c == '.' && nibbles != 0) {
889*0Sigor@sysoev.ru 
890*0Sigor@sysoev.ru             if (groups_left < 2 || ipv4 == NULL) {
891*0Sigor@sysoev.ru                 return NXT_ERROR;
892*0Sigor@sysoev.ru             }
893*0Sigor@sysoev.ru 
894*0Sigor@sysoev.ru             group = nxt_inet_addr(ipv4, end - ipv4);
895*0Sigor@sysoev.ru             if (group == INADDR_NONE) {
896*0Sigor@sysoev.ru                 return NXT_ERROR;
897*0Sigor@sysoev.ru             }
898*0Sigor@sysoev.ru 
899*0Sigor@sysoev.ru             group = ntohl(group);
900*0Sigor@sysoev.ru 
901*0Sigor@sysoev.ru             *addr++ = (u_char) ((group >> 24) & 0xff);
902*0Sigor@sysoev.ru             *addr++ = (u_char) ((group >> 16) & 0xff);
903*0Sigor@sysoev.ru             groups_left--;
904*0Sigor@sysoev.ru 
905*0Sigor@sysoev.ru             /* the low 16-bit are copied below */
906*0Sigor@sysoev.ru             break;
907*0Sigor@sysoev.ru         }
908*0Sigor@sysoev.ru 
909*0Sigor@sysoev.ru         nibbles++;
910*0Sigor@sysoev.ru 
911*0Sigor@sysoev.ru         if (nibbles > 4) {
912*0Sigor@sysoev.ru             return NXT_ERROR;
913*0Sigor@sysoev.ru         }
914*0Sigor@sysoev.ru 
915*0Sigor@sysoev.ru         group <<= 4;
916*0Sigor@sysoev.ru 
917*0Sigor@sysoev.ru         digit = c - '0';
918*0Sigor@sysoev.ru         /* values below '0' become large unsigned integers */
919*0Sigor@sysoev.ru 
920*0Sigor@sysoev.ru         if (digit < 10) {
921*0Sigor@sysoev.ru             group += digit;
922*0Sigor@sysoev.ru             continue;
923*0Sigor@sysoev.ru         }
924*0Sigor@sysoev.ru 
925*0Sigor@sysoev.ru         c |= 0x20;
926*0Sigor@sysoev.ru         digit = c - 'a';
927*0Sigor@sysoev.ru         /* values below 'a' become large unsigned integers */
928*0Sigor@sysoev.ru 
929*0Sigor@sysoev.ru         if (digit < 6) {
930*0Sigor@sysoev.ru             group += 10 + digit;
931*0Sigor@sysoev.ru             continue;
932*0Sigor@sysoev.ru         }
933*0Sigor@sysoev.ru 
934*0Sigor@sysoev.ru         return NXT_ERROR;
935*0Sigor@sysoev.ru     }
936*0Sigor@sysoev.ru 
937*0Sigor@sysoev.ru     if (nibbles == 0 && zero_start == NULL) {
938*0Sigor@sysoev.ru         return NXT_ERROR;
939*0Sigor@sysoev.ru     }
940*0Sigor@sysoev.ru 
941*0Sigor@sysoev.ru     *addr++ = (u_char) (group >> 8);
942*0Sigor@sysoev.ru     *addr++ = (u_char) (group & 0xff);
943*0Sigor@sysoev.ru     groups_left--;
944*0Sigor@sysoev.ru 
945*0Sigor@sysoev.ru     if (groups_left != 0) {
946*0Sigor@sysoev.ru 
947*0Sigor@sysoev.ru         if (zero_start != NULL) {
948*0Sigor@sysoev.ru 
949*0Sigor@sysoev.ru             /* moving part before consecutive zero groups to the end */
950*0Sigor@sysoev.ru 
951*0Sigor@sysoev.ru             groups_left *= 2;
952*0Sigor@sysoev.ru             src = addr - 1;
953*0Sigor@sysoev.ru             dst = src + groups_left;
954*0Sigor@sysoev.ru 
955*0Sigor@sysoev.ru             while (src >= zero_start) {
956*0Sigor@sysoev.ru                 *dst-- = *src--;
957*0Sigor@sysoev.ru             }
958*0Sigor@sysoev.ru 
959*0Sigor@sysoev.ru             nxt_memzero(zero_start, groups_left);
960*0Sigor@sysoev.ru 
961*0Sigor@sysoev.ru             return NXT_OK;
962*0Sigor@sysoev.ru         }
963*0Sigor@sysoev.ru 
964*0Sigor@sysoev.ru     } else {
965*0Sigor@sysoev.ru         if (zero_start == NULL) {
966*0Sigor@sysoev.ru             return NXT_OK;
967*0Sigor@sysoev.ru         }
968*0Sigor@sysoev.ru     }
969*0Sigor@sysoev.ru 
970*0Sigor@sysoev.ru     return NXT_ERROR;
971*0Sigor@sysoev.ru }
972*0Sigor@sysoev.ru 
973*0Sigor@sysoev.ru #endif
974