]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/http-addr.c
e5c3791cfd3648c386ee76e0dfa129bfa7321555
[thirdparty/cups.git] / cups / http-addr.c
1 /*
2 * "$Id$"
3 *
4 * HTTP address routines for CUPS.
5 *
6 * Copyright 2007-2013 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
8 *
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/".
14 */
15
16 /*
17 * Include necessary headers...
18 */
19
20 #include "cups-private.h"
21 #include <sys/stat.h>
22 #ifdef HAVE_RESOLV_H
23 # include <resolv.h>
24 #endif /* HAVE_RESOLV_H */
25 #ifdef __APPLE__
26 # include <CoreFoundation/CoreFoundation.h>
27 # include <SystemConfiguration/SystemConfiguration.h>
28 #endif /* __APPLE__ */
29
30
31 /*
32 * 'httpAddrAny()' - Check for the "any" address.
33 *
34 * @since CUPS 1.2/OS X 10.5@
35 */
36
37 int /* O - 1 if "any", 0 otherwise */
38 httpAddrAny(const http_addr_t *addr) /* I - Address to check */
39 {
40 if (!addr)
41 return (0);
42
43 #ifdef AF_INET6
44 if (addr->addr.sa_family == AF_INET6 &&
45 IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr)))
46 return (1);
47 #endif /* AF_INET6 */
48
49 if (addr->addr.sa_family == AF_INET &&
50 ntohl(addr->ipv4.sin_addr.s_addr) == 0x00000000)
51 return (1);
52
53 return (0);
54 }
55
56
57 /*
58 * 'httpAddrClose()' - Close a socket created by @link httpAddrConnect@ or
59 * @link httpAddrListen@.
60 *
61 * Pass @code NULL@ for sockets created with @link httpAddrConnect@ and the
62 * listen address for sockets created with @link httpAddrListen@. This will
63 * ensure that domain sockets are removed when closed.
64 *
65 * @since CUPS 2.0@
66 */
67
68 int /* O - 0 on success, -1 on failure */
69 httpAddrClose(http_addr_t *addr, /* I - Listen address or @code NULL@ */
70 int fd) /* I - Socket file descriptor */
71 {
72 #ifdef WIN32
73 if (closesocket(fd))
74 #else
75 if (close(fd))
76 #endif /* WIN32 */
77 return (-1);
78
79 #ifdef AF_LOCAL
80 if (addr && addr->addr.sa_family == AF_LOCAL)
81 return (unlink(addr->un.sun_path));
82 #endif /* AF_LOCAL */
83
84 return (0);
85 }
86
87
88 /*
89 * 'httpAddrEqual()' - Compare two addresses.
90 *
91 * @since CUPS 1.2/OS X 10.5@
92 */
93
94 int /* O - 1 if equal, 0 if not */
95 httpAddrEqual(const http_addr_t *addr1, /* I - First address */
96 const http_addr_t *addr2) /* I - Second address */
97 {
98 if (!addr1 && !addr2)
99 return (1);
100
101 if (!addr1 || !addr2)
102 return (0);
103
104 if (addr1->addr.sa_family != addr2->addr.sa_family)
105 return (0);
106
107 #ifdef AF_LOCAL
108 if (addr1->addr.sa_family == AF_LOCAL)
109 return (!strcmp(addr1->un.sun_path, addr2->un.sun_path));
110 #endif /* AF_LOCAL */
111
112 #ifdef AF_INET6
113 if (addr1->addr.sa_family == AF_INET6)
114 return (!memcmp(&(addr1->ipv6.sin6_addr), &(addr2->ipv6.sin6_addr), 16));
115 #endif /* AF_INET6 */
116
117 return (addr1->ipv4.sin_addr.s_addr == addr2->ipv4.sin_addr.s_addr);
118 }
119
120
121 /*
122 * 'httpAddrLength()' - Return the length of the address in bytes.
123 *
124 * @since CUPS 1.2/OS X 10.5@
125 */
126
127 int /* O - Length in bytes */
128 httpAddrLength(const http_addr_t *addr) /* I - Address */
129 {
130 if (!addr)
131 return (0);
132
133 #ifdef AF_INET6
134 if (addr->addr.sa_family == AF_INET6)
135 return (sizeof(addr->ipv6));
136 else
137 #endif /* AF_INET6 */
138 #ifdef AF_LOCAL
139 if (addr->addr.sa_family == AF_LOCAL)
140 return (offsetof(struct sockaddr_un, sun_path) +
141 strlen(addr->un.sun_path) + 1);
142 else
143 #endif /* AF_LOCAL */
144 if (addr->addr.sa_family == AF_INET)
145 return (sizeof(addr->ipv4));
146 else
147 return (0);
148
149 }
150
151
152 /*
153 * 'httpAddrListen()' - Create a listening socket bound to the specified
154 * address and port.
155 *
156 * @since CUPS 1.7/OS X 10.9@
157 */
158
159 int /* O - Socket or -1 on error */
160 httpAddrListen(http_addr_t *addr, /* I - Address to bind to */
161 int port) /* I - Port number to bind to */
162 {
163 int fd = -1, /* Socket */
164 val, /* Socket value */
165 status; /* Bind status */
166
167
168 /*
169 * Range check input...
170 */
171
172 if (!addr || port < 0)
173 return (-1);
174
175 /*
176 * Create the socket and set options...
177 */
178
179 if ((fd = socket(addr->addr.sa_family, SOCK_STREAM, 0)) < 0)
180 {
181 _cupsSetHTTPError(HTTP_STATUS_ERROR);
182 return (-1);
183 }
184
185 val = 1;
186 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val));
187
188 #ifdef IPV6_V6ONLY
189 if (addr->addr.sa_family == AF_INET6)
190 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, CUPS_SOCAST &val, sizeof(val));
191 #endif /* IPV6_V6ONLY */
192
193 /*
194 * Bind the socket...
195 */
196
197 #ifdef AF_LOCAL
198 if (addr->addr.sa_family == AF_LOCAL)
199 {
200 mode_t mask; /* Umask setting */
201
202 /*
203 * Remove any existing domain socket file...
204 */
205
206 unlink(addr->un.sun_path);
207
208 /*
209 * Save the current umask and set it to 0 so that all users can access
210 * the domain socket...
211 */
212
213 mask = umask(0);
214
215 /*
216 * Bind the domain socket...
217 */
218
219 status = bind(fd, (struct sockaddr *)addr, httpAddrLength(addr));
220
221 /*
222 * Restore the umask and fix permissions...
223 */
224
225 umask(mask);
226 chmod(addr->un.sun_path, 0140777);
227 }
228 else
229 #endif /* AF_LOCAL */
230 {
231 _httpAddrSetPort(addr, port);
232
233 status = bind(fd, (struct sockaddr *)addr, httpAddrLength(addr));
234 }
235
236 if (status)
237 {
238 _cupsSetHTTPError(HTTP_STATUS_ERROR);
239
240 close(fd);
241
242 return (-1);
243 }
244
245 /*
246 * Listen...
247 */
248
249 if (listen(fd, 5))
250 {
251 _cupsSetHTTPError(HTTP_STATUS_ERROR);
252
253 close(fd);
254
255 return (-1);
256 }
257
258 /*
259 * Close on exec...
260 */
261
262 #ifndef WIN32
263 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
264 #endif /* !WIN32 */
265
266 #ifdef SO_NOSIGPIPE
267 /*
268 * Disable SIGPIPE for this socket.
269 */
270
271 val = 1;
272 setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val));
273 #endif /* SO_NOSIGPIPE */
274
275 return (fd);
276 }
277
278
279 /*
280 * 'httpAddrLocalhost()' - Check for the local loopback address.
281 *
282 * @since CUPS 1.2/OS X 10.5@
283 */
284
285 int /* O - 1 if local host, 0 otherwise */
286 httpAddrLocalhost(
287 const http_addr_t *addr) /* I - Address to check */
288 {
289 if (!addr)
290 return (1);
291
292 #ifdef AF_INET6
293 if (addr->addr.sa_family == AF_INET6 &&
294 IN6_IS_ADDR_LOOPBACK(&(addr->ipv6.sin6_addr)))
295 return (1);
296 #endif /* AF_INET6 */
297
298 #ifdef AF_LOCAL
299 if (addr->addr.sa_family == AF_LOCAL)
300 return (1);
301 #endif /* AF_LOCAL */
302
303 if (addr->addr.sa_family == AF_INET &&
304 (ntohl(addr->ipv4.sin_addr.s_addr) & 0xff000000) == 0x7f000000)
305 return (1);
306
307 return (0);
308 }
309
310
311 /*
312 * 'httpAddrLookup()' - Lookup the hostname associated with the address.
313 *
314 * @since CUPS 1.2/OS X 10.5@
315 */
316
317 char * /* O - Host name */
318 httpAddrLookup(
319 const http_addr_t *addr, /* I - Address to lookup */
320 char *name, /* I - Host name buffer */
321 int namelen) /* I - Size of name buffer */
322 {
323 _cups_globals_t *cg = _cupsGlobals();
324 /* Global data */
325
326
327 DEBUG_printf(("httpAddrLookup(addr=%p, name=%p, namelen=%d)", addr, name,
328 namelen));
329
330 /*
331 * Range check input...
332 */
333
334 if (!addr || !name || namelen <= 2)
335 {
336 if (name && namelen >= 1)
337 *name = '\0';
338
339 return (NULL);
340 }
341
342 #ifdef AF_LOCAL
343 if (addr->addr.sa_family == AF_LOCAL)
344 {
345 strlcpy(name, addr->un.sun_path, namelen);
346 return (name);
347 }
348 #endif /* AF_LOCAL */
349
350 /*
351 * Optimize lookups for localhost/loopback addresses...
352 */
353
354 if (httpAddrLocalhost(addr))
355 {
356 strlcpy(name, "localhost", namelen);
357 return (name);
358 }
359
360 #ifdef HAVE_RES_INIT
361 /*
362 * STR #2920: Initialize resolver after failure in cups-polld
363 *
364 * If the previous lookup failed, re-initialize the resolver to prevent
365 * temporary network errors from persisting. This *should* be handled by
366 * the resolver libraries, but apparently the glibc folks do not agree.
367 *
368 * We set a flag at the end of this function if we encounter an error that
369 * requires reinitialization of the resolver functions. We then call
370 * res_init() if the flag is set on the next call here or in httpAddrLookup().
371 */
372
373 if (cg->need_res_init)
374 {
375 res_init();
376
377 cg->need_res_init = 0;
378 }
379 #endif /* HAVE_RES_INIT */
380
381 #ifdef HAVE_GETNAMEINFO
382 {
383 /*
384 * STR #2486: httpAddrLookup() fails when getnameinfo() returns EAI_AGAIN
385 *
386 * FWIW, I think this is really a bug in the implementation of
387 * getnameinfo(), but falling back on httpAddrString() is easy to
388 * do...
389 */
390
391 int error = getnameinfo(&addr->addr, httpAddrLength(addr), name, namelen,
392 NULL, 0, 0);
393
394 if (error)
395 {
396 if (error == EAI_FAIL)
397 cg->need_res_init = 1;
398
399 return (httpAddrString(addr, name, namelen));
400 }
401 }
402 #else
403 {
404 struct hostent *host; /* Host from name service */
405
406
407 # ifdef AF_INET6
408 if (addr->addr.sa_family == AF_INET6)
409 host = gethostbyaddr((char *)&(addr->ipv6.sin6_addr),
410 sizeof(struct in_addr), AF_INET6);
411 else
412 # endif /* AF_INET6 */
413 host = gethostbyaddr((char *)&(addr->ipv4.sin_addr),
414 sizeof(struct in_addr), AF_INET);
415
416 if (host == NULL)
417 {
418 /*
419 * No hostname, so return the raw address...
420 */
421
422 if (h_errno == NO_RECOVERY)
423 cg->need_res_init = 1;
424
425 return (httpAddrString(addr, name, namelen));
426 }
427
428 strlcpy(name, host->h_name, namelen);
429 }
430 #endif /* HAVE_GETNAMEINFO */
431
432 DEBUG_printf(("1httpAddrLookup: returning \"%s\"...", name));
433
434 return (name);
435 }
436
437
438 /*
439 * 'httpAddrFamily()' - Get the address family of an address.
440 */
441
442 int /* O - Address family */
443 httpAddrFamily(http_addr_t *addr) /* I - Address */
444 {
445 if (addr)
446 return (addr->addr.sa_family);
447 else
448 return (0);
449 }
450
451
452 /*
453 * 'httpAddrPort()' - Get the port number associated with an address.
454 *
455 * @since CUPS 1.7/OS X 10.9@
456 */
457
458 int /* O - Port number */
459 httpAddrPort(http_addr_t *addr) /* I - Address */
460 {
461 if (!addr)
462 return (-1);
463 #ifdef AF_INET6
464 else if (addr->addr.sa_family == AF_INET6)
465 return (ntohs(addr->ipv6.sin6_port));
466 #endif /* AF_INET6 */
467 else if (addr->addr.sa_family == AF_INET)
468 return (ntohs(addr->ipv4.sin_port));
469 else
470 return (0);
471 }
472
473 /* For OS X 10.8 and earlier */
474 int _httpAddrPort(http_addr_t *addr) { return (httpAddrPort(addr)); }
475
476
477 /*
478 * '_httpAddrSetPort()' - Set the port number associated with an address.
479 */
480
481 void
482 _httpAddrSetPort(http_addr_t *addr, /* I - Address */
483 int port) /* I - Port */
484 {
485 if (!addr || port <= 0)
486 return;
487
488 #ifdef AF_INET6
489 if (addr->addr.sa_family == AF_INET6)
490 addr->ipv6.sin6_port = htons(port);
491 else
492 #endif /* AF_INET6 */
493 if (addr->addr.sa_family == AF_INET)
494 addr->ipv4.sin_port = htons(port);
495 }
496
497
498 /*
499 * 'httpAddrString()' - Convert an address to a numeric string.
500 *
501 * @since CUPS 1.2/OS X 10.5@
502 */
503
504 char * /* O - Numeric address string */
505 httpAddrString(const http_addr_t *addr, /* I - Address to convert */
506 char *s, /* I - String buffer */
507 int slen) /* I - Length of string */
508 {
509 DEBUG_printf(("httpAddrString(addr=%p, s=%p, slen=%d)", addr, s, slen));
510
511 /*
512 * Range check input...
513 */
514
515 if (!addr || !s || slen <= 2)
516 {
517 if (s && slen >= 1)
518 *s = '\0';
519
520 return (NULL);
521 }
522
523 #ifdef AF_LOCAL
524 if (addr->addr.sa_family == AF_LOCAL)
525 {
526 if (addr->un.sun_path[0] == '/')
527 strlcpy(s, addr->un.sun_path, slen);
528 else
529 strlcpy(s, "localhost", slen);
530 }
531 else
532 #endif /* AF_LOCAL */
533 if (addr->addr.sa_family == AF_INET)
534 {
535 unsigned temp; /* Temporary address */
536
537
538 temp = ntohl(addr->ipv4.sin_addr.s_addr);
539
540 snprintf(s, slen, "%d.%d.%d.%d", (temp >> 24) & 255,
541 (temp >> 16) & 255, (temp >> 8) & 255, temp & 255);
542 }
543 #ifdef AF_INET6
544 else if (addr->addr.sa_family == AF_INET6)
545 {
546 char *sptr, /* Pointer into string */
547 temps[64]; /* Temporary string for address */
548
549 # ifdef HAVE_GETNAMEINFO
550 if (getnameinfo(&addr->addr, httpAddrLength(addr), temps, sizeof(temps),
551 NULL, 0, NI_NUMERICHOST))
552 {
553 /*
554 * If we get an error back, then the address type is not supported
555 * and we should zero out the buffer...
556 */
557
558 s[0] = '\0';
559
560 return (NULL);
561 }
562 else if ((sptr = strchr(temps, '%')) != NULL)
563 {
564 /*
565 * Convert "%zone" to "+zone" to match URI form...
566 */
567
568 *sptr = '+';
569 }
570
571 # else
572 int i; /* Looping var */
573 unsigned temp; /* Current value */
574 const char *prefix; /* Prefix for address */
575
576
577 prefix = "";
578 for (sptr = temps, i = 0; i < 4 && addr->ipv6.sin6_addr.s6_addr32[i]; i ++)
579 {
580 temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]);
581
582 snprintf(sptr, sizeof(temps) - (sptr - temps), "%s%x", prefix,
583 (temp >> 16) & 0xffff);
584 prefix = ":";
585 sptr += strlen(sptr);
586
587 temp &= 0xffff;
588
589 if (temp || i == 3 || addr->ipv6.sin6_addr.s6_addr32[i + 1])
590 {
591 snprintf(sptr, sizeof(temps) - (sptr - temps), "%s%x", prefix, temp);
592 sptr += strlen(sptr);
593 }
594 }
595
596 if (i < 4)
597 {
598 while (i < 4 && !addr->ipv6.sin6_addr.s6_addr32[i])
599 i ++;
600
601 if (i < 4)
602 {
603 snprintf(sptr, sizeof(temps) - (sptr - temps), "%s:", prefix);
604 prefix = ":";
605 sptr += strlen(sptr);
606
607 for (; i < 4; i ++)
608 {
609 temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]);
610
611 if ((temp & 0xffff0000) ||
612 (i > 0 && addr->ipv6.sin6_addr.s6_addr32[i - 1]))
613 {
614 snprintf(sptr, sizeof(temps) - (sptr - temps), "%s%x", prefix,
615 (temp >> 16) & 0xffff);
616 sptr += strlen(sptr);
617 }
618
619 snprintf(sptr, sizeof(temps) - (sptr - temps), "%s%x", prefix,
620 temp & 0xffff);
621 sptr += strlen(sptr);
622 }
623 }
624 else if (sptr == s)
625 {
626 /*
627 * Empty address...
628 */
629
630 strlcpy(temps, "::", sizeof(temps));
631 }
632 else
633 {
634 /*
635 * Empty at end...
636 */
637
638 strlcpy(sptr, "::", sizeof(temps) - (sptr - temps));
639 }
640 }
641 # endif /* HAVE_GETNAMEINFO */
642
643 /*
644 * Add "[v1." and "]" around IPv6 address to convert to URI form.
645 */
646
647 snprintf(s, slen, "[v1.%s]", temps);
648 }
649 #endif /* AF_INET6 */
650 else
651 strlcpy(s, "UNKNOWN", slen);
652
653 DEBUG_printf(("1httpAddrString: returning \"%s\"...", s));
654
655 return (s);
656 }
657
658
659 /*
660 * 'httpGetAddress()' - Get the address of the connected peer of a connection.
661 *
662 * Returns @code NULL@ if the socket is currently unconnected.
663 *
664 * @since CUPS 2.0@
665 */
666
667 http_addr_t * /* O - Connected address or @code NULL@ */
668 httpGetAddress(http_t *http) /* I - HTTP connection */
669 {
670 if (http)
671 return (http->hostaddr);
672 else
673 return (NULL);
674 }
675
676
677 /*
678 * 'httpGetHostByName()' - Lookup a hostname or IPv4 address, and return
679 * address records for the specified name.
680 *
681 * @deprecated@
682 */
683
684 struct hostent * /* O - Host entry */
685 httpGetHostByName(const char *name) /* I - Hostname or IP address */
686 {
687 const char *nameptr; /* Pointer into name */
688 unsigned ip[4]; /* IP address components */
689 _cups_globals_t *cg = _cupsGlobals();
690 /* Pointer to library globals */
691
692
693 DEBUG_printf(("httpGetHostByName(name=\"%s\")", name));
694
695 /*
696 * Avoid lookup delays and configuration problems when connecting
697 * to the localhost address...
698 */
699
700 if (!strcmp(name, "localhost"))
701 name = "127.0.0.1";
702
703 /*
704 * This function is needed because some operating systems have a
705 * buggy implementation of gethostbyname() that does not support
706 * IP addresses. If the first character of the name string is a
707 * number, then sscanf() is used to extract the IP components.
708 * We then pack the components into an IPv4 address manually,
709 * since the inet_aton() function is deprecated. We use the
710 * htonl() macro to get the right byte order for the address.
711 *
712 * We also support domain sockets when supported by the underlying
713 * OS...
714 */
715
716 #ifdef AF_LOCAL
717 if (name[0] == '/')
718 {
719 /*
720 * A domain socket address, so make an AF_LOCAL entry and return it...
721 */
722
723 cg->hostent.h_name = (char *)name;
724 cg->hostent.h_aliases = NULL;
725 cg->hostent.h_addrtype = AF_LOCAL;
726 cg->hostent.h_length = strlen(name) + 1;
727 cg->hostent.h_addr_list = cg->ip_ptrs;
728 cg->ip_ptrs[0] = (char *)name;
729 cg->ip_ptrs[1] = NULL;
730
731 DEBUG_puts("1httpGetHostByName: returning domain socket address...");
732
733 return (&cg->hostent);
734 }
735 #endif /* AF_LOCAL */
736
737 for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++);
738
739 if (!*nameptr)
740 {
741 /*
742 * We have an IPv4 address; break it up and provide the host entry
743 * to the caller.
744 */
745
746 if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4)
747 return (NULL); /* Must have 4 numbers */
748
749 if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255)
750 return (NULL); /* Invalid byte ranges! */
751
752 cg->ip_addr = htonl(((((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) |
753 ip[3]));
754
755 /*
756 * Fill in the host entry and return it...
757 */
758
759 cg->hostent.h_name = (char *)name;
760 cg->hostent.h_aliases = NULL;
761 cg->hostent.h_addrtype = AF_INET;
762 cg->hostent.h_length = 4;
763 cg->hostent.h_addr_list = cg->ip_ptrs;
764 cg->ip_ptrs[0] = (char *)&(cg->ip_addr);
765 cg->ip_ptrs[1] = NULL;
766
767 DEBUG_puts("1httpGetHostByName: returning IPv4 address...");
768
769 return (&cg->hostent);
770 }
771 else
772 {
773 /*
774 * Use the gethostbyname() function to get the IPv4 address for
775 * the name...
776 */
777
778 DEBUG_puts("1httpGetHostByName: returning domain lookup address(es)...");
779
780 return (gethostbyname(name));
781 }
782 }
783
784
785 /*
786 * 'httpGetHostname()' - Get the FQDN for the connection or local system.
787 *
788 * When "http" points to a connected socket, return the hostname or
789 * address that was used in the call to httpConnect() or httpConnectEncrypt(),
790 * or the address of the client for the connection from httpAcceptConnection().
791 * Otherwise, return the FQDN for the local system using both gethostname()
792 * and gethostbyname() to get the local hostname with domain.
793 *
794 * @since CUPS 1.2/OS X 10.5@
795 */
796
797 const char * /* O - FQDN for connection or system */
798 httpGetHostname(http_t *http, /* I - HTTP connection or NULL */
799 char *s, /* I - String buffer for name */
800 int slen) /* I - Size of buffer */
801 {
802 if (http)
803 {
804 if (!s || slen <= 1)
805 {
806 if (http->hostname[0] == '/')
807 return ("localhost");
808 else
809 return (http->hostname);
810 }
811 else if (http->hostname[0] == '/')
812 strlcpy(s, "localhost", slen);
813 else
814 strlcpy(s, http->hostname, slen);
815 }
816 else
817 {
818 /*
819 * Get the hostname...
820 */
821
822 if (!s || slen <= 1)
823 return (NULL);
824
825 if (gethostname(s, slen) < 0)
826 strlcpy(s, "localhost", slen);
827
828 if (!strchr(s, '.'))
829 {
830 #ifdef HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME
831 /*
832 * The hostname is not a FQDN, so use the local hostname from the
833 * SystemConfiguration framework...
834 */
835
836 SCDynamicStoreRef sc = SCDynamicStoreCreate(kCFAllocatorDefault,
837 CFSTR("libcups"), NULL, NULL);
838 /* System configuration data */
839 CFStringRef local = sc ? SCDynamicStoreCopyLocalHostName(sc) : NULL;
840 /* Local host name */
841 char localStr[1024]; /* Local host name C string */
842
843 if (local && CFStringGetCString(local, localStr, sizeof(localStr),
844 kCFStringEncodingUTF8))
845 {
846 /*
847 * Append ".local." to the hostname we get...
848 */
849
850 snprintf(s, slen, "%s.local.", localStr);
851 }
852
853 if (local)
854 CFRelease(local);
855 if (sc)
856 CFRelease(sc);
857
858 #else
859 /*
860 * The hostname is not a FQDN, so look it up...
861 */
862
863 struct hostent *host; /* Host entry to get FQDN */
864
865 if ((host = gethostbyname(s)) != NULL && host->h_name)
866 {
867 /*
868 * Use the resolved hostname...
869 */
870
871 strlcpy(s, host->h_name, slen);
872 }
873 #endif /* HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME */
874 }
875 }
876
877 /*
878 * Return the hostname with as much domain info as we have...
879 */
880
881 return (s);
882 }
883
884
885 /*
886 * 'httpResolveHostname()' - Resolve the hostname of the HTTP connection
887 * address.
888 *
889 * @since CUPS 2.0@
890 */
891
892 const char * /* O - Resolved hostname or @code NULL@ */
893 httpResolveHostname(http_t *http, /* I - HTTP connection */
894 char *buffer, /* I - Hostname buffer */
895 size_t bufsize) /* I - Size of buffer */
896 {
897 if (!http)
898 return (NULL);
899
900 if (isdigit(http->hostname[0] & 255) || http->hostname[0] == '[')
901 {
902 char temp[1024]; /* Temporary string */
903
904 if (httpAddrLookup(http->hostaddr, temp, sizeof(temp)))
905 strlcpy(http->hostname, temp, sizeof(http->hostname));
906 else
907 return (NULL);
908 }
909
910 if (buffer)
911 {
912 if (http->hostname[0] == '/')
913 strlcpy(buffer, "localhost", bufsize);
914 else
915 strlcpy(buffer, http->hostname, bufsize);
916
917 return (buffer);
918 }
919 else if (http->hostname[0] == '/')
920 return ("localhost");
921 else
922 return (http->hostname);
923 }
924
925
926 /*
927 * End of "$Id$".
928 */