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