]>
git.ipfire.org Git - thirdparty/cups.git/blob - cups/http-addrlist.c
ddf8079b4d9f58d1b921807e5b430a29f754bb92
2 * "$Id: http-addrlist.c 7910 2008-09-06 00:25:17Z mike $"
4 * HTTP address list routines for CUPS.
6 * Copyright 2007-2010 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
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/".
17 * httpAddrConnect() - Connect to any of the addresses in the list.
18 * httpAddrFreeList() - Free an address list.
19 * httpAddrGetList() - Get a list of addresses for a hostname.
23 * Include necessary headers...
26 #include "cups-private.h"
29 #endif /* HAVE_RESOLV_H */
33 * 'httpAddrConnect()' - Connect to any of the addresses in the list.
35 * @since CUPS 1.2/Mac OS X 10.5@
38 http_addrlist_t
* /* O - Connected address or NULL on failure */
40 http_addrlist_t
*addrlist
, /* I - List of potential addresses */
41 int *sock
) /* O - Socket */
43 int val
; /* Socket option value */
45 char temp
[256]; /* Temporary address string */
49 DEBUG_printf(("httpAddrConnect(addrlist=%p, sock=%p)", addrlist
, sock
));
58 * Loop through each address until we connect or run out of addresses...
64 * Create the socket...
67 DEBUG_printf(("2httpAddrConnect: Trying %s:%d...",
68 httpAddrString(&(addrlist
->addr
), temp
, sizeof(temp
)),
69 _httpAddrPort(&(addrlist
->addr
))));
71 if ((*sock
= (int)socket(addrlist
->addr
.addr
.sa_family
, SOCK_STREAM
,
75 * Don't abort yet, as this could just be an issue with the local
76 * system not being configured with IPv4/IPv6/domain socket enabled...
79 addrlist
= addrlist
->next
;
89 setsockopt(*sock
, SOL_SOCKET
, SO_REUSEADDR
, (const char *)&val
,
92 setsockopt(*sock
, SOL_SOCKET
, SO_REUSEADDR
, &val
, sizeof(val
));
97 setsockopt(*sock
, SOL_SOCKET
, SO_REUSEPORT
, &val
, sizeof(val
));
98 #endif /* SO_REUSEPORT */
102 setsockopt(*sock
, SOL_SOCKET
, SO_NOSIGPIPE
, &val
, sizeof(val
));
103 #endif /* SO_NOSIGPIPE */
106 * Using TCP_NODELAY improves responsiveness, especially on systems
107 * with a slow loopback interface...
112 setsockopt(*sock
, IPPROTO_TCP
, TCP_NODELAY
, (const char *)&val
,
115 setsockopt(*sock
, IPPROTO_TCP
, TCP_NODELAY
, &val
, sizeof(val
));
120 * Close this socket when starting another process...
123 fcntl(*sock
, F_SETFD
, FD_CLOEXEC
);
124 #endif /* FD_CLOEXEC */
130 if (!connect(*sock
, &(addrlist
->addr
.addr
),
131 httpAddrLength(&(addrlist
->addr
))))
133 DEBUG_printf(("1httpAddrConnect: Connected to %s:%d...",
134 httpAddrString(&(addrlist
->addr
), temp
, sizeof(temp
)),
135 _httpAddrPort(&(addrlist
->addr
))));
139 DEBUG_printf(("1httpAddrConnect: Unable to connect to %s:%d: %s",
140 httpAddrString(&(addrlist
->addr
), temp
, sizeof(temp
)),
141 _httpAddrPort(&(addrlist
->addr
)), strerror(errno
)));
144 * Close this socket and move to the next address...
154 addrlist
= addrlist
->next
;
162 * 'httpAddrFreeList()' - Free an address list.
164 * @since CUPS 1.2/Mac OS X 10.5@
169 http_addrlist_t
*addrlist
) /* I - Address list to free */
171 http_addrlist_t
*next
; /* Next address in list */
175 * Free each address in the list...
180 next
= addrlist
->next
;
190 * 'httpAddrGetList()' - Get a list of addresses for a hostname.
192 * @since CUPS 1.2/Mac OS X 10.5@
195 http_addrlist_t
* /* O - List of addresses or NULL */
196 httpAddrGetList(const char *hostname
, /* I - Hostname, IP address, or NULL for passive listen address */
197 int family
, /* I - Address family or AF_UNSPEC */
198 const char *service
) /* I - Service name or port number */
200 http_addrlist_t
*first
, /* First address in list */
201 *addr
, /* Current address in list */
202 *temp
; /* New address */
203 _cups_globals_t
*cg
= _cupsGlobals();
208 _cups_debug_printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, "
210 hostname
? hostname
: "(nil)",
211 family
== AF_UNSPEC
? "UNSPEC" :
213 family
== AF_LOCAL
? "LOCAL" :
214 # endif /* AF_LOCAL */
216 family
== AF_INET6
? "INET6" :
217 # endif /* AF_INET6 */
218 family
== AF_INET
? "INET" : "???", service
);
223 * STR #2920: Initialize resolver after failure in cups-polld
225 * If the previous lookup failed, re-initialize the resolver to prevent
226 * temporary network errors from persisting. This *should* be handled by
227 * the resolver libraries, but apparently the glibc folks do not agree.
229 * We set a flag at the end of this function if we encounter an error that
230 * requires reinitialization of the resolver functions. We then call
231 * res_init() if the flag is set on the next call here or in httpAddrLookup().
234 if (cg
->need_res_init
)
238 cg
->need_res_init
= 0;
240 #endif /* HAVE_RES_INIT */
244 * Lookup the address the best way we can...
250 if (hostname
&& hostname
[0] == '/')
253 * Domain socket address...
256 if ((first
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
))) != NULL
)
258 first
->addr
.un
.sun_family
= AF_LOCAL
;
259 strlcpy(first
->addr
.un
.sun_path
, hostname
, sizeof(first
->addr
.un
.sun_path
));
263 #endif /* AF_LOCAL */
264 if (!hostname
|| strcasecmp(hostname
, "localhost"))
266 #ifdef HAVE_GETADDRINFO
267 struct addrinfo hints
, /* Address lookup hints */
268 *results
, /* Address lookup results */
269 *current
; /* Current result */
270 char ipv6
[1024], /* IPv6 address */
271 *ipv6zone
; /* Pointer to zone separator */
272 int ipv6len
; /* Length of IPv6 address */
273 int error
; /* getaddrinfo() error */
277 * Lookup the address as needed...
280 memset(&hints
, 0, sizeof(hints
));
281 hints
.ai_family
= family
;
282 hints
.ai_flags
= hostname
? 0 : AI_PASSIVE
;
283 hints
.ai_socktype
= SOCK_STREAM
;
285 if (hostname
&& *hostname
== '[')
288 * Remove brackets from numeric IPv6 address...
291 if (!strncmp(hostname
, "[v1.", 4))
294 * Copy the newer address format which supports link-local addresses...
297 strlcpy(ipv6
, hostname
+ 4, sizeof(ipv6
));
298 if ((ipv6len
= (int)strlen(ipv6
) - 1) >= 0 && ipv6
[ipv6len
] == ']')
300 ipv6
[ipv6len
] = '\0';
304 * Convert "+zone" in address to "%zone"...
307 if ((ipv6zone
= strrchr(ipv6
, '+')) != NULL
)
314 * Copy the regular non-link-local IPv6 address...
317 strlcpy(ipv6
, hostname
+ 1, sizeof(ipv6
));
318 if ((ipv6len
= (int)strlen(ipv6
) - 1) >= 0 && ipv6
[ipv6len
] == ']')
320 ipv6
[ipv6len
] = '\0';
326 if ((error
= getaddrinfo(hostname
, service
, &hints
, &results
)) == 0)
329 * Copy the results to our own address list structure...
332 for (current
= results
; current
; current
= current
->ai_next
)
333 if (current
->ai_family
== AF_INET
|| current
->ai_family
== AF_INET6
)
336 * Copy the address over...
339 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
342 httpAddrFreeList(first
);
346 if (current
->ai_family
== AF_INET6
)
347 memcpy(&(temp
->addr
.ipv6
), current
->ai_addr
,
348 sizeof(temp
->addr
.ipv6
));
350 memcpy(&(temp
->addr
.ipv4
), current
->ai_addr
,
351 sizeof(temp
->addr
.ipv4
));
354 * Append the address to the list...
367 * Free the results from getaddrinfo()...
370 freeaddrinfo(results
);
372 else if (error
== EAI_FAIL
)
373 cg
->need_res_init
= 1;
378 int i
; /* Looping vars */
379 unsigned ip
[4]; /* IPv4 address components */
380 const char *ptr
; /* Pointer into hostname */
381 struct hostent
*host
; /* Result of lookup */
382 struct servent
*port
; /* Port number for service */
383 int portnum
; /* Port number */
387 * Lookup the service...
392 else if (isdigit(*service
& 255))
393 portnum
= atoi(service
);
394 else if ((port
= getservbyname(service
, NULL
)) != NULL
)
395 portnum
= ntohs(port
->s_port
);
396 else if (!strcmp(service
, "http"))
398 else if (!strcmp(service
, "https"))
400 else if (!strcmp(service
, "ipp"))
402 else if (!strcmp(service
, "lpd"))
404 else if (!strcmp(service
, "socket"))
410 * This code is needed because some operating systems have a
411 * buggy implementation of gethostbyname() that does not support
412 * IPv4 addresses. If the hostname string is an IPv4 address, then
413 * sscanf() is used to extract the IPv4 components. We then pack
414 * the components into an IPv4 address manually, since the
415 * inet_aton() function is deprecated. We use the htonl() macro
416 * to get the right byte order for the address.
419 for (ptr
= hostname
; isdigit(*ptr
& 255) || *ptr
== '.'; ptr
++);
424 * We have an IPv4 address; break it up and create an IPv4 address...
427 if (sscanf(hostname
, "%u.%u.%u.%u", ip
, ip
+ 1, ip
+ 2, ip
+ 3) == 4 &&
428 ip
[0] <= 255 && ip
[1] <= 255 && ip
[2] <= 255 && ip
[3] <= 255)
430 first
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
434 first
->addr
.ipv4
.sin_family
= AF_INET
;
435 first
->addr
.ipv4
.sin_addr
.s_addr
= htonl(((((((ip
[0] << 8) |
437 ip
[2]) << 8) | ip
[3]));
438 first
->addr
.ipv4
.sin_port
= htons(portnum
);
441 else if ((host
= gethostbyname(hostname
)) != NULL
&&
443 (host
->h_addrtype
== AF_INET
|| host
->h_addrtype
== AF_INET6
))
445 host
->h_addrtype
== AF_INET
)
446 # endif /* AF_INET6 */
448 for (i
= 0; host
->h_addr_list
[i
]; i
++)
451 * Copy the address over...
454 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
457 httpAddrFreeList(first
);
462 if (host
->h_addrtype
== AF_INET6
)
464 temp
->addr
.ipv6
.sin6_family
= AF_INET6
;
465 memcpy(&(temp
->addr
.ipv6
.sin6_addr
), host
->h_addr_list
[i
],
466 sizeof(temp
->addr
.ipv6
));
467 temp
->addr
.ipv6
.sin6_port
= htons(portnum
);
470 # endif /* AF_INET6 */
472 temp
->addr
.ipv4
.sin_family
= AF_INET
;
473 memcpy(&(temp
->addr
.ipv4
.sin_addr
), host
->h_addr_list
[i
],
474 sizeof(temp
->addr
.ipv4
));
475 temp
->addr
.ipv4
.sin_port
= htons(portnum
);
479 * Append the address to the list...
491 else if (h_errno
== NO_RECOVERY
)
492 cg
->need_res_init
= 1;
494 #endif /* HAVE_GETADDRINFO */
498 * Detect some common errors and handle them sanely...
501 if (!addr
&& (!hostname
|| !strcasecmp(hostname
, "localhost")))
503 struct servent
*port
; /* Port number for service */
504 int portnum
; /* Port number */
508 * Lookup the service...
513 else if (isdigit(*service
& 255))
514 portnum
= atoi(service
);
515 else if ((port
= getservbyname(service
, NULL
)) != NULL
)
516 portnum
= ntohs(port
->s_port
);
517 else if (!strcmp(service
, "http"))
519 else if (!strcmp(service
, "https"))
521 else if (!strcmp(service
, "ipp"))
523 else if (!strcmp(service
, "lpd"))
525 else if (!strcmp(service
, "socket"))
530 if (hostname
&& !strcasecmp(hostname
, "localhost"))
533 * Unfortunately, some users ignore all of the warnings in the
534 * /etc/hosts file and delete "localhost" from it. If we get here
535 * then we were unable to resolve the name, so use the IPv6 and/or
536 * IPv4 loopback interface addresses...
540 if (family
!= AF_INET
)
543 * Add [::1] to the address list...
546 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
549 httpAddrFreeList(first
);
553 temp
->addr
.ipv6
.sin6_family
= AF_INET6
;
554 temp
->addr
.ipv6
.sin6_port
= htons(portnum
);
556 temp
->addr
.ipv6
.sin6_addr
.u
.Byte
[15] = 1;
558 temp
->addr
.ipv6
.sin6_addr
.s6_addr32
[3] = htonl(1);
567 if (family
!= AF_INET6
)
568 #endif /* AF_INET6 */
571 * Add 127.0.0.1 to the address list...
574 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
577 httpAddrFreeList(first
);
581 temp
->addr
.ipv4
.sin_family
= AF_INET
;
582 temp
->addr
.ipv4
.sin_port
= htons(portnum
);
583 temp
->addr
.ipv4
.sin_addr
.s_addr
= htonl(0x7f000001);
595 * Provide one or more passive listening addresses...
599 if (family
!= AF_INET
)
602 * Add [::] to the address list...
605 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
608 httpAddrFreeList(first
);
612 temp
->addr
.ipv6
.sin6_family
= AF_INET6
;
613 temp
->addr
.ipv6
.sin6_port
= htons(portnum
);
621 if (family
!= AF_INET6
)
622 #endif /* AF_INET6 */
625 * Add 0.0.0.0 to the address list...
628 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
631 httpAddrFreeList(first
);
635 temp
->addr
.ipv4
.sin_family
= AF_INET
;
636 temp
->addr
.ipv4
.sin_port
= htons(portnum
);
648 * Return the address list...
656 * End of "$Id: http-addrlist.c 7910 2008-09-06 00:25:17Z mike $".