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