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