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