]>
git.ipfire.org Git - thirdparty/cups.git/blob - cups/http-addrlist.c
2 * "$Id: http-addrlist.c 4976 2006-01-25 15:07:40Z mike $"
4 * HTTP address list routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2006 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
= 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...
133 addrlist
= addrlist
->next
;
141 * 'httpAddrFreeList()' - Free an address list.
148 http_addrlist_t
*addrlist
) /* I - Address list to free */
150 http_addrlist_t
*next
; /* Next address in list */
154 * Free each address in the list...
159 next
= addrlist
->next
;
169 * 'httpAddrGetList()' - Get a list of addresses for a hostname.
174 http_addrlist_t
* /* O - List of addresses or NULL */
175 httpAddrGetList(const char *hostname
, /* I - Hostname, IP address, or NULL for passive listen address */
176 int family
, /* I - Address family or AF_UNSPEC */
177 const char *service
) /* I - Service name or port number */
179 http_addrlist_t
*first
, /* First address in list */
180 *addr
, /* Current address in list */
181 *temp
; /* New address */
185 printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, service=\"%s\")\n",
186 hostname
? hostname
: "(nil)",
187 family
== AF_UNSPEC
? "UNSPEC" :
189 family
== AF_LOCAL
? "LOCAL" :
190 # endif /* AF_LOCAL */
192 family
== AF_INET6
? "INET6" :
193 # endif /* AF_INET6 */
194 family
== AF_INET
? "INET" : "???", service
);
198 * Lookup the address the best way we can...
204 if (hostname
&& hostname
[0] == '/')
207 * Domain socket address...
210 first
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
211 first
->addr
.un
.sun_family
= AF_LOCAL
;
212 strlcpy(first
->addr
.un
.sun_path
, hostname
, sizeof(first
->addr
.un
.sun_path
));
215 #endif /* AF_LOCAL */
217 #ifdef HAVE_GETADDRINFO
218 struct addrinfo hints
, /* Address lookup hints */
219 *results
, /* Address lookup results */
220 *current
; /* Current result */
221 char ipv6
[1024], /* IPv6 address */
222 *ipv6zone
; /* Pointer to zone separator */
223 int ipv6len
; /* Length of IPv6 address */
226 * Lookup the address as needed...
229 memset(&hints
, 0, sizeof(hints
));
230 hints
.ai_family
= family
;
231 hints
.ai_flags
= hostname
? 0 : AI_PASSIVE
;
232 hints
.ai_socktype
= SOCK_STREAM
;
234 if (hostname
&& *hostname
== '[')
237 * Remove brackets from numeric IPv6 address...
240 if (!strncmp(hostname
, "[v1.", 4))
243 * Copy the newer address format which supports link-local addresses...
246 strlcpy(ipv6
, hostname
+ 4, sizeof(ipv6
));
247 if ((ipv6len
= strlen(ipv6
) - 1) >= 0 && ipv6
[ipv6len
] == ']')
249 ipv6
[ipv6len
] = '\0';
253 * Convert "+zone" in address to "%zone"...
256 if ((ipv6zone
= strrchr(ipv6
, '+')) != NULL
)
263 * Copy the regular non-link-local IPv6 address...
266 strlcpy(ipv6
, hostname
+ 1, sizeof(ipv6
));
267 if ((ipv6len
= strlen(ipv6
) - 1) >= 0 && ipv6
[ipv6len
] == ']')
269 ipv6
[ipv6len
] = '\0';
275 if (!getaddrinfo(hostname
, service
, &hints
, &results
))
278 * Copy the results to our own address list structure...
281 for (current
= results
; current
; current
= current
->ai_next
)
282 if (current
->ai_family
== AF_INET
|| current
->ai_family
== AF_INET6
)
285 * Copy the address over...
288 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
291 httpAddrFreeList(first
);
295 if (current
->ai_family
== AF_INET6
)
296 memcpy(&(temp
->addr
.ipv6
), current
->ai_addr
,
297 sizeof(temp
->addr
.ipv6
));
299 memcpy(&(temp
->addr
.ipv4
), current
->ai_addr
,
300 sizeof(temp
->addr
.ipv4
));
303 * Append the address to the list...
316 * Free the results from getaddrinfo()...
319 freeaddrinfo(results
);
324 int i
; /* Looping vars */
325 unsigned ip
[4]; /* IPv4 address components */
326 const char *ptr
; /* Pointer into hostname */
327 struct hostent
*host
; /* Result of lookup */
328 struct servent
*port
; /* Port number for service */
329 int portnum
; /* Port number */
333 * Lookup the service...
338 else if (isdigit(*service
& 255))
339 portnum
= atoi(service
);
340 else if ((port
= getservbyname(service
, NULL
)) != NULL
)
341 portnum
= ntohs(port
->s_port
);
342 else if (!strcmp(service
, "http"))
344 else if (!strcmp(service
, "https"))
346 else if (!strcmp(service
, "ipp"))
348 else if (!strcmp(service
, "lpd"))
350 else if (!strcmp(service
, "socket"))
356 * This code is needed because some operating systems have a
357 * buggy implementation of gethostbyname() that does not support
358 * IPv4 addresses. If the hostname string is an IPv4 address, then
359 * sscanf() is used to extract the IPv4 components. We then pack
360 * the components into an IPv4 address manually, since the
361 * inet_aton() function is deprecated. We use the htonl() macro
362 * to get the right byte order for the address.
365 for (ptr
= hostname
; isdigit(*ptr
& 255) || *ptr
== '.'; ptr
++);
370 * We have an IPv4 address; break it up and create an IPv4 address...
373 if (sscanf(hostname
, "%u.%u.%u.%u", ip
, ip
+ 1, ip
+ 2, ip
+ 3) == 4 &&
374 ip
[0] <= 255 && ip
[1] <= 255 && ip
[2] <= 255 && ip
[3] <= 255)
376 first
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
380 first
->addr
.ipv4
.sin_family
= AF_INET
;
381 first
->addr
.ipv4
.sin_addr
.s_addr
= htonl(((((((ip
[0] << 8) |
383 ip
[2]) << 8) | ip
[3]));
384 first
->addr
.ipv4
.sin_port
= htons(portnum
);
387 else if ((host
= gethostbyname(hostname
)) != NULL
&&
389 (host
->h_addrtype
== AF_INET
|| host
->h_addrtype
== AF_INET6
))
391 host
->h_addrtype
== AF_INET
)
392 # endif /* AF_INET6 */
394 for (i
= 0; host
->h_addr_list
[i
]; i
++)
397 * Copy the address over...
400 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
403 httpAddrFreeList(first
);
408 if (host
->h_addrtype
== AF_INET6
)
410 first
->addr
.ipv6
.sin6_family
= AF_INET6
;
411 memcpy(&(temp
->addr
.ipv6
), host
->h_addr_list
[i
],
412 sizeof(temp
->addr
.ipv6
));
413 temp
->addr
.ipv6
.sin6_port
= htons(portnum
);
416 # endif /* AF_INET6 */
418 first
->addr
.ipv4
.sin_family
= AF_INET
;
419 memcpy(&(temp
->addr
.ipv4
), host
->h_addr_list
[i
],
420 sizeof(temp
->addr
.ipv4
));
421 temp
->addr
.ipv4
.sin_port
= htons(portnum
);
425 * Append the address to the list...
438 #endif /* HAVE_GETADDRINFO */
442 * Detect some common errors and handle them sanely...
445 if (!addr
&& (!hostname
|| !strcmp(hostname
, "localhost")))
447 struct servent
*port
; /* Port number for service */
448 int portnum
; /* Port number */
452 * Lookup the service...
457 else if (isdigit(*service
& 255))
458 portnum
= atoi(service
);
459 else if ((port
= getservbyname(service
, NULL
)) != NULL
)
460 portnum
= ntohs(port
->s_port
);
461 else if (!strcmp(service
, "http"))
463 else if (!strcmp(service
, "https"))
465 else if (!strcmp(service
, "ipp"))
467 else if (!strcmp(service
, "lpd"))
469 else if (!strcmp(service
, "socket"))
474 if (hostname
&& !strcmp(hostname
, "localhost"))
477 * Unfortunately, some users ignore all of the warnings in the
478 * /etc/hosts file and delete "localhost" from it. If we get here
479 * then we were unable to resolve the name, so use the IPv6 and/or
480 * IPv4 loopback interface addresses...
484 if (family
!= AF_INET
)
487 * Add [::1] to the address list...
490 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
493 httpAddrFreeList(first
);
497 temp
->addr
.ipv6
.sin6_family
= AF_INET6
;
498 temp
->addr
.ipv6
.sin6_port
= htons(portnum
);
500 temp
->addr
.ipv6
.sin6_addr
.u
.Byte
[15] = 1;
502 temp
->addr
.ipv6
.sin6_addr
.s6_addr32
[3] = htonl(1);
508 if (family
!= AF_INET6
)
509 #endif /* AF_INET6 */
512 * Add 127.0.0.1 to the address list...
515 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
518 httpAddrFreeList(first
);
522 temp
->addr
.ipv4
.sin_family
= AF_INET
;
523 temp
->addr
.ipv4
.sin_port
= htons(portnum
);
524 temp
->addr
.ipv4
.sin_addr
.s_addr
= htonl(0x7f000001);
535 * Provide one or more passive listening addresses...
539 if (family
!= AF_INET
)
542 * Add [::] to the address list...
545 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
548 httpAddrFreeList(first
);
552 temp
->addr
.ipv6
.sin6_family
= AF_INET6
;
553 temp
->addr
.ipv6
.sin6_port
= htons(portnum
);
558 if (family
!= AF_INET6
)
559 #endif /* AF_INET6 */
562 * Add 0.0.0.0 to the address list...
565 temp
= (http_addrlist_t
*)calloc(1, sizeof(http_addrlist_t
));
568 httpAddrFreeList(first
);
572 temp
->addr
.ipv4
.sin_family
= AF_INET
;
573 temp
->addr
.ipv4
.sin_port
= htons(portnum
);
584 * Return the address list...
592 * End of "$Id: http-addrlist.c 4976 2006-01-25 15:07:40Z mike $".