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