/src/libcups/cups/http-addr.c
Line | Count | Source |
1 | | // |
2 | | // HTTP address routines for CUPS. |
3 | | // |
4 | | // Copyright © 2021-2024 by OpenPrinting. |
5 | | // Copyright © 2007-2021 by Apple Inc. |
6 | | // Copyright © 1997-2006 by Easy Software Products, all rights reserved. |
7 | | // |
8 | | // Licensed under Apache License v2.0. See the file "LICENSE" for more |
9 | | // information. |
10 | | // |
11 | | |
12 | | #include "cups-private.h" |
13 | | #include <sys/stat.h> |
14 | | #ifdef HAVE_RESOLV_H |
15 | | # include <resolv.h> |
16 | | #endif // HAVE_RESOLV_H |
17 | | #ifdef __APPLE__ |
18 | | # include <CoreFoundation/CoreFoundation.h> |
19 | | # ifdef HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME |
20 | | # include <SystemConfiguration/SystemConfiguration.h> |
21 | | # endif // HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME |
22 | | #endif // __APPLE__ |
23 | | |
24 | | |
25 | | // |
26 | | // 'httpAddrClose()' - Close a socket created by @link httpAddrConnect@ or |
27 | | // @link httpAddrListen@. |
28 | | // |
29 | | // Pass `NULL` for sockets created with @link httpAddrConnect@ and the |
30 | | // listen address for sockets created with @link httpAddrListen@. This function |
31 | | // ensures that domain sockets are removed when closed. |
32 | | // |
33 | | |
34 | | bool // O - `true` on success, `false` on failure |
35 | | httpAddrClose(http_addr_t *addr, // I - Listen address or `NULL` |
36 | | int fd) // I - Socket file descriptor |
37 | 0 | { |
38 | | #ifdef _WIN32 |
39 | | if (closesocket(fd)) |
40 | | #else |
41 | 0 | if (close(fd)) |
42 | 0 | #endif // _WIN32 |
43 | 0 | return (false); |
44 | | |
45 | 0 | #ifdef AF_LOCAL |
46 | 0 | if (addr && addr->addr.sa_family == AF_LOCAL) |
47 | 0 | return (!unlink(addr->un.sun_path)); |
48 | 0 | #endif // AF_LOCAL |
49 | | |
50 | 0 | return (true); |
51 | 0 | } |
52 | | |
53 | | |
54 | | // |
55 | | // 'httpGetAddress()' - Get the address of the connected peer of a connection. |
56 | | // |
57 | | // For connections created with @link httpConnect2@, the address is for the |
58 | | // server. For connections created with @link httpAccept@, the address is for |
59 | | // the client. |
60 | | // |
61 | | // Returns `NULL` if the socket is currently unconnected. |
62 | | // |
63 | | |
64 | | http_addr_t * // O - Connected address or `NULL` |
65 | | httpGetAddress(http_t *http) // I - HTTP connection |
66 | 0 | { |
67 | 0 | return (http ? http->hostaddr : NULL); |
68 | 0 | } |
69 | | |
70 | | |
71 | | // |
72 | | // 'httpAddrGetFamily()' - Get the address family of an address. |
73 | | // |
74 | | |
75 | | int // O - Address family |
76 | | httpAddrGetFamily(http_addr_t *addr) // I - Address |
77 | 0 | { |
78 | 0 | if (addr) |
79 | 0 | return (addr->addr.sa_family); |
80 | 0 | else |
81 | 0 | return (0); |
82 | 0 | } |
83 | | |
84 | | |
85 | | // |
86 | | // 'httpAddrGetLength()' - Return the length of the address in bytes. |
87 | | // |
88 | | |
89 | | size_t // O - Length in bytes |
90 | | httpAddrGetLength( |
91 | | const http_addr_t *addr) // I - Address |
92 | 0 | { |
93 | 0 | if (!addr) |
94 | 0 | return (0); |
95 | | |
96 | 0 | #ifdef AF_INET6 |
97 | 0 | if (addr->addr.sa_family == AF_INET6) |
98 | 0 | return (sizeof(addr->ipv6)); |
99 | 0 | else |
100 | 0 | #endif // AF_INET6 |
101 | 0 | #ifdef AF_LOCAL |
102 | 0 | if (addr->addr.sa_family == AF_LOCAL) |
103 | 0 | return (offsetof(struct sockaddr_un, sun_path) + strlen(addr->un.sun_path) + 1); |
104 | 0 | else |
105 | 0 | #endif // AF_LOCAL |
106 | 0 | if (addr->addr.sa_family == AF_INET) |
107 | 0 | return (sizeof(addr->ipv4)); |
108 | 0 | else |
109 | 0 | return (0); |
110 | |
|
111 | 0 | } |
112 | | |
113 | | |
114 | | // |
115 | | // 'httpAddrGetPort()' - Get the port number associated with an address. |
116 | | // |
117 | | |
118 | | int // O - Port number |
119 | | httpAddrGetPort(http_addr_t *addr) // I - Address |
120 | 0 | { |
121 | 0 | if (!addr) |
122 | 0 | return (-1); |
123 | 0 | #ifdef AF_INET6 |
124 | 0 | else if (addr->addr.sa_family == AF_INET6) |
125 | 0 | return (ntohs(addr->ipv6.sin6_port)); |
126 | 0 | #endif // AF_INET6 |
127 | 0 | else if (addr->addr.sa_family == AF_INET) |
128 | 0 | return (ntohs(addr->ipv4.sin_port)); |
129 | 0 | else |
130 | 0 | return (0); |
131 | 0 | } |
132 | | |
133 | | |
134 | | // |
135 | | // 'httpAddrGetString()' - Convert an address to a numeric string. |
136 | | // |
137 | | |
138 | | char * // O - Numeric address string |
139 | | httpAddrGetString( |
140 | | const http_addr_t *addr, // I - Address to convert |
141 | | char *s, // I - String buffer |
142 | | size_t slen) // I - Length of string buffer |
143 | 0 | { |
144 | 0 | DEBUG_printf("httpAddrGetString(addr=%p, s=%p, slen=%u)", (void *)addr, (void *)s, (unsigned)slen); |
145 | | |
146 | | // Range check input... |
147 | 0 | if (!addr || !s || slen <= 2) |
148 | 0 | { |
149 | 0 | if (s && slen >= 1) |
150 | 0 | *s = '\0'; |
151 | |
|
152 | 0 | return (NULL); |
153 | 0 | } |
154 | | |
155 | 0 | #ifdef AF_LOCAL |
156 | 0 | if (addr->addr.sa_family == AF_LOCAL) |
157 | 0 | { |
158 | 0 | if (addr->un.sun_path[0] == '/') |
159 | 0 | cupsCopyString(s, addr->un.sun_path, (size_t)slen); |
160 | 0 | else |
161 | 0 | cupsCopyString(s, "localhost", (size_t)slen); |
162 | 0 | } |
163 | 0 | else |
164 | 0 | #endif // AF_LOCAL |
165 | 0 | if (addr->addr.sa_family == AF_INET) |
166 | 0 | { |
167 | 0 | unsigned temp; // Temporary address |
168 | |
|
169 | 0 | temp = ntohl(addr->ipv4.sin_addr.s_addr); |
170 | |
|
171 | 0 | snprintf(s, (size_t)slen, "%d.%d.%d.%d", (temp >> 24) & 255, (temp >> 16) & 255, (temp >> 8) & 255, temp & 255); |
172 | 0 | } |
173 | 0 | #ifdef AF_INET6 |
174 | 0 | else if (addr->addr.sa_family == AF_INET6) |
175 | 0 | { |
176 | 0 | char *sptr, // Pointer into string |
177 | 0 | temps[64]; // Temporary string for address |
178 | |
|
179 | 0 | if (getnameinfo(&addr->addr, (socklen_t)httpAddrGetLength(addr), temps, sizeof(temps), NULL, 0, NI_NUMERICHOST)) |
180 | 0 | { |
181 | | // If we get an error back, then the address type is not supported |
182 | | // and we should zero out the buffer... |
183 | 0 | s[0] = '\0'; |
184 | |
|
185 | 0 | return (NULL); |
186 | 0 | } |
187 | 0 | else if ((sptr = strchr(temps, '%')) != NULL) |
188 | 0 | { |
189 | | // Convert "%zone" to "+zone" to match URI form... |
190 | 0 | *sptr = '+'; |
191 | 0 | } |
192 | | |
193 | | // Add "[v1." and "]" around IPv6 address to convert to URI form. |
194 | 0 | snprintf(s, (size_t)slen, "[v1.%s]", temps); |
195 | 0 | } |
196 | 0 | #endif // AF_INET6 |
197 | 0 | else |
198 | 0 | { |
199 | 0 | cupsCopyString(s, "UNKNOWN", (size_t)slen); |
200 | 0 | } |
201 | | |
202 | 0 | DEBUG_printf("2httpAddrGetString: returning \"%s\"...", s); |
203 | |
|
204 | 0 | return (s); |
205 | 0 | } |
206 | | |
207 | | |
208 | | // |
209 | | // 'httpAddrIsAny()' - Check for the "any" address. |
210 | | // |
211 | | |
212 | | bool // O - `true` if "any", `false` otherwise |
213 | | httpAddrIsAny(const http_addr_t *addr) // I - Address to check |
214 | 0 | { |
215 | 0 | if (!addr) |
216 | 0 | return (false); |
217 | | |
218 | 0 | #ifdef AF_INET6 |
219 | 0 | if (addr->addr.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr))) |
220 | 0 | return (true); |
221 | 0 | #endif // AF_INET6 |
222 | | |
223 | 0 | if (addr->addr.sa_family == AF_INET && ntohl(addr->ipv4.sin_addr.s_addr) == 0x00000000) |
224 | 0 | return (true); |
225 | | |
226 | 0 | return (false); |
227 | 0 | } |
228 | | |
229 | | |
230 | | // |
231 | | // 'httpAddrIsEqual()' - Compare two addresses. |
232 | | // |
233 | | |
234 | | bool // O - `true` if equal, `false` if not |
235 | | httpAddrIsEqual( |
236 | | const http_addr_t *addr1, // I - First address |
237 | | const http_addr_t *addr2) // I - Second address |
238 | 0 | { |
239 | 0 | if (!addr1 && !addr2) |
240 | 0 | return (true); |
241 | | |
242 | 0 | if (!addr1 || !addr2) |
243 | 0 | return (false); |
244 | | |
245 | 0 | if (addr1->addr.sa_family != addr2->addr.sa_family) |
246 | 0 | return (false); |
247 | | |
248 | 0 | #ifdef AF_LOCAL |
249 | 0 | if (addr1->addr.sa_family == AF_LOCAL) |
250 | 0 | return (!strcmp(addr1->un.sun_path, addr2->un.sun_path)); |
251 | 0 | #endif // AF_LOCAL |
252 | | |
253 | 0 | #ifdef AF_INET6 |
254 | 0 | if (addr1->addr.sa_family == AF_INET6) |
255 | 0 | return (!memcmp(&(addr1->ipv6.sin6_addr), &(addr2->ipv6.sin6_addr), 16)); |
256 | 0 | #endif // AF_INET6 |
257 | | |
258 | 0 | return (addr1->ipv4.sin_addr.s_addr == addr2->ipv4.sin_addr.s_addr); |
259 | 0 | } |
260 | | |
261 | | |
262 | | // |
263 | | // 'httpAddrIsLocalhost()' - Check for the local loopback address. |
264 | | // |
265 | | |
266 | | bool // O - `true` if local host, `false` otherwise |
267 | | httpAddrIsLocalhost( |
268 | | const http_addr_t *addr) // I - Address to check |
269 | 0 | { |
270 | 0 | if (!addr) |
271 | 0 | return (true); |
272 | | |
273 | 0 | #ifdef AF_INET6 |
274 | 0 | if (addr->addr.sa_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&(addr->ipv6.sin6_addr))) |
275 | 0 | return (true); |
276 | 0 | #endif // AF_INET6 |
277 | | |
278 | 0 | #ifdef AF_LOCAL |
279 | 0 | if (addr->addr.sa_family == AF_LOCAL) |
280 | 0 | return (true); |
281 | 0 | #endif // AF_LOCAL |
282 | | |
283 | 0 | if (addr->addr.sa_family == AF_INET && (ntohl(addr->ipv4.sin_addr.s_addr) & 0xff000000) == 0x7f000000) |
284 | 0 | return (true); |
285 | | |
286 | 0 | return (false); |
287 | 0 | } |
288 | | |
289 | | |
290 | | // |
291 | | // 'httpAddrListen()' - Create a listening socket bound to the specified address and port. |
292 | | // |
293 | | |
294 | | int // O - Socket or `-1` on error |
295 | | httpAddrListen(http_addr_t *addr, // I - Address to bind to |
296 | | int port) // I - Port number to bind to |
297 | 0 | { |
298 | 0 | int fd = -1, // Socket |
299 | 0 | val, // Socket value |
300 | 0 | status; // Bind status |
301 | | |
302 | | |
303 | | // Range check input... |
304 | 0 | if (!addr || port < 0) |
305 | 0 | return (-1); |
306 | | |
307 | | // Make sure the network stack is initialized... |
308 | 0 | httpInitialize(); |
309 | | |
310 | | // Create the socket and set options... |
311 | 0 | if ((fd = socket(addr->addr.sa_family, SOCK_STREAM, 0)) < 0) |
312 | 0 | { |
313 | 0 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), false); |
314 | 0 | return (-1); |
315 | 0 | } |
316 | | |
317 | 0 | val = 1; |
318 | 0 | if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val))) |
319 | 0 | DEBUG_printf("2httpAddrListen: setsockopt(SO_REUSEADDR) failed: %s", strerror(errno)); |
320 | |
|
321 | 0 | #ifdef IPV6_V6ONLY |
322 | 0 | if (addr->addr.sa_family == AF_INET6) |
323 | 0 | { |
324 | 0 | if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, CUPS_SOCAST &val, sizeof(val))) |
325 | 0 | DEBUG_printf("2httpAddrListen: setsockopt(IPv6_V6ONLY) failed: %s", strerror(errno)); |
326 | 0 | } |
327 | 0 | #endif // IPV6_V6ONLY |
328 | | |
329 | | // Bind the socket... |
330 | 0 | #ifdef AF_LOCAL |
331 | 0 | if (addr->addr.sa_family == AF_LOCAL) |
332 | 0 | { |
333 | 0 | mode_t mask; // Umask setting |
334 | | |
335 | | // Remove any existing domain socket file... |
336 | 0 | if ((status = unlink(addr->un.sun_path)) < 0) |
337 | 0 | { |
338 | 0 | if (errno == ENOENT) |
339 | 0 | status = 0; |
340 | 0 | else |
341 | 0 | DEBUG_printf("2httpAddrListen: Unable to unlink '%s': %s", |
342 | 0 | addr->un.sun_path, strerror(errno)); |
343 | 0 | } |
344 | |
|
345 | 0 | if (!status) |
346 | 0 | { |
347 | | // Save the current umask and set it to 0 so that all users can access |
348 | | // the domain socket... |
349 | 0 | mask = umask(0); |
350 | | |
351 | | // Bind the domain socket... |
352 | 0 | if ((status = bind(fd, (struct sockaddr *)addr, (socklen_t)httpAddrGetLength(addr))) < 0) |
353 | 0 | DEBUG_printf("1httpAddrListen: Unable to bind domain socket \"%s\": %s", addr->un.sun_path, strerror(errno)); |
354 | | |
355 | | // Restore the umask and fix permissions... |
356 | 0 | umask(mask); |
357 | 0 | } |
358 | 0 | } |
359 | 0 | else |
360 | 0 | #endif // AF_LOCAL |
361 | 0 | { |
362 | 0 | httpAddrSetPort(addr, port); |
363 | |
|
364 | 0 | if ((status = bind(fd, (struct sockaddr *)addr, (socklen_t)httpAddrGetLength(addr))) < 0) |
365 | 0 | DEBUG_printf("1httpAddrListen: Unable to bind network socket: %s", strerror(errno)); |
366 | 0 | } |
367 | |
|
368 | 0 | if (status) |
369 | 0 | { |
370 | 0 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), false); |
371 | |
|
372 | 0 | close(fd); |
373 | |
|
374 | 0 | return (-1); |
375 | 0 | } |
376 | | |
377 | | // Listen... |
378 | 0 | if (listen(fd, INT_MAX)) |
379 | 0 | { |
380 | 0 | DEBUG_printf("1httpAddrListen: Unable to listen on socket: %s", strerror(errno)); |
381 | 0 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), false); |
382 | |
|
383 | 0 | close(fd); |
384 | |
|
385 | 0 | return (-1); |
386 | 0 | } |
387 | | |
388 | | // Close on exec... |
389 | 0 | #ifndef _WIN32 |
390 | 0 | if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC)) |
391 | 0 | DEBUG_printf("2httpAddrListen: fcntl(F_SETFD, FD_CLOEXEC) failed: %s", strerror(errno)); |
392 | 0 | #endif // !_WIN32 |
393 | |
|
394 | | #ifdef SO_NOSIGPIPE |
395 | | // Disable SIGPIPE for this socket. |
396 | | val = 1; |
397 | | if (setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val))) |
398 | | DEBUG_printf("2httpAddrListen: setsockopt(SO_NOSIGPIPE) failed: %s", strerror(errno)); |
399 | | #endif // SO_NOSIGPIPE |
400 | |
|
401 | 0 | return (fd); |
402 | 0 | } |
403 | | |
404 | | |
405 | | // |
406 | | // 'httpAddrLookup()' - Lookup the hostname associated with the address. |
407 | | // |
408 | | |
409 | | char * // O - Host name |
410 | | httpAddrLookup( |
411 | | const http_addr_t *addr, // I - Address to lookup |
412 | | char *name, // I - Host name buffer |
413 | | size_t namelen) // I - Size of name buffer |
414 | 0 | { |
415 | 0 | _cups_globals_t *cg = _cupsGlobals(); |
416 | | // Global data |
417 | | |
418 | |
|
419 | 0 | DEBUG_printf("httpAddrLookup(addr=%p, name=%p, namelen=%u)", (void *)addr, (void *)name, (unsigned)namelen); |
420 | | |
421 | | // Range check input... |
422 | 0 | if (!addr || !name || namelen <= 2) |
423 | 0 | { |
424 | 0 | if (name && namelen >= 1) |
425 | 0 | *name = '\0'; |
426 | |
|
427 | 0 | return (NULL); |
428 | 0 | } |
429 | | |
430 | 0 | #ifdef AF_LOCAL |
431 | 0 | if (addr->addr.sa_family == AF_LOCAL) |
432 | 0 | { |
433 | 0 | cupsCopyString(name, addr->un.sun_path, (size_t)namelen); |
434 | 0 | return (name); |
435 | 0 | } |
436 | 0 | #endif // AF_LOCAL |
437 | | |
438 | | // Optimize lookups for localhost/loopback addresses... |
439 | 0 | if (httpAddrIsLocalhost(addr)) |
440 | 0 | { |
441 | 0 | cupsCopyString(name, "localhost", (size_t)namelen); |
442 | 0 | return (name); |
443 | 0 | } |
444 | | |
445 | 0 | #ifdef HAVE_RES_INIT |
446 | | // If the previous lookup failed, re-initialize the resolver to prevent |
447 | | // temporary network errors from persisting. This *should* be handled by |
448 | | // the resolver libraries, but apparently the glibc folks do not agree. |
449 | | // |
450 | | // We set a flag at the end of this function if we encounter an error that |
451 | | // requires reinitialization of the resolver functions. We then call |
452 | | // res_init() if the flag is set on the next call here or in httpAddrLookup(). |
453 | 0 | if (cg->need_res_init) |
454 | 0 | { |
455 | 0 | res_init(); |
456 | |
|
457 | 0 | cg->need_res_init = 0; |
458 | 0 | } |
459 | 0 | #endif // HAVE_RES_INIT |
460 | | |
461 | | // Fall back on httpAddrGetString if getnameinfo fails... |
462 | 0 | int error = getnameinfo(&addr->addr, (socklen_t)httpAddrGetLength(addr), name, (socklen_t)namelen, NULL, 0, 0); |
463 | |
|
464 | 0 | if (error) |
465 | 0 | { |
466 | 0 | if (error == EAI_FAIL) |
467 | 0 | cg->need_res_init = 1; |
468 | |
|
469 | 0 | return (httpAddrGetString(addr, name, namelen)); |
470 | 0 | } |
471 | | |
472 | 0 | DEBUG_printf("2httpAddrLookup: returning \"%s\"...", name); |
473 | |
|
474 | 0 | return (name); |
475 | 0 | } |
476 | | |
477 | | |
478 | | // |
479 | | // 'httpGetHostname()' - Get the FQDN for the connection or local system. |
480 | | // |
481 | | // When "http" points to a connected socket, return the hostname or address that |
482 | | // was used in the call to @link httpConnect@ or the address of the client for |
483 | | // the connection from @link httpAcceptConnection@. |
484 | | // |
485 | | // When "http" is `NULL`, return the FQDN for the local system. |
486 | | // |
487 | | |
488 | | const char * // O - FQDN for connection or system |
489 | | httpGetHostname(http_t *http, // I - HTTP connection or NULL |
490 | | char *s, // I - String buffer for name |
491 | | size_t slen) // I - Size of buffer |
492 | 0 | { |
493 | 0 | if (http) |
494 | 0 | { |
495 | | // Return the connection address... |
496 | 0 | if (!s || slen <= 1) |
497 | 0 | { |
498 | 0 | if (http->hostname[0] == '/') |
499 | 0 | return ("localhost"); |
500 | 0 | else |
501 | 0 | return (http->hostname); |
502 | 0 | } |
503 | 0 | else if (http->hostname[0] == '/') |
504 | 0 | { |
505 | 0 | cupsCopyString(s, "localhost", (size_t)slen); |
506 | 0 | } |
507 | 0 | else |
508 | 0 | { |
509 | 0 | cupsCopyString(s, http->hostname, (size_t)slen); |
510 | 0 | } |
511 | 0 | } |
512 | 0 | else |
513 | 0 | { |
514 | | // Return the hostname... |
515 | 0 | if (!s || slen <= 1) |
516 | 0 | return (NULL); |
517 | | |
518 | 0 | if (gethostname(s, (size_t)slen) < 0) |
519 | 0 | cupsCopyString(s, "localhost", (size_t)slen); |
520 | |
|
521 | 0 | DEBUG_printf("1httpGetHostname: gethostname() returned \"%s\".", s); |
522 | |
|
523 | 0 | if (!strchr(s, '.')) |
524 | 0 | { |
525 | | #ifdef HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME |
526 | | // The hostname is not a FQDN, so use the local hostname from the |
527 | | // SystemConfiguration framework... |
528 | | SCDynamicStoreRef sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("libcups"), NULL, NULL); |
529 | | // System configuration data |
530 | | CFStringRef local = sc ? SCDynamicStoreCopyLocalHostName(sc) : NULL; |
531 | | // Local host name |
532 | | char localStr[1024]; // Local host name C string |
533 | | |
534 | | if (local && CFStringGetCString(local, localStr, sizeof(localStr), kCFStringEncodingUTF8)) |
535 | | { |
536 | | // Append ".local." to the hostname we get... |
537 | | snprintf(s, (size_t)slen, "%s.local.", localStr); |
538 | | DEBUG_printf("1httpGetHostname: SCDynamicStoreCopyLocalHostName() returned \"%s\".", s); |
539 | | } |
540 | | |
541 | | if (local) |
542 | | CFRelease(local); |
543 | | if (sc) |
544 | | CFRelease(sc); |
545 | | |
546 | | #else |
547 | | // The hostname is not a FQDN, so look it up... |
548 | 0 | struct hostent *host; // Host entry to get FQDN |
549 | |
|
550 | 0 | if ((host = gethostbyname(s)) != NULL && host->h_name) |
551 | 0 | { |
552 | | // Use the resolved hostname... |
553 | 0 | cupsCopyString(s, host->h_name, (size_t)slen); |
554 | 0 | DEBUG_printf("1httpGetHostname: gethostbyname() returned \"%s\".", s); |
555 | 0 | } |
556 | 0 | #endif // HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME |
557 | 0 | } |
558 | | |
559 | | // Make sure .local hostnames end with a period... |
560 | 0 | if (strlen(s) > 6 && !strcmp(s + strlen(s) - 6, ".local")) |
561 | 0 | cupsConcatString(s, ".", (size_t)slen); |
562 | 0 | } |
563 | | |
564 | | // Convert the hostname to lowercase as needed... |
565 | 0 | if (s[0] != '/') |
566 | 0 | { |
567 | 0 | char *ptr; // Pointer into string |
568 | |
|
569 | 0 | for (ptr = s; *ptr; ptr ++) |
570 | 0 | *ptr = (char)_cups_tolower((int)*ptr); |
571 | 0 | } |
572 | | |
573 | | // Return the hostname with as much domain info as we have... |
574 | 0 | return (s); |
575 | 0 | } |
576 | | |
577 | | |
578 | | // |
579 | | // 'httpResolveHostname()' - Resolve the hostname of the HTTP connection |
580 | | // address. |
581 | | // |
582 | | |
583 | | const char * // O - Resolved hostname or `NULL` |
584 | | httpResolveHostname(http_t *http, // I - HTTP connection |
585 | | char *buffer, // I - Hostname buffer or `NULL` to use HTTP buffer |
586 | | size_t bufsize) // I - Size of buffer |
587 | 0 | { |
588 | 0 | if (!http) |
589 | 0 | return (NULL); |
590 | | |
591 | 0 | if (isdigit(http->hostname[0] & 255) || http->hostname[0] == '[') |
592 | 0 | { |
593 | 0 | char temp[1024]; // Temporary string |
594 | |
|
595 | 0 | if (httpAddrLookup(http->hostaddr, temp, sizeof(temp))) |
596 | 0 | cupsCopyString(http->hostname, temp, sizeof(http->hostname)); |
597 | 0 | else |
598 | 0 | return (NULL); |
599 | 0 | } |
600 | | |
601 | 0 | if (buffer) |
602 | 0 | { |
603 | 0 | if (http->hostname[0] == '/') |
604 | 0 | cupsCopyString(buffer, "localhost", bufsize); |
605 | 0 | else |
606 | 0 | cupsCopyString(buffer, http->hostname, bufsize); |
607 | |
|
608 | 0 | return (buffer); |
609 | 0 | } |
610 | 0 | else if (http->hostname[0] == '/') |
611 | 0 | { |
612 | 0 | return ("localhost"); |
613 | 0 | } |
614 | 0 | else |
615 | 0 | { |
616 | 0 | return (http->hostname); |
617 | 0 | } |
618 | 0 | } |
619 | | |
620 | | |
621 | | // |
622 | | // 'httpAddrSetPort()' - Set the port number associated with an address. |
623 | | // |
624 | | |
625 | | void |
626 | | httpAddrSetPort(http_addr_t *addr, // I - Address |
627 | | int port) // I - Port |
628 | 0 | { |
629 | 0 | if (!addr || port <= 0) |
630 | 0 | return; |
631 | | |
632 | 0 | #ifdef AF_INET6 |
633 | 0 | if (addr->addr.sa_family == AF_INET6) |
634 | 0 | addr->ipv6.sin6_port = htons(port); |
635 | 0 | else |
636 | 0 | #endif // AF_INET6 |
637 | 0 | if (addr->addr.sa_family == AF_INET) |
638 | 0 | addr->ipv4.sin_port = htons(port); |
639 | 0 | } |