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