]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
75bd9771 | 2 | * "$Id: http-addrlist.c 7460 2008-04-16 02:19:54Z mike $" |
ef416fc2 | 3 | * |
4 | * HTTP address list routines for the Common UNIX Printing System (CUPS). | |
5 | * | |
91c84a35 | 6 | * Copyright 2007-2008 by Apple Inc. |
b86bc4cf | 7 | * Copyright 1997-2007 by Easy Software Products, all rights reserved. |
ef416fc2 | 8 | * |
9 | * These coded instructions, statements, and computer programs are the | |
bc44d920 | 10 | * property of Apple Inc. and are protected by Federal copyright |
11 | * law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
12 | * which should have been included with this file. If this file is | |
13 | * file is missing or damaged, see the license at "http://www.cups.org/". | |
ef416fc2 | 14 | * |
15 | * Contents: | |
16 | * | |
17 | * httpAddrConnect() - Connect to any of the addresses in the list. | |
18 | * httpAddrFreeList() - Free an address list. | |
19 | * httpAddrGetList() - Get a list of addresses for a hostname. | |
20 | */ | |
21 | ||
22 | /* | |
23 | * Include necessary headers... | |
24 | */ | |
25 | ||
26 | #include "http-private.h" | |
27 | #include "globals.h" | |
28 | #include "debug.h" | |
29 | #include <stdlib.h> | |
1ff0402e | 30 | #include <errno.h> |
49d87452 MS |
31 | #ifdef HAVE_RESOLV_H |
32 | # include <resolv.h> | |
33 | #endif /* HAVE_RESOLV_H */ | |
ef416fc2 | 34 | |
35 | ||
36 | /* | |
37 | * 'httpAddrConnect()' - Connect to any of the addresses in the list. | |
38 | * | |
39 | * @since CUPS 1.2@ | |
40 | */ | |
41 | ||
42 | http_addrlist_t * /* O - Connected address or NULL on failure */ | |
43 | httpAddrConnect( | |
44 | http_addrlist_t *addrlist, /* I - List of potential addresses */ | |
45 | int *sock) /* O - Socket */ | |
46 | { | |
47 | int val; /* Socket option value */ | |
1ff0402e MS |
48 | #ifdef DEBUG |
49 | char temp[256]; /* Temporary address string */ | |
50 | #endif /* DEBUG */ | |
ef416fc2 | 51 | |
52 | ||
1ff0402e MS |
53 | DEBUG_printf(("httpAddrConnect(addrlist=%p, sock=%p)\n", addrlist, sock)); |
54 | ||
55 | if (!sock) | |
56 | { | |
57 | errno = EINVAL; | |
58 | return (NULL); | |
59 | } | |
60 | ||
ef416fc2 | 61 | /* |
62 | * Loop through each address until we connect or run out of addresses... | |
63 | */ | |
64 | ||
65 | while (addrlist) | |
66 | { | |
67 | /* | |
68 | * Create the socket... | |
69 | */ | |
70 | ||
1ff0402e MS |
71 | DEBUG_printf(("httpAddrConnect: Trying %s:%d...\n", |
72 | httpAddrString(&(addrlist->addr), temp, sizeof(temp)), | |
73 | _httpAddrPort(&(addrlist->addr)))); | |
74 | ||
75 | if ((*sock = (int)socket(addrlist->addr.addr.sa_family, SOCK_STREAM, | |
76 | 0)) < 0) | |
ef416fc2 | 77 | { |
78 | /* | |
79 | * Don't abort yet, as this could just be an issue with the local | |
80 | * system not being configured with IPv4/IPv6/domain socket enabled... | |
81 | */ | |
82 | ||
83 | addrlist = addrlist->next; | |
84 | continue; | |
85 | } | |
86 | ||
87 | /* | |
88 | * Set options... | |
89 | */ | |
90 | ||
91 | val = 1; | |
92 | #ifdef WIN32 | |
93 | setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, | |
94 | sizeof(val)); | |
95 | #else | |
96 | setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); | |
97 | #endif /* WIN32 */ | |
98 | ||
99 | #ifdef SO_REUSEPORT | |
100 | val = 1; | |
101 | setsockopt(*sock, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)); | |
102 | #endif /* SO_REUSEPORT */ | |
103 | ||
fa73b229 | 104 | #ifdef SO_NOSIGPIPE |
105 | val = 1; | |
106 | setsockopt(*sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val)); | |
107 | #endif /* SO_NOSIGPIPE */ | |
108 | ||
ef416fc2 | 109 | /* |
110 | * Using TCP_NODELAY improves responsiveness, especially on systems | |
111 | * with a slow loopback interface... | |
112 | */ | |
113 | ||
114 | val = 1; | |
115 | #ifdef WIN32 | |
116 | setsockopt(*sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&val, | |
117 | sizeof(val)); | |
118 | #else | |
119 | setsockopt(*sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); | |
120 | #endif /* WIN32 */ | |
121 | ||
122 | #ifdef FD_CLOEXEC | |
123 | /* | |
124 | * Close this socket when starting another process... | |
125 | */ | |
126 | ||
127 | fcntl(*sock, F_SETFD, FD_CLOEXEC); | |
128 | #endif /* FD_CLOEXEC */ | |
129 | ||
130 | /* | |
131 | * Then connect... | |
132 | */ | |
133 | ||
134 | if (!connect(*sock, &(addrlist->addr.addr), | |
135 | httpAddrLength(&(addrlist->addr)))) | |
1ff0402e MS |
136 | { |
137 | DEBUG_printf(("httpAddrConnect: Connected to %s:%d...\n", | |
138 | httpAddrString(&(addrlist->addr), temp, sizeof(temp)), | |
139 | _httpAddrPort(&(addrlist->addr)))); | |
ef416fc2 | 140 | break; |
1ff0402e MS |
141 | } |
142 | ||
143 | DEBUG_printf(("httpAddrConnect: Unable to connect to %s:%d: %s\n", | |
144 | httpAddrString(&(addrlist->addr), temp, sizeof(temp)), | |
145 | _httpAddrPort(&(addrlist->addr)), strerror(errno))); | |
ef416fc2 | 146 | |
147 | /* | |
148 | * Close this socket and move to the next address... | |
149 | */ | |
150 | ||
bd7854cb | 151 | #ifdef WIN32 |
ef416fc2 | 152 | closesocket(*sock); |
bd7854cb | 153 | #else |
154 | close(*sock); | |
155 | #endif /* WIN32 */ | |
ef416fc2 | 156 | |
1ff0402e | 157 | *sock = -1; |
ef416fc2 | 158 | addrlist = addrlist->next; |
159 | } | |
160 | ||
161 | return (addrlist); | |
162 | } | |
163 | ||
164 | ||
165 | /* | |
166 | * 'httpAddrFreeList()' - Free an address list. | |
167 | * | |
168 | * @since CUPS 1.2@ | |
169 | */ | |
170 | ||
171 | void | |
172 | httpAddrFreeList( | |
173 | http_addrlist_t *addrlist) /* I - Address list to free */ | |
174 | { | |
175 | http_addrlist_t *next; /* Next address in list */ | |
176 | ||
177 | ||
178 | /* | |
179 | * Free each address in the list... | |
180 | */ | |
181 | ||
182 | while (addrlist) | |
183 | { | |
184 | next = addrlist->next; | |
185 | ||
186 | free(addrlist); | |
187 | ||
188 | addrlist = next; | |
189 | } | |
190 | } | |
191 | ||
192 | ||
193 | /* | |
194 | * 'httpAddrGetList()' - Get a list of addresses for a hostname. | |
195 | * | |
196 | * @since CUPS 1.2@ | |
197 | */ | |
198 | ||
199 | http_addrlist_t * /* O - List of addresses or NULL */ | |
200 | httpAddrGetList(const char *hostname, /* I - Hostname, IP address, or NULL for passive listen address */ | |
201 | int family, /* I - Address family or AF_UNSPEC */ | |
202 | const char *service) /* I - Service name or port number */ | |
203 | { | |
204 | http_addrlist_t *first, /* First address in list */ | |
205 | *addr, /* Current address in list */ | |
206 | *temp; /* New address */ | |
49d87452 MS |
207 | _cups_globals_t *cg = _cupsGlobals(); |
208 | /* Global data */ | |
ef416fc2 | 209 | |
210 | ||
211 | #ifdef DEBUG | |
ae71f5de MS |
212 | _cups_debug_printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, " |
213 | "service=\"%s\")\n", | |
214 | hostname ? hostname : "(nil)", | |
215 | family == AF_UNSPEC ? "UNSPEC" : | |
ef416fc2 | 216 | # ifdef AF_LOCAL |
ae71f5de | 217 | family == AF_LOCAL ? "LOCAL" : |
ef416fc2 | 218 | # endif /* AF_LOCAL */ |
219 | # ifdef AF_INET6 | |
ae71f5de | 220 | family == AF_INET6 ? "INET6" : |
ef416fc2 | 221 | # endif /* AF_INET6 */ |
ae71f5de | 222 | family == AF_INET ? "INET" : "???", service); |
ef416fc2 | 223 | #endif /* DEBUG */ |
224 | ||
49d87452 MS |
225 | #ifdef HAVE_RES_INIT |
226 | /* | |
227 | * STR #2920: Initialize resolver after failure in cups-polld | |
228 | * | |
229 | * If the previous lookup failed, re-initialize the resolver to prevent | |
230 | * temporary network errors from persisting. This *should* be handled by | |
231 | * the resolver libraries, but apparently the glibc folks do not agree. | |
232 | * | |
233 | * We set a flag at the end of this function if we encounter an error that | |
234 | * requires reinitialization of the resolver functions. We then call | |
235 | * res_init() if the flag is set on the next call here or in httpAddrLookup(). | |
236 | */ | |
237 | ||
238 | if (cg->need_res_init) | |
239 | { | |
240 | res_init(); | |
241 | ||
242 | cg->need_res_init = 0; | |
243 | } | |
244 | #endif /* HAVE_RES_INIT */ | |
245 | ||
246 | ||
ef416fc2 | 247 | /* |
248 | * Lookup the address the best way we can... | |
249 | */ | |
250 | ||
251 | first = addr = NULL; | |
252 | ||
253 | #ifdef AF_LOCAL | |
254 | if (hostname && hostname[0] == '/') | |
255 | { | |
256 | /* | |
257 | * Domain socket address... | |
258 | */ | |
259 | ||
91c84a35 MS |
260 | if ((first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t))) != NULL) |
261 | { | |
262 | first->addr.un.sun_family = AF_LOCAL; | |
263 | strlcpy(first->addr.un.sun_path, hostname, sizeof(first->addr.un.sun_path)); | |
264 | } | |
ef416fc2 | 265 | } |
266 | else | |
267 | #endif /* AF_LOCAL */ | |
268 | { | |
269 | #ifdef HAVE_GETADDRINFO | |
270 | struct addrinfo hints, /* Address lookup hints */ | |
271 | *results, /* Address lookup results */ | |
272 | *current; /* Current result */ | |
273 | char ipv6[1024], /* IPv6 address */ | |
274 | *ipv6zone; /* Pointer to zone separator */ | |
275 | int ipv6len; /* Length of IPv6 address */ | |
49d87452 MS |
276 | int error; /* getaddrinfo() error */ |
277 | ||
ef416fc2 | 278 | |
279 | /* | |
280 | * Lookup the address as needed... | |
281 | */ | |
282 | ||
283 | memset(&hints, 0, sizeof(hints)); | |
284 | hints.ai_family = family; | |
285 | hints.ai_flags = hostname ? 0 : AI_PASSIVE; | |
286 | hints.ai_socktype = SOCK_STREAM; | |
287 | ||
288 | if (hostname && *hostname == '[') | |
289 | { | |
290 | /* | |
291 | * Remove brackets from numeric IPv6 address... | |
292 | */ | |
293 | ||
294 | if (!strncmp(hostname, "[v1.", 4)) | |
295 | { | |
296 | /* | |
297 | * Copy the newer address format which supports link-local addresses... | |
298 | */ | |
299 | ||
300 | strlcpy(ipv6, hostname + 4, sizeof(ipv6)); | |
b86bc4cf | 301 | if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']') |
ef416fc2 | 302 | { |
303 | ipv6[ipv6len] = '\0'; | |
304 | hostname = ipv6; | |
305 | ||
306 | /* | |
307 | * Convert "+zone" in address to "%zone"... | |
308 | */ | |
309 | ||
310 | if ((ipv6zone = strrchr(ipv6, '+')) != NULL) | |
311 | *ipv6zone = '%'; | |
312 | } | |
313 | } | |
314 | else | |
315 | { | |
316 | /* | |
317 | * Copy the regular non-link-local IPv6 address... | |
318 | */ | |
319 | ||
320 | strlcpy(ipv6, hostname + 1, sizeof(ipv6)); | |
b86bc4cf | 321 | if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']') |
ef416fc2 | 322 | { |
323 | ipv6[ipv6len] = '\0'; | |
324 | hostname = ipv6; | |
325 | } | |
326 | } | |
327 | } | |
328 | ||
49d87452 | 329 | if ((error = getaddrinfo(hostname, service, &hints, &results)) == 0) |
ef416fc2 | 330 | { |
331 | /* | |
332 | * Copy the results to our own address list structure... | |
333 | */ | |
334 | ||
335 | for (current = results; current; current = current->ai_next) | |
336 | if (current->ai_family == AF_INET || current->ai_family == AF_INET6) | |
337 | { | |
338 | /* | |
339 | * Copy the address over... | |
340 | */ | |
341 | ||
342 | temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); | |
343 | if (!temp) | |
344 | { | |
345 | httpAddrFreeList(first); | |
346 | return (NULL); | |
347 | } | |
348 | ||
349 | if (current->ai_family == AF_INET6) | |
350 | memcpy(&(temp->addr.ipv6), current->ai_addr, | |
351 | sizeof(temp->addr.ipv6)); | |
352 | else | |
353 | memcpy(&(temp->addr.ipv4), current->ai_addr, | |
354 | sizeof(temp->addr.ipv4)); | |
355 | ||
356 | /* | |
357 | * Append the address to the list... | |
358 | */ | |
359 | ||
360 | if (!first) | |
361 | first = temp; | |
362 | ||
363 | if (addr) | |
364 | addr->next = temp; | |
365 | ||
366 | addr = temp; | |
367 | } | |
368 | ||
369 | /* | |
370 | * Free the results from getaddrinfo()... | |
371 | */ | |
372 | ||
373 | freeaddrinfo(results); | |
374 | } | |
49d87452 MS |
375 | else if (error == EAI_FAIL) |
376 | cg->need_res_init = 1; | |
377 | ||
ef416fc2 | 378 | #else |
379 | if (hostname) | |
380 | { | |
381 | int i; /* Looping vars */ | |
382 | unsigned ip[4]; /* IPv4 address components */ | |
383 | const char *ptr; /* Pointer into hostname */ | |
384 | struct hostent *host; /* Result of lookup */ | |
385 | struct servent *port; /* Port number for service */ | |
386 | int portnum; /* Port number */ | |
387 | ||
388 | ||
389 | /* | |
390 | * Lookup the service... | |
391 | */ | |
392 | ||
393 | if (!service) | |
394 | portnum = 0; | |
395 | else if (isdigit(*service & 255)) | |
396 | portnum = atoi(service); | |
397 | else if ((port = getservbyname(service, NULL)) != NULL) | |
398 | portnum = ntohs(port->s_port); | |
399 | else if (!strcmp(service, "http")) | |
400 | portnum = 80; | |
401 | else if (!strcmp(service, "https")) | |
402 | portnum = 443; | |
403 | else if (!strcmp(service, "ipp")) | |
404 | portnum = 631; | |
405 | else if (!strcmp(service, "lpd")) | |
406 | portnum = 515; | |
407 | else if (!strcmp(service, "socket")) | |
408 | portnum = 9100; | |
409 | else | |
410 | return (NULL); | |
411 | ||
412 | /* | |
413 | * This code is needed because some operating systems have a | |
414 | * buggy implementation of gethostbyname() that does not support | |
415 | * IPv4 addresses. If the hostname string is an IPv4 address, then | |
416 | * sscanf() is used to extract the IPv4 components. We then pack | |
417 | * the components into an IPv4 address manually, since the | |
418 | * inet_aton() function is deprecated. We use the htonl() macro | |
419 | * to get the right byte order for the address. | |
420 | */ | |
421 | ||
422 | for (ptr = hostname; isdigit(*ptr & 255) || *ptr == '.'; ptr ++); | |
423 | ||
424 | if (!*ptr) | |
425 | { | |
426 | /* | |
427 | * We have an IPv4 address; break it up and create an IPv4 address... | |
428 | */ | |
429 | ||
430 | if (sscanf(hostname, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) == 4 && | |
431 | ip[0] <= 255 && ip[1] <= 255 && ip[2] <= 255 && ip[3] <= 255) | |
432 | { | |
433 | first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); | |
434 | if (!first) | |
435 | return (NULL); | |
436 | ||
437 | first->addr.ipv4.sin_family = AF_INET; | |
438 | first->addr.ipv4.sin_addr.s_addr = htonl(((((((ip[0] << 8) | | |
439 | ip[1]) << 8) | | |
440 | ip[2]) << 8) | ip[3])); | |
441 | first->addr.ipv4.sin_port = htons(portnum); | |
442 | } | |
443 | } | |
444 | else if ((host = gethostbyname(hostname)) != NULL && | |
445 | # ifdef AF_INET6 | |
446 | (host->h_addrtype == AF_INET || host->h_addrtype == AF_INET6)) | |
447 | # else | |
448 | host->h_addrtype == AF_INET) | |
449 | # endif /* AF_INET6 */ | |
450 | { | |
451 | for (i = 0; host->h_addr_list[i]; i ++) | |
452 | { | |
453 | /* | |
454 | * Copy the address over... | |
455 | */ | |
456 | ||
457 | temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); | |
458 | if (!temp) | |
459 | { | |
460 | httpAddrFreeList(first); | |
461 | return (NULL); | |
462 | } | |
463 | ||
464 | # ifdef AF_INET6 | |
465 | if (host->h_addrtype == AF_INET6) | |
466 | { | |
d6ae789d | 467 | temp->addr.ipv6.sin6_family = AF_INET6; |
ed486911 | 468 | memcpy(&(temp->addr.ipv6.sin6_addr), host->h_addr_list[i], |
ef416fc2 | 469 | sizeof(temp->addr.ipv6)); |
470 | temp->addr.ipv6.sin6_port = htons(portnum); | |
471 | } | |
472 | else | |
473 | # endif /* AF_INET6 */ | |
474 | { | |
d6ae789d | 475 | temp->addr.ipv4.sin_family = AF_INET; |
ed486911 | 476 | memcpy(&(temp->addr.ipv4.sin_addr), host->h_addr_list[i], |
ef416fc2 | 477 | sizeof(temp->addr.ipv4)); |
478 | temp->addr.ipv4.sin_port = htons(portnum); | |
479 | } | |
480 | ||
481 | /* | |
482 | * Append the address to the list... | |
483 | */ | |
484 | ||
485 | if (!first) | |
486 | first = temp; | |
487 | ||
488 | if (addr) | |
489 | addr->next = temp; | |
490 | ||
491 | addr = temp; | |
492 | } | |
493 | } | |
49d87452 MS |
494 | else if (h_errno == NO_RECOVERY) |
495 | cg->need_res_init = 1; | |
ef416fc2 | 496 | } |
497 | #endif /* HAVE_GETADDRINFO */ | |
498 | } | |
499 | ||
500 | /* | |
501 | * Detect some common errors and handle them sanely... | |
502 | */ | |
503 | ||
504 | if (!addr && (!hostname || !strcmp(hostname, "localhost"))) | |
505 | { | |
506 | struct servent *port; /* Port number for service */ | |
507 | int portnum; /* Port number */ | |
508 | ||
509 | ||
510 | /* | |
511 | * Lookup the service... | |
512 | */ | |
513 | ||
514 | if (!service) | |
515 | portnum = 0; | |
516 | else if (isdigit(*service & 255)) | |
517 | portnum = atoi(service); | |
518 | else if ((port = getservbyname(service, NULL)) != NULL) | |
519 | portnum = ntohs(port->s_port); | |
520 | else if (!strcmp(service, "http")) | |
521 | portnum = 80; | |
522 | else if (!strcmp(service, "https")) | |
523 | portnum = 443; | |
524 | else if (!strcmp(service, "ipp")) | |
525 | portnum = 631; | |
526 | else if (!strcmp(service, "lpd")) | |
527 | portnum = 515; | |
528 | else if (!strcmp(service, "socket")) | |
529 | portnum = 9100; | |
530 | else | |
531 | return (NULL); | |
532 | ||
533 | if (hostname && !strcmp(hostname, "localhost")) | |
534 | { | |
535 | /* | |
536 | * Unfortunately, some users ignore all of the warnings in the | |
537 | * /etc/hosts file and delete "localhost" from it. If we get here | |
538 | * then we were unable to resolve the name, so use the IPv6 and/or | |
539 | * IPv4 loopback interface addresses... | |
540 | */ | |
541 | ||
542 | #ifdef AF_INET6 | |
543 | if (family != AF_INET) | |
544 | { | |
545 | /* | |
546 | * Add [::1] to the address list... | |
547 | */ | |
548 | ||
549 | temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); | |
550 | if (!temp) | |
551 | { | |
552 | httpAddrFreeList(first); | |
553 | return (NULL); | |
554 | } | |
555 | ||
556 | temp->addr.ipv6.sin6_family = AF_INET6; | |
557 | temp->addr.ipv6.sin6_port = htons(portnum); | |
558 | # ifdef WIN32 | |
559 | temp->addr.ipv6.sin6_addr.u.Byte[15] = 1; | |
560 | # else | |
561 | temp->addr.ipv6.sin6_addr.s6_addr32[3] = htonl(1); | |
562 | # endif /* WIN32 */ | |
563 | ||
ed486911 | 564 | if (!first) |
565 | first = temp; | |
566 | ||
ef416fc2 | 567 | addr = temp; |
568 | } | |
569 | ||
570 | if (family != AF_INET6) | |
571 | #endif /* AF_INET6 */ | |
572 | { | |
573 | /* | |
574 | * Add 127.0.0.1 to the address list... | |
575 | */ | |
576 | ||
577 | temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); | |
578 | if (!temp) | |
579 | { | |
580 | httpAddrFreeList(first); | |
581 | return (NULL); | |
582 | } | |
583 | ||
584 | temp->addr.ipv4.sin_family = AF_INET; | |
585 | temp->addr.ipv4.sin_port = htons(portnum); | |
586 | temp->addr.ipv4.sin_addr.s_addr = htonl(0x7f000001); | |
587 | ||
ed486911 | 588 | if (!first) |
589 | first = temp; | |
590 | ||
ef416fc2 | 591 | if (addr) |
592 | addr->next = temp; | |
ef416fc2 | 593 | } |
594 | } | |
595 | else if (!hostname) | |
596 | { | |
597 | /* | |
598 | * Provide one or more passive listening addresses... | |
599 | */ | |
600 | ||
601 | #ifdef AF_INET6 | |
602 | if (family != AF_INET) | |
603 | { | |
604 | /* | |
605 | * Add [::] to the address list... | |
606 | */ | |
607 | ||
608 | temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); | |
609 | if (!temp) | |
610 | { | |
611 | httpAddrFreeList(first); | |
612 | return (NULL); | |
613 | } | |
614 | ||
615 | temp->addr.ipv6.sin6_family = AF_INET6; | |
616 | temp->addr.ipv6.sin6_port = htons(portnum); | |
617 | ||
ed486911 | 618 | if (!first) |
619 | first = temp; | |
620 | ||
ef416fc2 | 621 | addr = temp; |
622 | } | |
623 | ||
624 | if (family != AF_INET6) | |
625 | #endif /* AF_INET6 */ | |
626 | { | |
627 | /* | |
628 | * Add 0.0.0.0 to the address list... | |
629 | */ | |
630 | ||
631 | temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); | |
632 | if (!temp) | |
633 | { | |
634 | httpAddrFreeList(first); | |
635 | return (NULL); | |
636 | } | |
637 | ||
638 | temp->addr.ipv4.sin_family = AF_INET; | |
639 | temp->addr.ipv4.sin_port = htons(portnum); | |
640 | ||
ed486911 | 641 | if (!first) |
642 | first = temp; | |
643 | ||
ef416fc2 | 644 | if (addr) |
645 | addr->next = temp; | |
ef416fc2 | 646 | } |
647 | } | |
648 | } | |
649 | ||
650 | /* | |
651 | * Return the address list... | |
652 | */ | |
653 | ||
654 | return (first); | |
655 | } | |
656 | ||
657 | ||
658 | /* | |
75bd9771 | 659 | * End of "$Id: http-addrlist.c 7460 2008-04-16 02:19:54Z mike $". |
ef416fc2 | 660 | */ |