]>
git.ipfire.org Git - thirdparty/cups.git/blob - cups/http-addrlist.c
2 * "$Id: http-addrlist.c 6187 2007-01-10 16:20:42Z mike $"
4 * HTTP address list routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * httpAddrConnect() - Connect to any of the addresses in the list.
27 * httpAddrFreeList() - Free an address list.
28 * httpAddrGetList() - Get a list of addresses for a hostname.
32 * Include necessary headers...
35 #include "http-private.h"
42 * 'httpAddrConnect()' - Connect to any of the addresses in the list.
47 http_addrlist_t
* /* O - Connected address or NULL on failure */
49 http_addrlist_t
*addrlist
, /* I - List of potential addresses */
50 int *sock
) /* O - Socket */
52 int val
; /* Socket option value */
56 * Loop through each address until we connect or run out of addresses...
62 * Create the socket...
65 if ((*sock
= (int)socket(addrlist
->addr
.addr
.sa_family
, SOCK_STREAM
, 0)) < 0)
68 * Don't abort yet, as this could just be an issue with the local
69 * system not being configured with IPv4/IPv6/domain socket enabled...
72 addrlist
= addrlist
->next
;
82 setsockopt(*sock
, SOL_SOCKET
, SO_REUSEADDR
, (const char *)&val
,
85 setsockopt(*sock
, SOL_SOCKET
, SO_REUSEADDR
, &val
, sizeof(val
));
90 setsockopt(*sock
, SOL_SOCKET
, SO_REUSEPORT
, &val
, sizeof(val
));
91 #endif /* SO_REUSEPORT */
95 setsockopt(*sock
, SOL_SOCKET
, SO_NOSIGPIPE
, &val
, sizeof(val
));
96 #endif /* SO_NOSIGPIPE */
99 * Using TCP_NODELAY improves responsiveness, especially on systems
100 * with a slow loopback interface...
105 setsockopt(*sock
, IPPROTO_TCP
, TCP_NODELAY
, (const char *)&val
,
108 setsockopt(*sock
, IPPROTO_TCP
, TCP_NODELAY
, &val
, sizeof(val
));
113 * Close this socket when starting another process...
116 fcntl(*sock
, F_SETFD
, FD_CLOEXEC
);
117 #endif /* FD_CLOEXEC */
123 if (!connect(*sock
, &(addrlist
->addr
.addr
),
124 httpAddrLength(&(addrlist
->addr
))))
128 * Close this socket and move to the next address...
137 addrlist
= addrlist
->next
;
145 * 'httpAddrFreeList()' - Free an address list.
152 http_addrlist_t
*addrlist
) /* I - Address list to free */
154 http_addrlist_t
*next
; /* Next address in list */
158 * Free each address in the list...
163 next
= addrlist
->next
;
173 * 'httpAddrGetList()' - Get a list of addresses for a hostname.
178 http_addrlist_t
* /* O - List of addresses or NULL */
179 httpAddrGetList(const char *hostname
, /* I - Hostname, IP address, or NULL for passive listen address */
180 int family
, /* I - Address family or AF_UNSPEC */
181 const char *service
) /* I - Service name or port number */
183 http_addrlist_t
*first
, /* First address in list */
184 *addr
, /* Current address in list */
185 *temp
; /* New address */
189 printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, service=\"%s\")\n",
190 hostname
? hostname
: "(nil)",
191 family
== AF_UNSPEC
? "UNSPEC" :
193 family
== AF_LOCAL
? "LOCAL" :
194 # endif /* AF_LOCAL */
196 family
== AF_INET6
? "INET6" :
197 # endif /* AF_INET6 */
198 family
== AF_INET
? "INET" : "???", service
);
202 * Lookup the address the best way we can...
208 if (hostname
&& hostname
[0] == '/')
211 * Domain socket address...
214 first
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
215 first
->addr
.un
.sun_family
= AF_LOCAL
;
216 strlcpy(first
->addr
.un
.sun_path
, hostname
, sizeof(first
->addr
.un
.sun_path
));
219 #endif /* AF_LOCAL */
221 #ifdef HAVE_GETADDRINFO
222 struct addrinfo hints
, /* Address lookup hints */
223 *results
, /* Address lookup results */
224 *current
; /* Current result */
225 char ipv6
[1024], /* IPv6 address */
226 *ipv6zone
; /* Pointer to zone separator */
227 int ipv6len
; /* Length of IPv6 address */
230 * Lookup the address as needed...
233 memset(&hints
, 0, sizeof(hints
));
234 hints
.ai_family
= family
;
235 hints
.ai_flags
= hostname
? 0 : AI_PASSIVE
;
236 hints
.ai_socktype
= SOCK_STREAM
;
238 if (hostname
&& *hostname
== '[')
241 * Remove brackets from numeric IPv6 address...
244 if (!strncmp(hostname
, "[v1.", 4))
247 * Copy the newer address format which supports link-local addresses...
250 strlcpy(ipv6
, hostname
+ 4, sizeof(ipv6
));
251 if ((ipv6len
= (int)strlen(ipv6
) - 1) >= 0 && ipv6
[ipv6len
] == ']')
253 ipv6
[ipv6len
] = '\0';
257 * Convert "+zone" in address to "%zone"...
260 if ((ipv6zone
= strrchr(ipv6
, '+')) != NULL
)
267 * Copy the regular non-link-local IPv6 address...
270 strlcpy(ipv6
, hostname
+ 1, sizeof(ipv6
));
271 if ((ipv6len
= (int)strlen(ipv6
) - 1) >= 0 && ipv6
[ipv6len
] == ']')
273 ipv6
[ipv6len
] = '\0';
279 if (!getaddrinfo(hostname
, service
, &hints
, &results
))
282 * Copy the results to our own address list structure...
285 for (current
= results
; current
; current
= current
->ai_next
)
286 if (current
->ai_family
== AF_INET
|| current
->ai_family
== AF_INET6
)
289 * Copy the address over...
292 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
295 httpAddrFreeList(first
);
299 if (current
->ai_family
== AF_INET6
)
300 memcpy(&(temp
->addr
.ipv6
), current
->ai_addr
,
301 sizeof(temp
->addr
.ipv6
));
303 memcpy(&(temp
->addr
.ipv4
), current
->ai_addr
,
304 sizeof(temp
->addr
.ipv4
));
307 * Append the address to the list...
320 * Free the results from getaddrinfo()...
323 freeaddrinfo(results
);
328 int i
; /* Looping vars */
329 unsigned ip
[4]; /* IPv4 address components */
330 const char *ptr
; /* Pointer into hostname */
331 struct hostent
*host
; /* Result of lookup */
332 struct servent
*port
; /* Port number for service */
333 int portnum
; /* Port number */
337 * Lookup the service...
342 else if (isdigit(*service
& 255))
343 portnum
= atoi(service
);
344 else if ((port
= getservbyname(service
, NULL
)) != NULL
)
345 portnum
= ntohs(port
->s_port
);
346 else if (!strcmp(service
, "http"))
348 else if (!strcmp(service
, "https"))
350 else if (!strcmp(service
, "ipp"))
352 else if (!strcmp(service
, "lpd"))
354 else if (!strcmp(service
, "socket"))
360 * This code is needed because some operating systems have a
361 * buggy implementation of gethostbyname() that does not support
362 * IPv4 addresses. If the hostname string is an IPv4 address, then
363 * sscanf() is used to extract the IPv4 components. We then pack
364 * the components into an IPv4 address manually, since the
365 * inet_aton() function is deprecated. We use the htonl() macro
366 * to get the right byte order for the address.
369 for (ptr
= hostname
; isdigit(*ptr
& 255) || *ptr
== '.'; ptr
++);
374 * We have an IPv4 address; break it up and create an IPv4 address...
377 if (sscanf(hostname
, "%u.%u.%u.%u", ip
, ip
+ 1, ip
+ 2, ip
+ 3) == 4 &&
378 ip
[0] <= 255 && ip
[1] <= 255 && ip
[2] <= 255 && ip
[3] <= 255)
380 first
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
384 first
->addr
.ipv4
.sin_family
= AF_INET
;
385 first
->addr
.ipv4
.sin_addr
.s_addr
= htonl(((((((ip
[0] << 8) |
387 ip
[2]) << 8) | ip
[3]));
388 first
->addr
.ipv4
.sin_port
= htons(portnum
);
391 else if ((host
= gethostbyname(hostname
)) != NULL
&&
393 (host
->h_addrtype
== AF_INET
|| host
->h_addrtype
== AF_INET6
))
395 host
->h_addrtype
== AF_INET
)
396 # endif /* AF_INET6 */
398 for (i
= 0; host
->h_addr_list
[i
]; i
++)
401 * Copy the address over...
404 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
407 httpAddrFreeList(first
);
412 if (host
->h_addrtype
== AF_INET6
)
414 temp
->addr
.ipv6
.sin6_family
= AF_INET6
;
415 memcpy(&(temp
->addr
.ipv6
.sin6_addr
), host
->h_addr_list
[i
],
416 sizeof(temp
->addr
.ipv6
));
417 temp
->addr
.ipv6
.sin6_port
= htons(portnum
);
420 # endif /* AF_INET6 */
422 temp
->addr
.ipv4
.sin_family
= AF_INET
;
423 memcpy(&(temp
->addr
.ipv4
.sin_addr
), host
->h_addr_list
[i
],
424 sizeof(temp
->addr
.ipv4
));
425 temp
->addr
.ipv4
.sin_port
= htons(portnum
);
429 * Append the address to the list...
442 #endif /* HAVE_GETADDRINFO */
446 * Detect some common errors and handle them sanely...
449 if (!addr
&& (!hostname
|| !strcmp(hostname
, "localhost")))
451 struct servent
*port
; /* Port number for service */
452 int portnum
; /* Port number */
456 * Lookup the service...
461 else if (isdigit(*service
& 255))
462 portnum
= atoi(service
);
463 else if ((port
= getservbyname(service
, NULL
)) != NULL
)
464 portnum
= ntohs(port
->s_port
);
465 else if (!strcmp(service
, "http"))
467 else if (!strcmp(service
, "https"))
469 else if (!strcmp(service
, "ipp"))
471 else if (!strcmp(service
, "lpd"))
473 else if (!strcmp(service
, "socket"))
478 if (hostname
&& !strcmp(hostname
, "localhost"))
481 * Unfortunately, some users ignore all of the warnings in the
482 * /etc/hosts file and delete "localhost" from it. If we get here
483 * then we were unable to resolve the name, so use the IPv6 and/or
484 * IPv4 loopback interface addresses...
488 if (family
!= AF_INET
)
491 * Add [::1] to the address list...
494 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
497 httpAddrFreeList(first
);
501 temp
->addr
.ipv6
.sin6_family
= AF_INET6
;
502 temp
->addr
.ipv6
.sin6_port
= htons(portnum
);
504 temp
->addr
.ipv6
.sin6_addr
.u
.Byte
[15] = 1;
506 temp
->addr
.ipv6
.sin6_addr
.s6_addr32
[3] = htonl(1);
515 if (family
!= AF_INET6
)
516 #endif /* AF_INET6 */
519 * Add 127.0.0.1 to the address list...
522 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
525 httpAddrFreeList(first
);
529 temp
->addr
.ipv4
.sin_family
= AF_INET
;
530 temp
->addr
.ipv4
.sin_port
= htons(portnum
);
531 temp
->addr
.ipv4
.sin_addr
.s_addr
= htonl(0x7f000001);
545 * Provide one or more passive listening addresses...
549 if (family
!= AF_INET
)
552 * Add [::] to the address list...
555 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
558 httpAddrFreeList(first
);
562 temp
->addr
.ipv6
.sin6_family
= AF_INET6
;
563 temp
->addr
.ipv6
.sin6_port
= htons(portnum
);
571 if (family
!= AF_INET6
)
572 #endif /* AF_INET6 */
575 * Add 0.0.0.0 to the address list...
578 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
581 httpAddrFreeList(first
);
585 temp
->addr
.ipv4
.sin_family
= AF_INET
;
586 temp
->addr
.ipv4
.sin_port
= htons(portnum
);
600 * Return the address list...
608 * End of "$Id: http-addrlist.c 6187 2007-01-10 16:20:42Z mike $".