Groonga 3.0.9 Source Code Document
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_inet.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 
11 
12 static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u);
13 static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u);
14 static ngx_int_t ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u);
15 
16 
17 in_addr_t
18 ngx_inet_addr(u_char *text, size_t len)
19 {
20  u_char *p, c;
21  in_addr_t addr;
22  ngx_uint_t octet, n;
23 
24  addr = 0;
25  octet = 0;
26  n = 0;
27 
28  for (p = text; p < text + len; p++) {
29 
30  c = *p;
31 
32  if (c >= '0' && c <= '9') {
33  octet = octet * 10 + (c - '0');
34  continue;
35  }
36 
37  if (c == '.' && octet < 256) {
38  addr = (addr << 8) + octet;
39  octet = 0;
40  n++;
41  continue;
42  }
43 
44  return INADDR_NONE;
45  }
46 
47  if (n == 3 && octet < 256) {
48  addr = (addr << 8) + octet;
49  return htonl(addr);
50  }
51 
52  return INADDR_NONE;
53 }
54 
55 
56 #if (NGX_HAVE_INET6)
57 
59 ngx_inet6_addr(u_char *p, size_t len, u_char *addr)
60 {
61  u_char c, *zero, *digit, *s, *d;
62  size_t len4;
63  ngx_uint_t n, nibbles, word;
64 
65  if (len == 0) {
66  return NGX_ERROR;
67  }
68 
69  zero = NULL;
70  digit = NULL;
71  len4 = 0;
72  nibbles = 0;
73  word = 0;
74  n = 8;
75 
76  if (p[0] == ':') {
77  p++;
78  len--;
79  }
80 
81  for (/* void */; len; len--) {
82  c = *p++;
83 
84  if (c == ':') {
85  if (nibbles) {
86  digit = p;
87  len4 = len;
88  *addr++ = (u_char) (word >> 8);
89  *addr++ = (u_char) (word & 0xff);
90 
91  if (--n) {
92  nibbles = 0;
93  word = 0;
94  continue;
95  }
96 
97  } else {
98  if (zero == NULL) {
99  digit = p;
100  len4 = len;
101  zero = addr;
102  continue;
103  }
104  }
105 
106  return NGX_ERROR;
107  }
108 
109  if (c == '.' && nibbles) {
110  if (n < 2 || digit == NULL) {
111  return NGX_ERROR;
112  }
113 
114  word = ngx_inet_addr(digit, len4 - 1);
115  if (word == INADDR_NONE) {
116  return NGX_ERROR;
117  }
118 
119  word = ntohl(word);
120  *addr++ = (u_char) ((word >> 24) & 0xff);
121  *addr++ = (u_char) ((word >> 16) & 0xff);
122  n--;
123  break;
124  }
125 
126  if (++nibbles > 4) {
127  return NGX_ERROR;
128  }
129 
130  if (c >= '0' && c <= '9') {
131  word = word * 16 + (c - '0');
132  continue;
133  }
134 
135  c |= 0x20;
136 
137  if (c >= 'a' && c <= 'f') {
138  word = word * 16 + (c - 'a') + 10;
139  continue;
140  }
141 
142  return NGX_ERROR;
143  }
144 
145  if (nibbles == 0 && zero == NULL) {
146  return NGX_ERROR;
147  }
148 
149  *addr++ = (u_char) (word >> 8);
150  *addr++ = (u_char) (word & 0xff);
151 
152  if (--n) {
153  if (zero) {
154  n *= 2;
155  s = addr - 1;
156  d = s + n;
157  while (s >= zero) {
158  *d-- = *s--;
159  }
160  ngx_memzero(zero, n);
161  return NGX_OK;
162  }
163 
164  } else {
165  if (zero == NULL) {
166  return NGX_OK;
167  }
168  }
169 
170  return NGX_ERROR;
171 }
172 
173 #endif
174 
175 
176 size_t
177 ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, ngx_uint_t port)
178 {
179  u_char *p;
180  struct sockaddr_in *sin;
181 #if (NGX_HAVE_INET6)
182  size_t n;
183  struct sockaddr_in6 *sin6;
184 #endif
185 #if (NGX_HAVE_UNIX_DOMAIN)
186  struct sockaddr_un *saun;
187 #endif
188 
189  switch (sa->sa_family) {
190 
191  case AF_INET:
192 
193  sin = (struct sockaddr_in *) sa;
194  p = (u_char *) &sin->sin_addr;
195 
196  if (port) {
197  p = ngx_snprintf(text, len, "%ud.%ud.%ud.%ud:%d",
198  p[0], p[1], p[2], p[3], ntohs(sin->sin_port));
199  } else {
200  p = ngx_snprintf(text, len, "%ud.%ud.%ud.%ud",
201  p[0], p[1], p[2], p[3]);
202  }
203 
204  return (p - text);
205 
206 #if (NGX_HAVE_INET6)
207 
208  case AF_INET6:
209 
210  sin6 = (struct sockaddr_in6 *) sa;
211 
212  n = 0;
213 
214  if (port) {
215  text[n++] = '[';
216  }
217 
218  n = ngx_inet6_ntop(sin6->sin6_addr.s6_addr, &text[n], len);
219 
220  if (port) {
221  n = ngx_sprintf(&text[1 + n], "]:%d",
222  ntohs(sin6->sin6_port)) - text;
223  }
224 
225  return n;
226 #endif
227 
228 #if (NGX_HAVE_UNIX_DOMAIN)
229 
230  case AF_UNIX:
231  saun = (struct sockaddr_un *) sa;
232 
233  /* we do not include trailing zero in address length */
234 
235  return ngx_snprintf(text, len, "unix:%s%Z", saun->sun_path) - text - 1;
236 
237 #endif
238 
239  default:
240  return 0;
241  }
242 }
243 
244 
245 size_t
246 ngx_inet_ntop(int family, void *addr, u_char *text, size_t len)
247 {
248  u_char *p;
249 
250  switch (family) {
251 
252  case AF_INET:
253 
254  p = addr;
255 
256  return ngx_snprintf(text, len, "%ud.%ud.%ud.%ud",
257  p[0], p[1], p[2], p[3])
258  - text;
259 
260 #if (NGX_HAVE_INET6)
261 
262  case AF_INET6:
263  return ngx_inet6_ntop(addr, text, len);
264 
265 #endif
266 
267  default:
268  return 0;
269  }
270 }
271 
272 
273 #if (NGX_HAVE_INET6)
274 
275 size_t
276 ngx_inet6_ntop(u_char *p, u_char *text, size_t len)
277 {
278  u_char *dst;
279  size_t max, n;
280  ngx_uint_t i, zero, last;
281 
282  if (len < NGX_INET6_ADDRSTRLEN) {
283  return 0;
284  }
285 
286  zero = (ngx_uint_t) -1;
287  last = (ngx_uint_t) -1;
288  max = 1;
289  n = 0;
290 
291  for (i = 0; i < 16; i += 2) {
292 
293  if (p[i] || p[i + 1]) {
294 
295  if (max < n) {
296  zero = last;
297  max = n;
298  }
299 
300  n = 0;
301  continue;
302  }
303 
304  if (n++ == 0) {
305  last = i;
306  }
307  }
308 
309  if (max < n) {
310  zero = last;
311  max = n;
312  }
313 
314  dst = text;
315  n = 16;
316 
317  if (zero == 0) {
318 
319  if ((max == 5 && p[10] == 0xff && p[11] == 0xff)
320  || (max == 6)
321  || (max == 7 && p[14] != 0 && p[15] != 1))
322  {
323  n = 12;
324  }
325 
326  *dst++ = ':';
327  }
328 
329  for (i = 0; i < n; i += 2) {
330 
331  if (i == zero) {
332  *dst++ = ':';
333  i += (max - 1) * 2;
334  continue;
335  }
336 
337  dst = ngx_sprintf(dst, "%uxi", p[i] * 256 + p[i + 1]);
338 
339  if (i < 14) {
340  *dst++ = ':';
341  }
342  }
343 
344  if (n == 12) {
345  dst = ngx_sprintf(dst, "%ud.%ud.%ud.%ud", p[12], p[13], p[14], p[15]);
346  }
347 
348  return dst - text;
349 }
350 
351 #endif
352 
353 
354 ngx_int_t
356 {
357  u_char *addr, *mask, *last;
358  size_t len;
359  ngx_int_t shift;
360 #if (NGX_HAVE_INET6)
361  ngx_int_t rc;
362  ngx_uint_t s, i;
363 #endif
364 
365  addr = text->data;
366  last = addr + text->len;
367 
368  mask = ngx_strlchr(addr, last, '/');
369  len = (mask ? mask : last) - addr;
370 
371  cidr->u.in.addr = ngx_inet_addr(addr, len);
372 
373  if (cidr->u.in.addr != INADDR_NONE) {
374  cidr->family = AF_INET;
375 
376  if (mask == NULL) {
377  cidr->u.in.mask = 0xffffffff;
378  return NGX_OK;
379  }
380 
381 #if (NGX_HAVE_INET6)
382  } else if (ngx_inet6_addr(addr, len, cidr->u.in6.addr.s6_addr) == NGX_OK) {
383  cidr->family = AF_INET6;
384 
385  if (mask == NULL) {
386  ngx_memset(cidr->u.in6.mask.s6_addr, 0xff, 16);
387  return NGX_OK;
388  }
389 
390 #endif
391  } else {
392  return NGX_ERROR;
393  }
394 
395  mask++;
396 
397  shift = ngx_atoi(mask, last - mask);
398  if (shift == NGX_ERROR) {
399  return NGX_ERROR;
400  }
401 
402  switch (cidr->family) {
403 
404 #if (NGX_HAVE_INET6)
405  case AF_INET6:
406  if (shift > 128) {
407  return NGX_ERROR;
408  }
409 
410  addr = cidr->u.in6.addr.s6_addr;
411  mask = cidr->u.in6.mask.s6_addr;
412  rc = NGX_OK;
413 
414  for (i = 0; i < 16; i++) {
415 
416  s = (shift > 8) ? 8 : shift;
417  shift -= s;
418 
419  mask[i] = (u_char) (0xffu << (8 - s));
420 
421  if (addr[i] != (addr[i] & mask[i])) {
422  rc = NGX_DONE;
423  addr[i] &= mask[i];
424  }
425  }
426 
427  return rc;
428 #endif
429 
430  default: /* AF_INET */
431  if (shift > 32) {
432  return NGX_ERROR;
433  }
434 
435  if (shift) {
436  cidr->u.in.mask = htonl((uint32_t) (0xffffffffu << (32 - shift)));
437 
438  } else {
439  /* x86 compilers use a shl instruction that shifts by modulo 32 */
440  cidr->u.in.mask = 0;
441  }
442 
443  if (cidr->u.in.addr == (cidr->u.in.addr & cidr->u.in.mask)) {
444  return NGX_OK;
445  }
446 
447  cidr->u.in.addr &= cidr->u.in.mask;
448 
449  return NGX_DONE;
450  }
451 }
452 
453 
454 ngx_int_t
455 ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t len)
456 {
457  in_addr_t inaddr;
458  ngx_uint_t family;
459  struct sockaddr_in *sin;
460 #if (NGX_HAVE_INET6)
461  struct in6_addr inaddr6;
462  struct sockaddr_in6 *sin6;
463 
464  /*
465  * prevent MSVC8 warning:
466  * potentially uninitialized local variable 'inaddr6' used
467  */
468  ngx_memzero(&inaddr6, sizeof(struct in6_addr));
469 #endif
470 
471  inaddr = ngx_inet_addr(text, len);
472 
473  if (inaddr != INADDR_NONE) {
474  family = AF_INET;
475  len = sizeof(struct sockaddr_in);
476 
477 #if (NGX_HAVE_INET6)
478  } else if (ngx_inet6_addr(text, len, inaddr6.s6_addr) == NGX_OK) {
479  family = AF_INET6;
480  len = sizeof(struct sockaddr_in6);
481 
482 #endif
483  } else {
484  return NGX_DECLINED;
485  }
486 
487  addr->sockaddr = ngx_pcalloc(pool, len);
488  if (addr->sockaddr == NULL) {
489  return NGX_ERROR;
490  }
491 
492  addr->sockaddr->sa_family = (u_char) family;
493  addr->socklen = len;
494 
495  switch (family) {
496 
497 #if (NGX_HAVE_INET6)
498  case AF_INET6:
499  sin6 = (struct sockaddr_in6 *) addr->sockaddr;
500  ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16);
501  break;
502 #endif
503 
504  default: /* AF_INET */
505  sin = (struct sockaddr_in *) addr->sockaddr;
506  sin->sin_addr.s_addr = inaddr;
507  break;
508  }
509 
510  return NGX_OK;
511 }
512 
513 
514 ngx_int_t
516 {
517  u_char *p;
518 
519  p = u->url.data;
520 
521  if (ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) {
522  return ngx_parse_unix_domain_url(pool, u);
523  }
524 
525  if (p[0] == '[') {
526  return ngx_parse_inet6_url(pool, u);
527  }
528 
529  return ngx_parse_inet_url(pool, u);
530 }
531 
532 
533 static ngx_int_t
534 ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u)
535 {
536 #if (NGX_HAVE_UNIX_DOMAIN)
537  u_char *path, *uri, *last;
538  size_t len;
539  struct sockaddr_un *saun;
540 
541  len = u->url.len;
542  path = u->url.data;
543 
544  path += 5;
545  len -= 5;
546 
547  if (u->uri_part) {
548 
549  last = path + len;
550  uri = ngx_strlchr(path, last, ':');
551 
552  if (uri) {
553  len = uri - path;
554  uri++;
555  u->uri.len = last - uri;
556  u->uri.data = uri;
557  }
558  }
559 
560  if (len == 0) {
561  u->err = "no path in the unix domain socket";
562  return NGX_ERROR;
563  }
564 
565  u->host.len = len++;
566  u->host.data = path;
567 
568  if (len > sizeof(saun->sun_path)) {
569  u->err = "too long path in the unix domain socket";
570  return NGX_ERROR;
571  }
572 
573  u->socklen = sizeof(struct sockaddr_un);
574  saun = (struct sockaddr_un *) &u->sockaddr;
575  saun->sun_family = AF_UNIX;
576  (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);
577 
578  u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
579  if (u->addrs == NULL) {
580  return NGX_ERROR;
581  }
582 
583  saun = ngx_pcalloc(pool, sizeof(struct sockaddr_un));
584  if (saun == NULL) {
585  return NGX_ERROR;
586  }
587 
588  u->family = AF_UNIX;
589  u->naddrs = 1;
590 
591  saun->sun_family = AF_UNIX;
592  (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);
593 
594  u->addrs[0].sockaddr = (struct sockaddr *) saun;
595  u->addrs[0].socklen = sizeof(struct sockaddr_un);
596  u->addrs[0].name.len = len + 4;
597  u->addrs[0].name.data = u->url.data;
598 
599  return NGX_OK;
600 
601 #else
602 
603  u->err = "the unix domain sockets are not supported on this platform";
604 
605  return NGX_ERROR;
606 
607 #endif
608 }
609 
610 
611 static ngx_int_t
612 ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u)
613 {
614  u_char *p, *host, *port, *last, *uri, *args;
615  size_t len;
616  ngx_int_t n;
617  struct sockaddr_in *sin;
618 #if (NGX_HAVE_INET6)
619  struct sockaddr_in6 *sin6;
620 #endif
621 
622  u->socklen = sizeof(struct sockaddr_in);
623  sin = (struct sockaddr_in *) &u->sockaddr;
624  sin->sin_family = AF_INET;
625 
626  u->family = AF_INET;
627 
628  host = u->url.data;
629 
630  last = host + u->url.len;
631 
632  port = ngx_strlchr(host, last, ':');
633 
634  uri = ngx_strlchr(host, last, '/');
635 
636  args = ngx_strlchr(host, last, '?');
637 
638  if (args) {
639  if (uri == NULL || args < uri) {
640  uri = args;
641  }
642  }
643 
644  if (uri) {
645  if (u->listen || !u->uri_part) {
646  u->err = "invalid host";
647  return NGX_ERROR;
648  }
649 
650  u->uri.len = last - uri;
651  u->uri.data = uri;
652 
653  last = uri;
654 
655  if (uri < port) {
656  port = NULL;
657  }
658  }
659 
660  if (port) {
661  port++;
662 
663  len = last - port;
664 
665  n = ngx_atoi(port, len);
666 
667  if (n < 1 || n > 65535) {
668  u->err = "invalid port";
669  return NGX_ERROR;
670  }
671 
672  u->port = (in_port_t) n;
673  sin->sin_port = htons((in_port_t) n);
674 
675  u->port_text.len = len;
676  u->port_text.data = port;
677 
678  last = port - 1;
679 
680  } else {
681  if (uri == NULL) {
682 
683  if (u->listen) {
684 
685  /* test value as port only */
686 
687  n = ngx_atoi(host, last - host);
688 
689  if (n != NGX_ERROR) {
690 
691  if (n < 1 || n > 65535) {
692  u->err = "invalid port";
693  return NGX_ERROR;
694  }
695 
696  u->port = (in_port_t) n;
697  sin->sin_port = htons((in_port_t) n);
698 
699  u->port_text.len = last - host;
700  u->port_text.data = host;
701 
702  u->wildcard = 1;
703 
704  return NGX_OK;
705  }
706  }
707  }
708 
709  u->no_port = 1;
710  u->port = u->default_port;
711  sin->sin_port = htons(u->default_port);
712  }
713 
714  len = last - host;
715 
716  if (len == 0) {
717  u->err = "no host";
718  return NGX_ERROR;
719  }
720 
721  u->host.len = len;
722  u->host.data = host;
723 
724  if (u->listen && len == 1 && *host == '*') {
725  sin->sin_addr.s_addr = INADDR_ANY;
726  u->wildcard = 1;
727  return NGX_OK;
728  }
729 
730  sin->sin_addr.s_addr = ngx_inet_addr(host, len);
731 
732  if (sin->sin_addr.s_addr != INADDR_NONE) {
733 
734  if (sin->sin_addr.s_addr == INADDR_ANY) {
735  u->wildcard = 1;
736  }
737 
738  u->naddrs = 1;
739 
740  u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
741  if (u->addrs == NULL) {
742  return NGX_ERROR;
743  }
744 
745  sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
746  if (sin == NULL) {
747  return NGX_ERROR;
748  }
749 
750  ngx_memcpy(sin, u->sockaddr, sizeof(struct sockaddr_in));
751 
752  u->addrs[0].sockaddr = (struct sockaddr *) sin;
753  u->addrs[0].socklen = sizeof(struct sockaddr_in);
754 
755  p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1);
756  if (p == NULL) {
757  return NGX_ERROR;
758  }
759 
760  u->addrs[0].name.len = ngx_sprintf(p, "%V:%d",
761  &u->host, u->port) - p;
762  u->addrs[0].name.data = p;
763 
764  return NGX_OK;
765  }
766 
767  if (u->no_resolve) {
768  return NGX_OK;
769  }
770 
771  if (ngx_inet_resolve_host(pool, u) != NGX_OK) {
772  return NGX_ERROR;
773  }
774 
775  u->family = u->addrs[0].sockaddr->sa_family;
776  u->socklen = u->addrs[0].socklen;
777  ngx_memcpy(u->sockaddr, u->addrs[0].sockaddr, u->addrs[0].socklen);
778 
779  switch (u->family) {
780 
781 #if (NGX_HAVE_INET6)
782  case AF_INET6:
783  sin6 = (struct sockaddr_in6 *) &u->sockaddr;
784 
785  if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
786  u->wildcard = 1;
787  }
788 
789  break;
790 #endif
791 
792  default: /* AF_INET */
793  sin = (struct sockaddr_in *) &u->sockaddr;
794 
795  if (sin->sin_addr.s_addr == INADDR_ANY) {
796  u->wildcard = 1;
797  }
798 
799  break;
800  }
801 
802  return NGX_OK;
803 }
804 
805 
806 static ngx_int_t
807 ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u)
808 {
809 #if (NGX_HAVE_INET6)
810  u_char *p, *host, *port, *last, *uri;
811  size_t len;
812  ngx_int_t n;
813  struct sockaddr_in6 *sin6;
814 
815  u->socklen = sizeof(struct sockaddr_in6);
816  sin6 = (struct sockaddr_in6 *) &u->sockaddr;
817  sin6->sin6_family = AF_INET6;
818 
819  host = u->url.data + 1;
820 
821  last = u->url.data + u->url.len;
822 
823  p = ngx_strlchr(host, last, ']');
824 
825  if (p == NULL) {
826  u->err = "invalid host";
827  return NGX_ERROR;
828  }
829 
830  if (last - p) {
831 
832  port = p + 1;
833 
834  uri = ngx_strlchr(port, last, '/');
835 
836  if (uri) {
837  if (u->listen || !u->uri_part) {
838  u->err = "invalid host";
839  return NGX_ERROR;
840  }
841 
842  u->uri.len = last - uri;
843  u->uri.data = uri;
844 
845  last = uri;
846  }
847 
848  if (*port == ':') {
849  port++;
850 
851  len = last - port;
852 
853  n = ngx_atoi(port, len);
854 
855  if (n < 1 || n > 65535) {
856  u->err = "invalid port";
857  return NGX_ERROR;
858  }
859 
860  u->port = (in_port_t) n;
861  sin6->sin6_port = htons((in_port_t) n);
862 
863  u->port_text.len = len;
864  u->port_text.data = port;
865 
866  } else {
867  u->no_port = 1;
868  u->port = u->default_port;
869  sin6->sin6_port = htons(u->default_port);
870  }
871  }
872 
873  len = p - host;
874 
875  if (len == 0) {
876  u->err = "no host";
877  return NGX_ERROR;
878  }
879 
880  u->host.len = len + 2;
881  u->host.data = host - 1;
882 
883  if (ngx_inet6_addr(host, len, sin6->sin6_addr.s6_addr) != NGX_OK) {
884  u->err = "invalid IPv6 address";
885  return NGX_ERROR;
886  }
887 
888  if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
889  u->wildcard = 1;
890  }
891 
892  u->family = AF_INET6;
893  u->naddrs = 1;
894 
895  u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
896  if (u->addrs == NULL) {
897  return NGX_ERROR;
898  }
899 
900  sin6 = ngx_pcalloc(pool, sizeof(struct sockaddr_in6));
901  if (sin6 == NULL) {
902  return NGX_ERROR;
903  }
904 
905  ngx_memcpy(sin6, u->sockaddr, sizeof(struct sockaddr_in6));
906 
907  u->addrs[0].sockaddr = (struct sockaddr *) sin6;
908  u->addrs[0].socklen = sizeof(struct sockaddr_in6);
909 
910  p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1);
911  if (p == NULL) {
912  return NGX_ERROR;
913  }
914 
915  u->addrs[0].name.len = ngx_sprintf(p, "%V:%d",
916  &u->host, u->port) - p;
917  u->addrs[0].name.data = p;
918 
919  return NGX_OK;
920 
921 #else
922 
923  u->err = "the INET6 sockets are not supported on this platform";
924 
925  return NGX_ERROR;
926 
927 #endif
928 }
929 
930 
931 #if (NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6)
932 
933 ngx_int_t
935 {
936  u_char *p, *host;
937  size_t len;
938  in_port_t port;
939  ngx_uint_t i;
940  struct addrinfo hints, *res, *rp;
941  struct sockaddr_in *sin;
942  struct sockaddr_in6 *sin6;
943 
944  port = htons(u->port);
945 
946  host = ngx_alloc(u->host.len + 1, pool->log);
947  if (host == NULL) {
948  return NGX_ERROR;
949  }
950 
951  (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
952 
953  ngx_memzero(&hints, sizeof(struct addrinfo));
954  hints.ai_family = AF_UNSPEC;
955  hints.ai_socktype = SOCK_STREAM;
956 
957  if (getaddrinfo((char *) host, NULL, &hints, &res) != 0) {
958  u->err = "host not found";
959  ngx_free(host);
960  return NGX_ERROR;
961  }
962 
963  ngx_free(host);
964 
965  for (i = 0, rp = res; rp != NULL; rp = rp->ai_next) {
966 
967  switch (rp->ai_family) {
968 
969  case AF_INET:
970  case AF_INET6:
971  break;
972 
973  default:
974  continue;
975  }
976 
977  i++;
978  }
979 
980  if (i == 0) {
981  u->err = "host not found";
982  goto failed;
983  }
984 
985  /* MP: ngx_shared_palloc() */
986 
987  u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t));
988  if (u->addrs == NULL) {
989  goto failed;
990  }
991 
992  u->naddrs = i;
993 
994  i = 0;
995 
996  /* AF_INET addresses first */
997 
998  for (rp = res; rp != NULL; rp = rp->ai_next) {
999 
1000  if (rp->ai_family != AF_INET) {
1001  continue;
1002  }
1003 
1004  sin = ngx_pcalloc(pool, rp->ai_addrlen);
1005  if (sin == NULL) {
1006  goto failed;
1007  }
1008 
1009  ngx_memcpy(sin, rp->ai_addr, rp->ai_addrlen);
1010 
1011  sin->sin_port = port;
1012 
1013  u->addrs[i].sockaddr = (struct sockaddr *) sin;
1014  u->addrs[i].socklen = rp->ai_addrlen;
1015 
1016  len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
1017 
1018  p = ngx_pnalloc(pool, len);
1019  if (p == NULL) {
1020  goto failed;
1021  }
1022 
1023  len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1);
1024 
1025  u->addrs[i].name.len = len;
1026  u->addrs[i].name.data = p;
1027 
1028  i++;
1029  }
1030 
1031  for (rp = res; rp != NULL; rp = rp->ai_next) {
1032 
1033  if (rp->ai_family != AF_INET6) {
1034  continue;
1035  }
1036 
1037  sin6 = ngx_pcalloc(pool, rp->ai_addrlen);
1038  if (sin6 == NULL) {
1039  goto failed;
1040  }
1041 
1042  ngx_memcpy(sin6, rp->ai_addr, rp->ai_addrlen);
1043 
1044  sin6->sin6_port = port;
1045 
1046  u->addrs[i].sockaddr = (struct sockaddr *) sin6;
1047  u->addrs[i].socklen = rp->ai_addrlen;
1048 
1049  len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1;
1050 
1051  p = ngx_pnalloc(pool, len);
1052  if (p == NULL) {
1053  goto failed;
1054  }
1055 
1056  len = ngx_sock_ntop((struct sockaddr *) sin6, p, len, 1);
1057 
1058  u->addrs[i].name.len = len;
1059  u->addrs[i].name.data = p;
1060 
1061  i++;
1062  }
1063 
1064  freeaddrinfo(res);
1065  return NGX_OK;
1066 
1067 failed:
1068 
1069  freeaddrinfo(res);
1070  return NGX_ERROR;
1071 }
1072 
1073 #else /* !NGX_HAVE_GETADDRINFO || !NGX_HAVE_INET6 */
1074 
1075 ngx_int_t
1077 {
1078  u_char *p, *host;
1079  size_t len;
1080  in_port_t port;
1081  in_addr_t in_addr;
1082  ngx_uint_t i;
1083  struct hostent *h;
1084  struct sockaddr_in *sin;
1085 
1086  /* AF_INET only */
1087 
1088  port = htons(u->port);
1089 
1090  in_addr = ngx_inet_addr(u->host.data, u->host.len);
1091 
1092  if (in_addr == INADDR_NONE) {
1093  host = ngx_alloc(u->host.len + 1, pool->log);
1094  if (host == NULL) {
1095  return NGX_ERROR;
1096  }
1097 
1098  (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
1099 
1100  h = gethostbyname((char *) host);
1101 
1102  ngx_free(host);
1103 
1104  if (h == NULL || h->h_addr_list[0] == NULL) {
1105  u->err = "host not found";
1106  return NGX_ERROR;
1107  }
1108 
1109  for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ }
1110 
1111  /* MP: ngx_shared_palloc() */
1112 
1113  u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t));
1114  if (u->addrs == NULL) {
1115  return NGX_ERROR;
1116  }
1117 
1118  u->naddrs = i;
1119 
1120  for (i = 0; i < u->naddrs; i++) {
1121 
1122  sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
1123  if (sin == NULL) {
1124  return NGX_ERROR;
1125  }
1126 
1127  sin->sin_family = AF_INET;
1128  sin->sin_port = port;
1129  sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]);
1130 
1131  u->addrs[i].sockaddr = (struct sockaddr *) sin;
1132  u->addrs[i].socklen = sizeof(struct sockaddr_in);
1133 
1134  len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
1135 
1136  p = ngx_pnalloc(pool, len);
1137  if (p == NULL) {
1138  return NGX_ERROR;
1139  }
1140 
1141  len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1);
1142 
1143  u->addrs[i].name.len = len;
1144  u->addrs[i].name.data = p;
1145  }
1146 
1147  } else {
1148 
1149  /* MP: ngx_shared_palloc() */
1150 
1151  u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
1152  if (u->addrs == NULL) {
1153  return NGX_ERROR;
1154  }
1155 
1156  sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
1157  if (sin == NULL) {
1158  return NGX_ERROR;
1159  }
1160 
1161  u->naddrs = 1;
1162 
1163  sin->sin_family = AF_INET;
1164  sin->sin_port = port;
1165  sin->sin_addr.s_addr = in_addr;
1166 
1167  u->addrs[0].sockaddr = (struct sockaddr *) sin;
1168  u->addrs[0].socklen = sizeof(struct sockaddr_in);
1169 
1170  p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1);
1171  if (p == NULL) {
1172  return NGX_ERROR;
1173  }
1174 
1175  u->addrs[0].name.len = ngx_sprintf(p, "%V:%d",
1176  &u->host, ntohs(port)) - p;
1177  u->addrs[0].name.data = p;
1178  }
1179 
1180  return NGX_OK;
1181 }
1182 
1183 #endif /* NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6 */