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