]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/http-addrlist.c
Changes to eliminate warnings from new Clang.
[thirdparty/cups.git] / cups / http-addrlist.c
1 /*
2 * "$Id$"
3 *
4 * HTTP address list routines for CUPS.
5 *
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 *
9 * These coded instructions, statements, and computer programs are the
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/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 */
17
18 /*
19 * Include necessary headers...
20 */
21
22 #include "cups-private.h"
23 #ifdef HAVE_RESOLV_H
24 # include <resolv.h>
25 #endif /* HAVE_RESOLV_H */
26 #ifdef HAVE_POLL
27 # include <poll.h>
28 #endif /* HAVE_POLL */
29 #ifndef WIN32
30 # include <fcntl.h>
31 #endif /* WIN32 */
32
33
34 /*
35 * 'httpAddrConnect()' - Connect to any of the addresses in the list.
36 *
37 * @since CUPS 1.2/OS X 10.5@
38 */
39
40 http_addrlist_t * /* O - Connected address or NULL on failure */
41 httpAddrConnect(
42 http_addrlist_t *addrlist, /* I - List of potential addresses */
43 int *sock) /* O - Socket */
44 {
45 DEBUG_printf(("httpAddrConnect(addrlist=%p, sock=%p)", (void *)addrlist, (void *)sock));
46
47 return (httpAddrConnect2(addrlist, sock, 30000, NULL));
48 }
49
50
51 /*
52 * 'httpAddrConnect2()' - Connect to any of the addresses in the list with a
53 * timeout and optional cancel.
54 *
55 * @since CUPS 1.7/OS X 10.9@
56 */
57
58 http_addrlist_t * /* O - Connected address or NULL on failure */
59 httpAddrConnect2(
60 http_addrlist_t *addrlist, /* I - List of potential addresses */
61 int *sock, /* O - Socket */
62 int msec, /* I - Timeout in milliseconds */
63 int *cancel) /* I - Pointer to "cancel" variable */
64 {
65 int val; /* Socket option value */
66 #ifdef O_NONBLOCK
67 socklen_t len; /* Length of value */
68 http_addr_t peer; /* Peer address */
69 int flags, /* Socket flags */
70 remaining; /* Remaining timeout */
71 int i, /* Looping var */
72 nfds, /* Number of file descriptors */
73 fds[100], /* Socket file descriptors */
74 result; /* Result from select() or poll() */
75 http_addrlist_t *addrs[100]; /* Addresses */
76 # ifdef HAVE_POLL
77 struct pollfd pfds[100]; /* Polled file descriptors */
78 # else
79 int max_fd = -1; /* Highest file descriptor */
80 fd_set input_set, /* select() input set */
81 output_set; /* select() output set */
82 struct timeval timeout; /* Timeout */
83 # endif /* HAVE_POLL */
84 #endif /* O_NONBLOCK */
85 #ifdef DEBUG
86 char temp[256]; /* Temporary address string */
87 #endif /* DEBUG */
88
89
90 DEBUG_printf(("httpAddrConnect2(addrlist=%p, sock=%p, msec=%d, cancel=%p)", (void *)addrlist, (void *)sock, msec, (void *)cancel));
91
92 if (!sock)
93 {
94 errno = EINVAL;
95 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
96 return (NULL);
97 }
98
99 if (cancel && *cancel)
100 return (NULL);
101
102 if (msec <= 0)
103 msec = INT_MAX;
104
105 /*
106 * Loop through each address until we connect or run out of addresses...
107 */
108
109 for (nfds = 0; addrlist && nfds < (int)(sizeof(fds) / sizeof(fds[0])); addrlist = addrlist->next)
110 {
111 if (cancel && *cancel)
112 {
113 while (nfds > 0)
114 {
115 nfds --;
116 httpAddrClose(NULL, fds[nfds]);
117 }
118
119 return (NULL);
120 }
121
122 /*
123 * Create the socket...
124 */
125
126 DEBUG_printf(("2httpAddrConnect2: Trying %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr))));
127
128 if ((fds[nfds] = (int)socket(httpAddrFamily(&(addrlist->addr)), SOCK_STREAM, 0)) < 0)
129 {
130 /*
131 * Don't abort yet, as this could just be an issue with the local
132 * system not being configured with IPv4/IPv6/domain socket enabled...
133 */
134
135 continue;
136 }
137
138 /*
139 * Set options...
140 */
141
142 val = 1;
143 setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val));
144
145 #ifdef SO_REUSEPORT
146 val = 1;
147 setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEPORT, CUPS_SOCAST &val, sizeof(val));
148 #endif /* SO_REUSEPORT */
149
150 #ifdef SO_NOSIGPIPE
151 val = 1;
152 setsockopt(fds[nfds], SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val));
153 #endif /* SO_NOSIGPIPE */
154
155 /*
156 * Using TCP_NODELAY improves responsiveness, especially on systems
157 * with a slow loopback interface...
158 */
159
160 val = 1;
161 setsockopt(fds[nfds], IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val));
162
163 #ifdef FD_CLOEXEC
164 /*
165 * Close this socket when starting another process...
166 */
167
168 fcntl(fds[nfds], F_SETFD, FD_CLOEXEC);
169 #endif /* FD_CLOEXEC */
170
171 #ifdef O_NONBLOCK
172 /*
173 * Do an asynchronous connect by setting the socket non-blocking...
174 */
175
176 DEBUG_printf(("httpAddrConnect2: Setting non-blocking connect()"));
177
178 flags = fcntl(fds[nfds], F_GETFL, 0);
179 fcntl(fds[nfds], F_SETFL, flags | O_NONBLOCK);
180 #endif /* O_NONBLOCK */
181
182 /*
183 * Then connect...
184 */
185
186 if (!connect(fds[nfds], &(addrlist->addr.addr), (socklen_t)httpAddrLength(&(addrlist->addr))))
187 {
188 DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr))));
189
190 #ifdef O_NONBLOCK
191 fcntl(fds[nfds], F_SETFL, flags);
192 #endif /* O_NONBLOCK */
193
194 *sock = fds[nfds];
195
196 while (nfds > 0)
197 {
198 nfds --;
199 httpAddrClose(NULL, fds[nfds]);
200 }
201
202 return (addrlist);
203 }
204
205 #ifdef WIN32
206 if (WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK)
207 #else
208 if (errno != EINPROGRESS && errno != EWOULDBLOCK)
209 #endif /* WIN32 */
210 {
211 DEBUG_printf(("1httpAddrConnect2: Unable to connect to %s:%d: %s", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)), strerror(errno)));
212 httpAddrClose(NULL, fds[nfds]);
213 continue;
214 }
215
216 fcntl(fds[nfds], F_SETFL, flags);
217
218 #ifndef HAVE_POLL
219 if (fds[nfds] > max_fd)
220 max_fd = fds[nfds];
221 #endif /* !HAVE_POLL */
222
223 addrs[nfds] = addrlist;
224 nfds ++;
225 }
226
227 #ifdef O_NONBLOCK
228 DEBUG_puts("1httpAddrConnect2: Finishing async connect()");
229
230 for (remaining = msec; remaining > 0; remaining -= 250)
231 {
232 do
233 {
234 if (cancel && *cancel)
235 {
236 /*
237 * Close this socket and return...
238 */
239
240 DEBUG_puts("1httpAddrConnect2: Canceled connect()");
241
242 while (nfds > 0)
243 {
244 nfds --;
245 httpAddrClose(NULL, fds[nfds]);
246 }
247
248 *sock = -1;
249
250 return (NULL);
251 }
252
253 # ifdef HAVE_POLL
254 for (i = 0; i < nfds; i ++)
255 {
256 pfds[i].fd = fds[i];
257 pfds[i].events = POLLIN | POLLOUT;
258 }
259
260 result = poll(pfds, (nfds_t)nfds, remaining > 250 ? 250 : remaining);
261
262 DEBUG_printf(("1httpAddrConnect2: poll() returned %d (%d)", result, errno));
263
264 # else
265 FD_ZERO(&input_set);
266 for (i = 0; i < nfds; i ++)
267 FD_SET(fds[i], &input_set);
268 output_set = input_set;
269
270 timeout.tv_sec = 0;
271 timeout.tv_usec = (remaining > 250 ? 250 : remaining) * 1000;
272
273 result = select(max_fd + 1, &input_set, &output_set, NULL, &timeout);
274
275 DEBUG_printf(("1httpAddrConnect2: select() returned %d (%d)", result, errno));
276 # endif /* HAVE_POLL */
277 }
278 # ifdef WIN32
279 while (result < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK));
280 # else
281 while (result < 0 && (errno == EINTR || errno == EAGAIN));
282 # endif /* WIN32 */
283
284 if (result > 0)
285 {
286 for (i = 0; i < nfds; i ++)
287 {
288 # ifdef HAVE_POLL
289 DEBUG_printf(("pfds[%d].revents=%x\n", i, pfds[i].revents));
290 if (pfds[i].revents)
291 # else
292 if (FD_ISSET(fds[i], &input))
293 # endif /* HAVE_POLL */
294 {
295 *sock = fds[i];
296 len = sizeof(peer);
297 if (!getpeername(fds[i], (struct sockaddr *)&peer, &len))
298 {
299 DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&peer, temp, sizeof(temp)), httpAddrPort(&peer)));
300
301 addrlist = addrs[i];
302 }
303 }
304 else
305 httpAddrClose(NULL, fds[i]);
306 }
307
308 return (addrlist);
309 }
310 }
311 #endif /* O_NONBLOCK */
312
313 while (nfds > 0)
314 {
315 nfds --;
316 httpAddrClose(NULL, fds[nfds]);
317 }
318
319 #ifdef WIN32
320 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, "Connection failed", 0);
321 #else
322 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, strerror(errno), 0);
323 #endif /* WIN32 */
324
325 return (NULL);
326 }
327
328
329 /*
330 * 'httpAddrCopyList()' - Copy an address list.
331 *
332 * @since CUPS 1.7/OS X 10.9@
333 */
334
335 http_addrlist_t * /* O - New address list or @code NULL@ on error */
336 httpAddrCopyList(
337 http_addrlist_t *src) /* I - Source address list */
338 {
339 http_addrlist_t *dst = NULL, /* First list entry */
340 *prev = NULL, /* Previous list entry */
341 *current = NULL;/* Current list entry */
342
343
344 while (src)
345 {
346 if ((current = malloc(sizeof(http_addrlist_t))) == NULL)
347 {
348 current = dst;
349
350 while (current)
351 {
352 prev = current;
353 current = current->next;
354
355 free(prev);
356 }
357
358 return (NULL);
359 }
360
361 memcpy(current, src, sizeof(http_addrlist_t));
362
363 current->next = NULL;
364
365 if (prev)
366 prev->next = current;
367 else
368 dst = current;
369
370 prev = current;
371 src = src->next;
372 }
373
374 return (dst);
375 }
376
377
378 /*
379 * 'httpAddrFreeList()' - Free an address list.
380 *
381 * @since CUPS 1.2/OS X 10.5@
382 */
383
384 void
385 httpAddrFreeList(
386 http_addrlist_t *addrlist) /* I - Address list to free */
387 {
388 http_addrlist_t *next; /* Next address in list */
389
390
391 /*
392 * Free each address in the list...
393 */
394
395 while (addrlist)
396 {
397 next = addrlist->next;
398
399 free(addrlist);
400
401 addrlist = next;
402 }
403 }
404
405
406 /*
407 * 'httpAddrGetList()' - Get a list of addresses for a hostname.
408 *
409 * @since CUPS 1.2/OS X 10.5@
410 */
411
412 http_addrlist_t * /* O - List of addresses or NULL */
413 httpAddrGetList(const char *hostname, /* I - Hostname, IP address, or NULL for passive listen address */
414 int family, /* I - Address family or AF_UNSPEC */
415 const char *service) /* I - Service name or port number */
416 {
417 http_addrlist_t *first, /* First address in list */
418 *addr, /* Current address in list */
419 *temp; /* New address */
420 _cups_globals_t *cg = _cupsGlobals();
421 /* Global data */
422
423
424 #ifdef DEBUG
425 _cups_debug_printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, "
426 "service=\"%s\")\n",
427 hostname ? hostname : "(nil)",
428 family == AF_UNSPEC ? "UNSPEC" :
429 # ifdef AF_LOCAL
430 family == AF_LOCAL ? "LOCAL" :
431 # endif /* AF_LOCAL */
432 # ifdef AF_INET6
433 family == AF_INET6 ? "INET6" :
434 # endif /* AF_INET6 */
435 family == AF_INET ? "INET" : "???", service);
436 #endif /* DEBUG */
437
438 #ifdef HAVE_RES_INIT
439 /*
440 * STR #2920: Initialize resolver after failure in cups-polld
441 *
442 * If the previous lookup failed, re-initialize the resolver to prevent
443 * temporary network errors from persisting. This *should* be handled by
444 * the resolver libraries, but apparently the glibc folks do not agree.
445 *
446 * We set a flag at the end of this function if we encounter an error that
447 * requires reinitialization of the resolver functions. We then call
448 * res_init() if the flag is set on the next call here or in httpAddrLookup().
449 */
450
451 if (cg->need_res_init)
452 {
453 res_init();
454
455 cg->need_res_init = 0;
456 }
457 #endif /* HAVE_RES_INIT */
458
459 /*
460 * Lookup the address the best way we can...
461 */
462
463 first = addr = NULL;
464
465 #ifdef AF_LOCAL
466 if (hostname && hostname[0] == '/')
467 {
468 /*
469 * Domain socket address...
470 */
471
472 if ((first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t))) != NULL)
473 {
474 addr = first;
475 first->addr.un.sun_family = AF_LOCAL;
476 strlcpy(first->addr.un.sun_path, hostname, sizeof(first->addr.un.sun_path));
477 }
478 }
479 else
480 #endif /* AF_LOCAL */
481 if (!hostname || _cups_strcasecmp(hostname, "localhost"))
482 {
483 #ifdef HAVE_GETADDRINFO
484 struct addrinfo hints, /* Address lookup hints */
485 *results, /* Address lookup results */
486 *current; /* Current result */
487 char ipv6[64], /* IPv6 address */
488 *ipv6zone; /* Pointer to zone separator */
489 int ipv6len; /* Length of IPv6 address */
490 int error; /* getaddrinfo() error */
491
492
493 /*
494 * Lookup the address as needed...
495 */
496
497 memset(&hints, 0, sizeof(hints));
498 hints.ai_family = family;
499 hints.ai_flags = hostname ? 0 : AI_PASSIVE;
500 hints.ai_socktype = SOCK_STREAM;
501
502 if (hostname && *hostname == '[')
503 {
504 /*
505 * Remove brackets from numeric IPv6 address...
506 */
507
508 if (!strncmp(hostname, "[v1.", 4))
509 {
510 /*
511 * Copy the newer address format which supports link-local addresses...
512 */
513
514 strlcpy(ipv6, hostname + 4, sizeof(ipv6));
515 if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
516 {
517 ipv6[ipv6len] = '\0';
518 hostname = ipv6;
519
520 /*
521 * Convert "+zone" in address to "%zone"...
522 */
523
524 if ((ipv6zone = strrchr(ipv6, '+')) != NULL)
525 *ipv6zone = '%';
526 }
527 }
528 else
529 {
530 /*
531 * Copy the regular non-link-local IPv6 address...
532 */
533
534 strlcpy(ipv6, hostname + 1, sizeof(ipv6));
535 if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
536 {
537 ipv6[ipv6len] = '\0';
538 hostname = ipv6;
539 }
540 }
541 }
542
543 if ((error = getaddrinfo(hostname, service, &hints, &results)) == 0)
544 {
545 /*
546 * Copy the results to our own address list structure...
547 */
548
549 for (current = results; current; current = current->ai_next)
550 if (current->ai_family == AF_INET || current->ai_family == AF_INET6)
551 {
552 /*
553 * Copy the address over...
554 */
555
556 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
557 if (!temp)
558 {
559 httpAddrFreeList(first);
560 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
561 return (NULL);
562 }
563
564 if (current->ai_family == AF_INET6)
565 memcpy(&(temp->addr.ipv6), current->ai_addr,
566 sizeof(temp->addr.ipv6));
567 else
568 memcpy(&(temp->addr.ipv4), current->ai_addr,
569 sizeof(temp->addr.ipv4));
570
571 /*
572 * Append the address to the list...
573 */
574
575 if (!first)
576 first = temp;
577
578 if (addr)
579 addr->next = temp;
580
581 addr = temp;
582 }
583
584 /*
585 * Free the results from getaddrinfo()...
586 */
587
588 freeaddrinfo(results);
589 }
590 else
591 {
592 if (error == EAI_FAIL)
593 cg->need_res_init = 1;
594
595 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerror(error), 0);
596 }
597
598 #else
599 if (hostname)
600 {
601 int i; /* Looping vars */
602 unsigned ip[4]; /* IPv4 address components */
603 const char *ptr; /* Pointer into hostname */
604 struct hostent *host; /* Result of lookup */
605 struct servent *port; /* Port number for service */
606 int portnum; /* Port number */
607
608
609 /*
610 * Lookup the service...
611 */
612
613 if (!service)
614 portnum = 0;
615 else if (isdigit(*service & 255))
616 portnum = atoi(service);
617 else if ((port = getservbyname(service, NULL)) != NULL)
618 portnum = ntohs(port->s_port);
619 else if (!strcmp(service, "http"))
620 portnum = 80;
621 else if (!strcmp(service, "https"))
622 portnum = 443;
623 else if (!strcmp(service, "ipp") || !strcmp(service, "ipps"))
624 portnum = 631;
625 else if (!strcmp(service, "lpd"))
626 portnum = 515;
627 else if (!strcmp(service, "socket"))
628 portnum = 9100;
629 else
630 return (NULL);
631
632 /*
633 * This code is needed because some operating systems have a
634 * buggy implementation of gethostbyname() that does not support
635 * IPv4 addresses. If the hostname string is an IPv4 address, then
636 * sscanf() is used to extract the IPv4 components. We then pack
637 * the components into an IPv4 address manually, since the
638 * inet_aton() function is deprecated. We use the htonl() macro
639 * to get the right byte order for the address.
640 */
641
642 for (ptr = hostname; isdigit(*ptr & 255) || *ptr == '.'; ptr ++);
643
644 if (!*ptr)
645 {
646 /*
647 * We have an IPv4 address; break it up and create an IPv4 address...
648 */
649
650 if (sscanf(hostname, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) == 4 &&
651 ip[0] <= 255 && ip[1] <= 255 && ip[2] <= 255 && ip[3] <= 255)
652 {
653 first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
654 if (!first)
655 return (NULL);
656
657 first->addr.ipv4.sin_family = AF_INET;
658 first->addr.ipv4.sin_addr.s_addr = htonl((((((((unsigned)ip[0] << 8) |
659 (unsigned)ip[1]) << 8) |
660 (unsigned)ip[2]) << 8) |
661 (unsigned)ip[3]));
662 first->addr.ipv4.sin_port = htons(portnum);
663 }
664 }
665 else if ((host = gethostbyname(hostname)) != NULL &&
666 # ifdef AF_INET6
667 (host->h_addrtype == AF_INET || host->h_addrtype == AF_INET6))
668 # else
669 host->h_addrtype == AF_INET)
670 # endif /* AF_INET6 */
671 {
672 for (i = 0; host->h_addr_list[i]; i ++)
673 {
674 /*
675 * Copy the address over...
676 */
677
678 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
679 if (!temp)
680 {
681 httpAddrFreeList(first);
682 return (NULL);
683 }
684
685 # ifdef AF_INET6
686 if (host->h_addrtype == AF_INET6)
687 {
688 temp->addr.ipv6.sin6_family = AF_INET6;
689 memcpy(&(temp->addr.ipv6.sin6_addr), host->h_addr_list[i],
690 sizeof(temp->addr.ipv6));
691 temp->addr.ipv6.sin6_port = htons(portnum);
692 }
693 else
694 # endif /* AF_INET6 */
695 {
696 temp->addr.ipv4.sin_family = AF_INET;
697 memcpy(&(temp->addr.ipv4.sin_addr), host->h_addr_list[i],
698 sizeof(temp->addr.ipv4));
699 temp->addr.ipv4.sin_port = htons(portnum);
700 }
701
702 /*
703 * Append the address to the list...
704 */
705
706 if (!first)
707 first = temp;
708
709 if (addr)
710 addr->next = temp;
711
712 addr = temp;
713 }
714 }
715 else
716 {
717 if (h_errno == NO_RECOVERY)
718 cg->need_res_init = 1;
719
720 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, hstrerror(h_errno), 0);
721 }
722 }
723 #endif /* HAVE_GETADDRINFO */
724 }
725
726 /*
727 * Detect some common errors and handle them sanely...
728 */
729
730 if (!addr && (!hostname || !_cups_strcasecmp(hostname, "localhost")))
731 {
732 struct servent *port; /* Port number for service */
733 int portnum; /* Port number */
734
735
736 /*
737 * Lookup the service...
738 */
739
740 if (!service)
741 portnum = 0;
742 else if (isdigit(*service & 255))
743 portnum = atoi(service);
744 else if ((port = getservbyname(service, NULL)) != NULL)
745 portnum = ntohs(port->s_port);
746 else if (!strcmp(service, "http"))
747 portnum = 80;
748 else if (!strcmp(service, "https"))
749 portnum = 443;
750 else if (!strcmp(service, "ipp") || !strcmp(service, "ipps"))
751 portnum = 631;
752 else if (!strcmp(service, "lpd"))
753 portnum = 515;
754 else if (!strcmp(service, "socket"))
755 portnum = 9100;
756 else
757 {
758 httpAddrFreeList(first);
759
760 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown service name."), 1);
761 return (NULL);
762 }
763
764 if (hostname && !_cups_strcasecmp(hostname, "localhost"))
765 {
766 /*
767 * Unfortunately, some users ignore all of the warnings in the
768 * /etc/hosts file and delete "localhost" from it. If we get here
769 * then we were unable to resolve the name, so use the IPv6 and/or
770 * IPv4 loopback interface addresses...
771 */
772
773 #ifdef AF_INET6
774 if (family != AF_INET)
775 {
776 /*
777 * Add [::1] to the address list...
778 */
779
780 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
781 if (!temp)
782 {
783 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
784 httpAddrFreeList(first);
785 return (NULL);
786 }
787
788 temp->addr.ipv6.sin6_family = AF_INET6;
789 temp->addr.ipv6.sin6_port = htons(portnum);
790 # ifdef WIN32
791 temp->addr.ipv6.sin6_addr.u.Byte[15] = 1;
792 # else
793 temp->addr.ipv6.sin6_addr.s6_addr32[3] = htonl(1);
794 # endif /* WIN32 */
795
796 if (!first)
797 first = temp;
798
799 addr = temp;
800 }
801
802 if (family != AF_INET6)
803 #endif /* AF_INET6 */
804 {
805 /*
806 * Add 127.0.0.1 to the address list...
807 */
808
809 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
810 if (!temp)
811 {
812 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
813 httpAddrFreeList(first);
814 return (NULL);
815 }
816
817 temp->addr.ipv4.sin_family = AF_INET;
818 temp->addr.ipv4.sin_port = htons(portnum);
819 temp->addr.ipv4.sin_addr.s_addr = htonl(0x7f000001);
820
821 if (!first)
822 first = temp;
823
824 if (addr)
825 addr->next = temp;
826 }
827 }
828 else if (!hostname)
829 {
830 /*
831 * Provide one or more passive listening addresses...
832 */
833
834 #ifdef AF_INET6
835 if (family != AF_INET)
836 {
837 /*
838 * Add [::] to the address list...
839 */
840
841 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
842 if (!temp)
843 {
844 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
845 httpAddrFreeList(first);
846 return (NULL);
847 }
848
849 temp->addr.ipv6.sin6_family = AF_INET6;
850 temp->addr.ipv6.sin6_port = htons(portnum);
851
852 if (!first)
853 first = temp;
854
855 addr = temp;
856 }
857
858 if (family != AF_INET6)
859 #endif /* AF_INET6 */
860 {
861 /*
862 * Add 0.0.0.0 to the address list...
863 */
864
865 temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
866 if (!temp)
867 {
868 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
869 httpAddrFreeList(first);
870 return (NULL);
871 }
872
873 temp->addr.ipv4.sin_family = AF_INET;
874 temp->addr.ipv4.sin_port = htons(portnum);
875
876 if (!first)
877 first = temp;
878
879 if (addr)
880 addr->next = temp;
881 }
882 }
883 }
884
885 /*
886 * Return the address list...
887 */
888
889 return (first);
890 }
891
892
893 /*
894 * End of "$Id$".
895 */