xref: /unit/src/nxt_sockaddr.c (revision 102:8dc96d9dcff7)
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) NGINX, Inc.
5  */
6 
7 #include <nxt_main.h>
8 
9 
10 #if (NXT_INET6)
11 static u_char *nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end);
12 #endif
13 
14 static nxt_sockaddr_t *nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr);
15 static nxt_sockaddr_t *nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr);
16 static nxt_sockaddr_t *nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr);
17 
18 static nxt_int_t nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs);
19 static nxt_int_t nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs);
20 static nxt_int_t nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs);
21 
22 
23 nxt_sockaddr_t *
24 nxt_sockaddr_alloc(nxt_mp_t *mp, socklen_t socklen, size_t address_length)
25 {
26     size_t          size;
27     nxt_sockaddr_t  *sa;
28 
29     size = offsetof(nxt_sockaddr_t, u) + socklen + address_length;
30 
31     /*
32      * The current struct sockaddr's define 32-bit fields at maximum
33      * and may define 64-bit AF_INET6 fields in the future.  Alignment
34      * of memory allocated by nxt_mp_zalloc() is enough for these fields.
35      * If 128-bit alignment will be required then nxt_mem_malloc() and
36      * nxt_memzero() should be used instead.
37      */
38 
39     sa = nxt_mp_zalloc(mp, size);
40 
41     if (nxt_fast_path(sa != NULL)) {
42         sa->socklen = socklen;
43         sa->length = address_length;
44         sa->sockaddr_size = size;
45     }
46 
47     return sa;
48 }
49 
50 
51 nxt_sockaddr_t *
52 nxt_sockaddr_create(nxt_mp_t *mp, struct sockaddr *sockaddr, socklen_t length,
53     size_t address_length)
54 {
55     size_t          size, copy;
56     nxt_sockaddr_t  *sa;
57 
58     size = length;
59     copy = length;
60 
61 #if (NXT_HAVE_UNIX_DOMAIN)
62 
63     /*
64      * Unspecified Unix domain sockaddr_un form and length are very
65      * platform depended (see comment in unix/socket.h).  Here they are
66      * normalized to the sockaddr_un with single zero byte sun_path[].
67      */
68 
69     if (size <= offsetof(struct sockaddr_un, sun_path)) {
70         /*
71          * Small socket length means a short unspecified Unix domain
72          * socket address:
73          *
74          *   getsockname() and getpeername() on OpenBSD prior to 5.3
75          *   return zero length and does not update a passed sockaddr
76          *   buffer at all.
77          *
78          *   Linux returns length equal to 2, i.e. sockaddr_un without
79          *   sun_path[], unix(7):
80          *
81          *     unnamed: A stream socket that has not been bound
82          *     to a pathname using bind(2) has no name.  Likewise,
83          *     the two sockets created by socketpair(2) are unnamed.
84          *     When the address of an unnamed socket is returned by
85          *     getsockname(2), getpeername(2), and accept(2), its
86          *     length is sizeof(sa_family_t), and sun_path should
87          *     not be inspected.
88          */
89         size = offsetof(struct sockaddr_un, sun_path) + 1;
90 
91 #if !(NXT_LINUX)
92 
93     } else if (sockaddr->sa_family == AF_UNIX && sockaddr->sa_data[0] == '\0') {
94         /*
95          * Omit nonsignificant zeros of the unspecified Unix domain socket
96          * address.  This test is disabled for Linux since Linux abstract
97          * socket address also starts with zero.  However Linux unspecified
98          * Unix domain socket address is short and is handled above.
99          */
100         size = offsetof(struct sockaddr_un, sun_path) + 1;
101         copy = size;
102 
103 #endif
104     }
105 
106 #endif  /* NXT_HAVE_UNIX_DOMAIN */
107 
108     sa = nxt_sockaddr_alloc(mp, size, address_length);
109 
110     if (nxt_fast_path(sa != NULL)) {
111         nxt_memcpy(&sa->u.sockaddr, sockaddr, copy);
112 
113 #if (NXT_HAVE_UNIX_DOMAIN && NXT_OPENBSD)
114 
115         if (length == 0) {
116             sa->u.sockaddr.sa_family = AF_UNIX;
117         }
118 
119 #endif
120     }
121 
122     return sa;
123 }
124 
125 
126 nxt_sockaddr_t *
127 nxt_sockaddr_copy(nxt_mp_t *mp, nxt_sockaddr_t *src)
128 {
129     size_t          length;
130     nxt_sockaddr_t  *dst;
131 
132     length = offsetof(nxt_sockaddr_t, u) + src->socklen;
133 
134     dst = nxt_mp_alloc(mp, length);
135 
136     if (nxt_fast_path(dst != NULL)) {
137         nxt_memcpy(dst, src, length);
138     }
139 
140     return dst;
141 }
142 
143 
144 nxt_sockaddr_t *
145 nxt_getsockname(nxt_task_t *task, nxt_mp_t *mp, nxt_socket_t s)
146 {
147     int                 ret;
148     size_t              length;
149     socklen_t           socklen;
150     nxt_sockaddr_buf_t  sockaddr;
151 
152     socklen = NXT_SOCKADDR_LEN;
153 
154     ret = getsockname(s, &sockaddr.buf, &socklen);
155 
156     if (nxt_fast_path(ret == 0)) {
157 
158         switch (sockaddr.buf.sa_family) {
159 #if (NXT_INET6)
160         case AF_INET6:
161              length = NXT_INET6_ADDR_STR_LEN;
162              break;
163 #endif
164 
165 #if (NXT_HAVE_UNIX_DOMAIN)
166         case AF_UNIX:
167              length = sizeof("unix:") - 1 + socklen;
168 #endif
169              break;
170 
171         case AF_INET:
172              length = NXT_INET_ADDR_STR_LEN;
173              break;
174 
175         default:
176              length = 0;
177              break;
178         }
179 
180         return nxt_sockaddr_create(mp, &sockaddr.buf, socklen, length);
181     }
182 
183     nxt_log(task, NXT_LOG_ERR, "getsockname(%d) failed %E", s, nxt_errno);
184 
185     return NULL;
186 }
187 
188 
189 void
190 nxt_sockaddr_text(nxt_sockaddr_t *sa)
191 {
192     size_t    offset;
193     u_char    *p, *start, *end, *octet;
194     uint32_t  port;
195 
196     offset = offsetof(nxt_sockaddr_t, u) + sa->socklen;
197     sa->start = offset;
198 
199     start = nxt_pointer_to(sa, offset);
200     end = nxt_pointer_to(sa, sa->sockaddr_size);
201 
202     switch (sa->u.sockaddr.sa_family) {
203 
204     case AF_INET:
205         sa->address_start = offset;
206 
207         octet = (u_char *) &sa->u.sockaddr_in.sin_addr;
208 
209         p = nxt_sprintf(start, end, "%ud.%ud.%ud.%ud",
210                         octet[0], octet[1], octet[2], octet[3]);
211 
212         sa->address_length = p - start;
213         sa->port_start = sa->address_length + 1;
214 
215         port = sa->u.sockaddr_in.sin_port;
216 
217         break;
218 
219 #if (NXT_INET6)
220 
221     case AF_INET6:
222         sa->address_start = offset + 1;
223 
224         p = start;
225         *p++ = '[';
226 
227         p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end);
228 
229         sa->address_length = p - (start + 1);
230         sa->port_start = sa->address_length + 2;
231 
232         *p++ = ']';
233 
234         port = sa->u.sockaddr_in6.sin6_port;
235 
236         break;
237 
238 #endif
239 
240 #if (NXT_HAVE_UNIX_DOMAIN)
241 
242     case AF_UNIX:
243         sa->address_start = offset;
244 
245         p = (u_char *) sa->u.sockaddr_un.sun_path;
246 
247 #if (NXT_LINUX)
248 
249         if (p[0] == '\0') {
250             int  length;
251 
252             /* Linux abstract socket address has no trailing zero. */
253             length = sa->socklen - offsetof(struct sockaddr_un, sun_path);
254 
255             p = nxt_sprintf(start, end, "unix:@%*s", length - 1, p + 1);
256 
257         } else {
258             p = nxt_sprintf(start, end, "unix:%s", p);
259         }
260 
261 #else  /* !(NXT_LINUX) */
262 
263         p = nxt_sprintf(start, end, "unix:%s", p);
264 
265 #endif
266 
267         sa->address_length = p - start;
268         sa->port_start = sa->address_length;
269         sa->length = p - start;
270 
271         return;
272 
273 #endif  /* NXT_HAVE_UNIX_DOMAIN */
274 
275     default:
276         return;
277     }
278 
279     p = nxt_sprintf(p, end, ":%d", ntohs(port));
280 
281     sa->length = p - start;
282 }
283 
284 
285 uint32_t
286 nxt_sockaddr_port_number(nxt_sockaddr_t *sa)
287 {
288     uint32_t  port;
289 
290     switch (sa->u.sockaddr.sa_family) {
291 
292 #if (NXT_INET6)
293 
294     case AF_INET6:
295         port = sa->u.sockaddr_in6.sin6_port;
296         break;
297 
298 #endif
299 
300 #if (NXT_HAVE_UNIX_DOMAIN)
301 
302     case AF_UNIX:
303         return 0;
304 
305 #endif
306 
307     default:
308         port = sa->u.sockaddr_in.sin_port;
309         break;
310     }
311 
312     return ntohs((uint16_t) port);
313 }
314 
315 
316 nxt_bool_t
317 nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, nxt_sockaddr_t *sa2)
318 {
319     if (sa1->socklen != sa2->socklen) {
320         return 0;
321     }
322 
323     if (sa1->type != sa2->type) {
324         return 0;
325     }
326 
327     if (sa1->u.sockaddr.sa_family != sa2->u.sockaddr.sa_family) {
328         return 0;
329     }
330 
331     /*
332      * sockaddr struct's cannot be compared in whole since kernel
333      * may fill some fields in inherited sockaddr struct's.
334      */
335 
336     switch (sa1->u.sockaddr.sa_family) {
337 
338 #if (NXT_INET6)
339 
340     case AF_INET6:
341         if (sa1->u.sockaddr_in6.sin6_port != sa2->u.sockaddr_in6.sin6_port) {
342             return 0;
343         }
344 
345         if (nxt_memcmp(&sa1->u.sockaddr_in6.sin6_addr,
346                        &sa2->u.sockaddr_in6.sin6_addr, 16)
347             != 0)
348         {
349             return 0;
350         }
351 
352         return 1;
353 
354 #endif
355 
356 #if (NXT_HAVE_UNIX_DOMAIN)
357 
358     case AF_UNIX:
359         {
360             size_t  length;
361 
362             length = sa1->socklen - offsetof(struct sockaddr_un, sun_path);
363 
364             if (nxt_memcmp(&sa1->u.sockaddr_un.sun_path,
365                            &sa2->u.sockaddr_un.sun_path, length)
366                 != 0)
367             {
368                 return 0;
369             }
370 
371             return 1;
372         }
373 
374 #endif
375 
376     default: /* AF_INET */
377         if (sa1->u.sockaddr_in.sin_port != sa2->u.sockaddr_in.sin_port) {
378             return 0;
379         }
380 
381         if (sa1->u.sockaddr_in.sin_addr.s_addr
382             != sa2->u.sockaddr_in.sin_addr.s_addr)
383         {
384             return 0;
385         }
386 
387         return 1;
388     }
389 }
390 
391 
392 size_t
393 nxt_sockaddr_ntop(nxt_sockaddr_t *sa, u_char *buf, u_char *end, nxt_bool_t port)
394 {
395     u_char  *p;
396 
397     switch (sa->u.sockaddr.sa_family) {
398 
399     case AF_INET:
400         p = (u_char *) &sa->u.sockaddr_in.sin_addr;
401 
402         if (port) {
403             p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud:%d",
404                             p[0], p[1], p[2], p[3],
405                             ntohs(sa->u.sockaddr_in.sin_port));
406         } else {
407             p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud",
408                             p[0], p[1], p[2], p[3]);
409         }
410 
411         return p - buf;
412 
413 #if (NXT_INET6)
414 
415     case AF_INET6:
416         p = buf;
417 
418         if (port) {
419             *p++ = '[';
420         }
421 
422         p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end);
423 
424         if (port) {
425             p = nxt_sprintf(p, end, "]:%d",
426                             ntohs(sa->u.sockaddr_in6.sin6_port));
427         }
428 
429         return p - buf;
430 #endif
431 
432 #if (NXT_HAVE_UNIX_DOMAIN)
433 
434     case AF_UNIX:
435 
436 #if (NXT_LINUX)
437 
438         p = (u_char *) sa->u.sockaddr_un.sun_path;
439 
440         if (p[0] == '\0') {
441             int  length;
442 
443             /* Linux abstract socket address has no trailing zero. */
444 
445             length = sa->socklen - offsetof(struct sockaddr_un, sun_path) - 1;
446             p = nxt_sprintf(buf, end, "unix:\\0%*s", length, p + 1);
447 
448         } else {
449             p = nxt_sprintf(buf, end, "unix:%s", p);
450         }
451 
452 #else  /* !(NXT_LINUX) */
453 
454         p = nxt_sprintf(buf, end, "unix:%s", sa->u.sockaddr_un.sun_path);
455 
456 #endif
457 
458         return p - buf;
459 
460 #endif  /* NXT_HAVE_UNIX_DOMAIN */
461 
462     default:
463         return 0;
464     }
465 }
466 
467 
468 #if (NXT_INET6)
469 
470 static u_char *
471 nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end)
472 {
473     u_char       *p;
474     size_t       zero_groups, last_zero_groups, ipv6_bytes;
475     nxt_uint_t   i, zero_start, last_zero_start;
476 
477     const size_t  max_inet6_length =
478                       sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") - 1;
479 
480     if (buf + max_inet6_length > end) {
481         return buf;
482     }
483 
484     zero_start = 8;
485     zero_groups = 0;
486     last_zero_start = 8;
487     last_zero_groups = 0;
488 
489     for (i = 0; i < 16; i += 2) {
490 
491         if (addr[i] == 0 && addr[i + 1] == 0) {
492 
493             if (last_zero_groups == 0) {
494                 last_zero_start = i;
495             }
496 
497             last_zero_groups++;
498 
499         } else {
500             if (zero_groups < last_zero_groups) {
501                 zero_groups = last_zero_groups;
502                 zero_start = last_zero_start;
503             }
504 
505             last_zero_groups = 0;
506         }
507     }
508 
509     if (zero_groups < last_zero_groups) {
510         zero_groups = last_zero_groups;
511         zero_start = last_zero_start;
512     }
513 
514     ipv6_bytes = 16;
515     p = buf;
516 
517     if (zero_start == 0) {
518 
519                /* IPv4-mapped address */
520         if ((zero_groups == 5 && addr[10] == 0xff && addr[11] == 0xff)
521                /* IPv4-compatible address */
522             || (zero_groups == 6)
523                /* not IPv6 loopback address */
524             || (zero_groups == 7 && addr[14] != 0 && addr[15] != 1))
525         {
526             ipv6_bytes = 12;
527         }
528 
529         *p++ = ':';
530     }
531 
532     for (i = 0; i < ipv6_bytes; i += 2) {
533 
534         if (i == zero_start) {
535             /* Output maximum number of consecutive zero groups as "::". */
536             i += (zero_groups - 1) * 2;
537             *p++ = ':';
538             continue;
539         }
540 
541         p = nxt_sprintf(p, end, "%uxd", (addr[i] << 8) + addr[i + 1]);
542 
543         if (i < 14) {
544             *p++ = ':';
545         }
546     }
547 
548     if (ipv6_bytes == 12) {
549         p = nxt_sprintf(p, end, "%ud.%ud.%ud.%ud",
550                         addr[12], addr[13], addr[14], addr[15]);
551     }
552 
553     return p;
554 }
555 
556 #endif
557 
558 
559 nxt_sockaddr_t *
560 nxt_sockaddr_parse(nxt_mp_t *mp, nxt_str_t *addr)
561 {
562     nxt_sockaddr_t  *sa;
563 
564     if (addr->length > 6 && nxt_memcmp(addr->start, "unix:", 5) == 0) {
565         sa = nxt_sockaddr_unix_parse(mp, addr);
566 
567     } else if (addr->length != 0 && addr->start[0] == '[') {
568         sa = nxt_sockaddr_inet6_parse(mp, addr);
569 
570     } else {
571         sa = nxt_sockaddr_inet_parse(mp, addr);
572     }
573 
574     if (nxt_fast_path(sa != NULL)) {
575         nxt_sockaddr_text(sa);
576     }
577 
578     return sa;
579 }
580 
581 
582 static nxt_sockaddr_t *
583 nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr)
584 {
585 #if (NXT_HAVE_UNIX_DOMAIN)
586     size_t          length, socklen;
587     u_char          *path;
588     nxt_sockaddr_t  *sa;
589 
590     /*
591      * Actual sockaddr_un length can be lesser or even larger than defined
592      * struct sockaddr_un length (see comment in unix/nxt_socket.h).  So
593      * limit maximum Unix domain socket address length by defined sun_path[]
594      * length because some OSes accept addresses twice larger than defined
595      * struct sockaddr_un.  Also reserve space for a trailing zero to avoid
596      * ambiguity, since many OSes accept Unix domain socket addresses
597      * without a trailing zero.
598      */
599     const size_t max_len = sizeof(struct sockaddr_un)
600                            - offsetof(struct sockaddr_un, sun_path) - 1;
601 
602     /* Cutting "unix:". */
603     length = addr->length - 5;
604     path = addr->start + 5;
605 
606     if (length > max_len) {
607         nxt_thread_log_error(NXT_LOG_ERR,
608                              "unix domain socket \"%V\" name is too long",
609                              addr);
610         return NULL;
611     }
612 
613     socklen = offsetof(struct sockaddr_un, sun_path) + length + 1;
614 
615 #if (NXT_LINUX)
616 
617     /*
618      * Linux unix(7):
619      *
620      *   abstract: an abstract socket address is distinguished by the fact
621      *   that sun_path[0] is a null byte ('\0').  The socket's address in
622      *   this namespace is given by the additional bytes in sun_path that
623      *   are covered by the specified length of the address structure.
624      *   (Null bytes in the name have no special significance.)
625      */
626     if (path[0] == '@') {
627         path[0] = '\0';
628         socklen--;
629     }
630 
631 #endif
632 
633     sa = nxt_sockaddr_alloc(mp, socklen, addr->length);
634 
635     if (nxt_fast_path(sa != NULL)) {
636         sa->u.sockaddr_un.sun_family = AF_UNIX;
637         nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length);
638     }
639 
640     return sa;
641 
642 #else  /* !(NXT_HAVE_UNIX_DOMAIN) */
643 
644     nxt_thread_log_error(NXT_LOG_ERR,
645                          "unix domain socket \"%V\" is not supported", addr);
646 
647     return NULL;
648 
649 #endif
650 }
651 
652 
653 static nxt_sockaddr_t *
654 nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr)
655 {
656 #if (NXT_INET6)
657     u_char          *p, *start, *end;
658     size_t          length;
659     nxt_int_t       ret, port;
660     nxt_sockaddr_t  *sa;
661 
662     length = addr->length - 1;
663     start = addr->start + 1;
664 
665     end = nxt_memchr(start, ']', length);
666 
667     if (end != NULL) {
668         sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6),
669                                 NXT_INET6_ADDR_STR_LEN);
670         if (nxt_slow_path(sa == NULL)) {
671             return NULL;
672         }
673 
674         ret = nxt_inet6_addr(&sa->u.sockaddr_in6.sin6_addr, start, end - start);
675 
676         if (nxt_fast_path(ret == NXT_OK)) {
677             p = end + 1;
678             length = (start + length) - p;
679 
680             if (length > 2 && *p == ':') {
681                 port = nxt_int_parse(p + 1, length - 1);
682 
683                 if (port > 0 && port < 65536) {
684                     sa->u.sockaddr_in6.sin6_port = htons((in_port_t) port);
685                     sa->u.sockaddr_in6.sin6_family = AF_INET6;
686 
687                     return sa;
688                 }
689             }
690 
691             nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr);
692 
693             return NULL;
694         }
695     }
696 
697     nxt_thread_log_error(NXT_LOG_ERR, "invalid IPv6 address in \"%V\"", addr);
698 
699     return NULL;
700 
701 #else  /* !(NXT_INET6) */
702 
703     nxt_thread_log_error(NXT_LOG_ERR, "IPv6 socket \"%V\" is not supported",
704                          addr);
705     return NULL;
706 
707 #endif
708 }
709 
710 
711 static nxt_sockaddr_t *
712 nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr)
713 {
714     u_char          *p;
715     size_t          length;
716     nxt_int_t       port;
717     in_addr_t       inaddr;
718     nxt_sockaddr_t  *sa;
719 
720     p = nxt_memchr(addr->start, ':', addr->length);
721 
722     if (nxt_fast_path(p != NULL)) {
723         inaddr = INADDR_ANY;
724         length = p - addr->start;
725 
726         if (length != 1 || addr->start[0] != '*') {
727             inaddr = nxt_inet_addr(addr->start, length);
728 
729             if (nxt_slow_path(inaddr == INADDR_NONE)) {
730                 nxt_thread_log_error(NXT_LOG_ERR, "invalid address \"%V\"",
731                                      addr);
732                 return NULL;
733             }
734         }
735 
736         p++;
737         length = (addr->start + addr->length) - p;
738         port = nxt_int_parse(p, length);
739 
740         if (port > 0 && port < 65536) {
741             sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in),
742                                     NXT_INET_ADDR_STR_LEN);
743 
744             if (nxt_slow_path(sa != NULL)) {
745                 sa->u.sockaddr_in.sin_family = AF_INET;
746                 sa->u.sockaddr_in.sin_port = htons((in_port_t) port);
747                 sa->u.sockaddr_in.sin_addr.s_addr = inaddr;
748             }
749 
750             return sa;
751         }
752     }
753 
754     nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr);
755 
756     return NULL;
757 }
758 
759 
760 void
761 nxt_job_sockaddr_parse(nxt_job_sockaddr_parse_t *jbs)
762 {
763     u_char              *p;
764     size_t              length;
765     nxt_int_t           ret;
766     nxt_work_handler_t  handler;
767 
768     nxt_job_set_name(&jbs->resolve.job, "job sockaddr parse");
769 
770     length = jbs->addr.length;
771     p = jbs->addr.start;
772 
773     if (length > 6 && nxt_memcmp(p, "unix:", 5) == 0) {
774         ret = nxt_job_sockaddr_unix_parse(jbs);
775 
776     } else if (length != 0 && *p == '[') {
777         ret = nxt_job_sockaddr_inet6_parse(jbs);
778 
779     } else {
780         ret = nxt_job_sockaddr_inet_parse(jbs);
781     }
782 
783     switch (ret) {
784 
785     case NXT_OK:
786         handler = jbs->resolve.ready_handler;
787         break;
788 
789     case NXT_ERROR:
790         handler = jbs->resolve.error_handler;
791         break;
792 
793     default: /* NXT_AGAIN */
794         return;
795     }
796 
797     nxt_job_return(jbs->resolve.job.task, &jbs->resolve.job, handler);
798 }
799 
800 
801 static nxt_int_t
802 nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs)
803 {
804 #if (NXT_HAVE_UNIX_DOMAIN)
805     size_t          length, socklen;
806     u_char          *path;
807     nxt_mp_t        *mp;
808     nxt_sockaddr_t  *sa;
809 
810     /*
811      * Actual sockaddr_un length can be lesser or even larger than defined
812      * struct sockaddr_un length (see comment in unix/nxt_socket.h).  So
813      * limit maximum Unix domain socket address length by defined sun_path[]
814      * length because some OSes accept addresses twice larger than defined
815      * struct sockaddr_un.  Also reserve space for a trailing zero to avoid
816      * ambiguity, since many OSes accept Unix domain socket addresses
817      * without a trailing zero.
818      */
819     const size_t max_len = sizeof(struct sockaddr_un)
820                            - offsetof(struct sockaddr_un, sun_path) - 1;
821 
822     /* cutting "unix:" */
823     length = jbs->addr.length - 5;
824     path = jbs->addr.start + 5;
825 
826     if (length > max_len) {
827         nxt_thread_log_error(jbs->resolve.log_level,
828                              "unix domain socket \"%V\" name is too long",
829                              &jbs->addr);
830         return NXT_ERROR;
831     }
832 
833     socklen = offsetof(struct sockaddr_un, sun_path) + length + 1;
834 
835 #if (NXT_LINUX)
836 
837     /*
838      * Linux unix(7):
839      *
840      *   abstract: an abstract socket address is distinguished by the fact
841      *   that sun_path[0] is a null byte ('\0').  The socket's address in
842      *   this namespace is given by the additional bytes in sun_path that
843      *   are covered by the specified length of the address structure.
844      *   (Null bytes in the name have no special significance.)
845      */
846     if (path[0] == '\0') {
847         socklen--;
848     }
849 
850 #endif
851 
852     mp = jbs->resolve.job.mem_pool;
853 
854     jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *));
855 
856     if (nxt_fast_path(jbs->resolve.sockaddrs != NULL)) {
857         sa = nxt_sockaddr_alloc(mp, socklen, jbs->addr.length);
858 
859         if (nxt_fast_path(sa != NULL)) {
860             jbs->resolve.count = 1;
861             jbs->resolve.sockaddrs[0] = sa;
862 
863             sa->u.sockaddr_un.sun_family = AF_UNIX;
864             nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length);
865 
866             return NXT_OK;
867         }
868     }
869 
870     return NXT_ERROR;
871 
872 #else  /* !(NXT_HAVE_UNIX_DOMAIN) */
873 
874     nxt_thread_log_error(jbs->resolve.log_level,
875                          "unix domain socket \"%V\" is not supported",
876                          &jbs->addr);
877     return NXT_ERROR;
878 
879 #endif
880 }
881 
882 
883 static nxt_int_t
884 nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs)
885 {
886 #if (NXT_INET6)
887     u_char           *p, *addr, *addr_end;
888     size_t           length;
889     nxt_mp_t         *mp;
890     nxt_int_t        port;
891     nxt_sockaddr_t   *sa;
892     struct in6_addr  *in6_addr;
893 
894     length = jbs->addr.length - 1;
895     addr = jbs->addr.start + 1;
896 
897     addr_end = nxt_memchr(addr, ']', length);
898 
899     if (addr_end == NULL) {
900         goto invalid_address;
901     }
902 
903     mp = jbs->resolve.job.mem_pool;
904 
905     jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *));
906 
907     if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) {
908         return NXT_ERROR;
909     }
910 
911     sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6),
912                             NXT_INET6_ADDR_STR_LEN);
913 
914     if (nxt_slow_path(sa == NULL)) {
915         return NXT_ERROR;
916     }
917 
918     jbs->resolve.count = 1;
919     jbs->resolve.sockaddrs[0] = sa;
920 
921     in6_addr = &sa->u.sockaddr_in6.sin6_addr;
922 
923     if (nxt_inet6_addr(in6_addr, addr, addr_end - addr) != NXT_OK) {
924         goto invalid_address;
925     }
926 
927     p = addr_end + 1;
928     length = (addr + length) - p;
929 
930     if (length == 0) {
931         jbs->no_port = 1;
932         port = jbs->resolve.port;
933         goto found;
934     }
935 
936     if (*p == ':') {
937         port = nxt_int_parse(p + 1, length - 1);
938 
939         if (port >= 1 && port <= 65535) {
940             port = htons((in_port_t) port);
941             goto found;
942         }
943     }
944 
945     nxt_thread_log_error(jbs->resolve.log_level,
946                          "invalid port in \"%V\"", &jbs->addr);
947 
948     return NXT_ERROR;
949 
950 found:
951 
952     sa->u.sockaddr_in6.sin6_family = AF_INET6;
953     sa->u.sockaddr_in6.sin6_port = (in_port_t) port;
954 
955     if (IN6_IS_ADDR_UNSPECIFIED(in6_addr)) {
956         jbs->wildcard = 1;
957     }
958 
959     return NXT_OK;
960 
961 invalid_address:
962 
963     nxt_thread_log_error(jbs->resolve.log_level,
964                          "invalid IPv6 address in \"%V\"", &jbs->addr);
965     return NXT_ERROR;
966 
967 #else
968 
969     nxt_thread_log_error(jbs->resolve.log_level,
970                          "IPv6 socket \"%V\" is not supported", &jbs->addr);
971     return NXT_ERROR;
972 
973 #endif
974 }
975 
976 
977 static nxt_int_t
978 nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs)
979 {
980     u_char          *p, *host;
981     size_t          length;
982     nxt_mp_t        *mp;
983     nxt_int_t       port;
984     in_addr_t       addr;
985     nxt_sockaddr_t  *sa;
986 
987     addr = INADDR_ANY;
988 
989     length = jbs->addr.length;
990     host = jbs->addr.start;
991 
992     p = nxt_memchr(host, ':', length);
993 
994     if (p == NULL) {
995 
996         /* single value port, address, or host name */
997 
998         port = nxt_int_parse(host, length);
999 
1000         if (port > 0) {
1001             if (port < 1 || port > 65535) {
1002                 goto invalid_port;
1003             }
1004 
1005             /* "*:XX" */
1006             port = htons((in_port_t) port);
1007             jbs->resolve.port = (in_port_t) port;
1008 
1009         } else {
1010             jbs->no_port = 1;
1011 
1012             addr = nxt_inet_addr(host, length);
1013 
1014             if (addr == INADDR_NONE) {
1015                 jbs->resolve.name.length = length;
1016                 jbs->resolve.name.start = host;
1017 
1018                 nxt_job_resolve(&jbs->resolve);
1019                 return NXT_AGAIN;
1020             }
1021 
1022             /* "x.x.x.x" */
1023             port = jbs->resolve.port;
1024         }
1025 
1026     } else {
1027 
1028         /* x.x.x.x:XX or host:XX */
1029 
1030         p++;
1031         length = (host + length) - p;
1032         port = nxt_int_parse(p, length);
1033 
1034         if (port < 1 || port > 65535) {
1035             goto invalid_port;
1036         }
1037 
1038         port = htons((in_port_t) port);
1039 
1040         length = (p - 1) - host;
1041 
1042         if (length != 1 || host[0] != '*') {
1043             addr = nxt_inet_addr(host, length);
1044 
1045             if (addr == INADDR_NONE) {
1046                 jbs->resolve.name.length = length;
1047                 jbs->resolve.name.start = host;
1048                 jbs->resolve.port = (in_port_t) port;
1049 
1050                 nxt_job_resolve(&jbs->resolve);
1051                 return NXT_AGAIN;
1052             }
1053 
1054             /* "x.x.x.x:XX" */
1055         }
1056     }
1057 
1058     mp = jbs->resolve.job.mem_pool;
1059 
1060     jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *));
1061     if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) {
1062         return NXT_ERROR;
1063     }
1064 
1065     sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in),
1066                             NXT_INET_ADDR_STR_LEN);
1067 
1068     if (nxt_fast_path(sa != NULL)) {
1069         jbs->resolve.count = 1;
1070         jbs->resolve.sockaddrs[0] = sa;
1071 
1072         jbs->wildcard = (addr == INADDR_ANY);
1073 
1074         sa->u.sockaddr_in.sin_family = AF_INET;
1075         sa->u.sockaddr_in.sin_port = (in_port_t) port;
1076         sa->u.sockaddr_in.sin_addr.s_addr = addr;
1077 
1078         return NXT_OK;
1079     }
1080 
1081     return NXT_ERROR;
1082 
1083 invalid_port:
1084 
1085     nxt_thread_log_error(jbs->resolve.log_level,
1086                          "invalid port in \"%V\"", &jbs->addr);
1087 
1088     return NXT_ERROR;
1089 }
1090 
1091 
1092 in_addr_t
1093 nxt_inet_addr(u_char *buf, size_t length)
1094 {
1095     u_char      c, *end;
1096     in_addr_t   addr;
1097     nxt_uint_t  digit, octet, dots;
1098 
1099     addr = 0;
1100     octet = 0;
1101     dots = 0;
1102 
1103     end = buf + length;
1104 
1105     while (buf < end) {
1106 
1107         c = *buf++;
1108 
1109         digit = c - '0';
1110         /* values below '0' become large unsigned integers */
1111 
1112         if (digit < 10) {
1113             octet = octet * 10 + digit;
1114             continue;
1115         }
1116 
1117         if (c == '.' && octet < 256) {
1118             addr = (addr << 8) + octet;
1119             octet = 0;
1120             dots++;
1121             continue;
1122         }
1123 
1124         return INADDR_NONE;
1125     }
1126 
1127     if (dots == 3 && octet < 256) {
1128         addr = (addr << 8) + octet;
1129         return htonl(addr);
1130     }
1131 
1132     return INADDR_NONE;
1133 }
1134 
1135 
1136 #if (NXT_INET6)
1137 
1138 nxt_int_t
1139 nxt_inet6_addr(struct in6_addr *in6_addr, u_char *buf, size_t length)
1140 {
1141     u_char      c, *addr, *zero_start, *ipv4, *dst, *src, *end;
1142     nxt_uint_t  digit, group, nibbles, groups_left;
1143 
1144     if (length == 0) {
1145         return NXT_ERROR;
1146     }
1147 
1148     end = buf + length;
1149 
1150     if (buf[0] == ':') {
1151         buf++;
1152     }
1153 
1154     addr = in6_addr->s6_addr;
1155     zero_start = NULL;
1156     groups_left = 8;
1157     nibbles = 0;
1158     group = 0;
1159     ipv4 = NULL;
1160 
1161     while (buf < end) {
1162         c = *buf++;
1163 
1164         if (c == ':') {
1165             if (nibbles != 0) {
1166                 ipv4 = buf;
1167 
1168                 *addr++ = (u_char) (group >> 8);
1169                 *addr++ = (u_char) (group & 0xff);
1170                 groups_left--;
1171 
1172                 if (groups_left != 0) {
1173                     nibbles = 0;
1174                     group = 0;
1175                     continue;
1176                 }
1177 
1178             } else {
1179                 if (zero_start == NULL) {
1180                     ipv4 = buf;
1181                     zero_start = addr;
1182                     continue;
1183                 }
1184             }
1185 
1186             return NXT_ERROR;
1187         }
1188 
1189         if (c == '.' && nibbles != 0) {
1190 
1191             if (groups_left < 2 || ipv4 == NULL) {
1192                 return NXT_ERROR;
1193             }
1194 
1195             group = nxt_inet_addr(ipv4, end - ipv4);
1196             if (group == INADDR_NONE) {
1197                 return NXT_ERROR;
1198             }
1199 
1200             group = ntohl(group);
1201 
1202             *addr++ = (u_char) ((group >> 24) & 0xff);
1203             *addr++ = (u_char) ((group >> 16) & 0xff);
1204             groups_left--;
1205 
1206             /* the low 16-bit are copied below */
1207             break;
1208         }
1209 
1210         nibbles++;
1211 
1212         if (nibbles > 4) {
1213             return NXT_ERROR;
1214         }
1215 
1216         group <<= 4;
1217 
1218         digit = c - '0';
1219         /* values below '0' become large unsigned integers */
1220 
1221         if (digit < 10) {
1222             group += digit;
1223             continue;
1224         }
1225 
1226         c |= 0x20;
1227         digit = c - 'a';
1228         /* values below 'a' become large unsigned integers */
1229 
1230         if (digit < 6) {
1231             group += 10 + digit;
1232             continue;
1233         }
1234 
1235         return NXT_ERROR;
1236     }
1237 
1238     if (nibbles == 0 && zero_start == NULL) {
1239         return NXT_ERROR;
1240     }
1241 
1242     *addr++ = (u_char) (group >> 8);
1243     *addr++ = (u_char) (group & 0xff);
1244     groups_left--;
1245 
1246     if (groups_left != 0) {
1247 
1248         if (zero_start != NULL) {
1249 
1250             /* moving part before consecutive zero groups to the end */
1251 
1252             groups_left *= 2;
1253             src = addr - 1;
1254             dst = src + groups_left;
1255 
1256             while (src >= zero_start) {
1257                 *dst-- = *src--;
1258             }
1259 
1260             nxt_memzero(zero_start, groups_left);
1261 
1262             return NXT_OK;
1263         }
1264 
1265     } else {
1266         if (zero_start == NULL) {
1267             return NXT_OK;
1268         }
1269     }
1270 
1271     return NXT_ERROR;
1272 }
1273 
1274 #endif
1275