/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 | status = bind(fd, (struct sockaddr *)addr, (socklen_t)httpAddrGetLength(addr)); |
353 | | |
354 | | // Restore the umask and fix permissions... |
355 | 0 | umask(mask); |
356 | 0 | } |
357 | 0 | } |
358 | 0 | else |
359 | 0 | #endif // AF_LOCAL |
360 | 0 | { |
361 | 0 | httpAddrSetPort(addr, port); |
362 | |
|
363 | 0 | status = bind(fd, (struct sockaddr *)addr, (socklen_t)httpAddrGetLength(addr)); |
364 | 0 | } |
365 | |
|
366 | 0 | if (status) |
367 | 0 | { |
368 | 0 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), false); |
369 | |
|
370 | 0 | close(fd); |
371 | |
|
372 | 0 | return (-1); |
373 | 0 | } |
374 | | |
375 | | // Listen... |
376 | 0 | if (listen(fd, INT_MAX)) |
377 | 0 | { |
378 | 0 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), false); |
379 | |
|
380 | 0 | close(fd); |
381 | |
|
382 | 0 | return (-1); |
383 | 0 | } |
384 | | |
385 | | // Close on exec... |
386 | 0 | #ifndef _WIN32 |
387 | 0 | if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC)) |
388 | 0 | DEBUG_printf("2httpAddrListen: fcntl(F_SETFD, FD_CLOEXEC) failed: %s", strerror(errno)); |
389 | 0 | #endif // !_WIN32 |
390 | |
|
391 | | #ifdef SO_NOSIGPIPE |
392 | | // Disable SIGPIPE for this socket. |
393 | | val = 1; |
394 | | if (setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val))) |
395 | | DEBUG_printf("2httpAddrListen: setsockopt(SO_NOSIGPIPE) failed: %s", strerror(errno)); |
396 | | #endif // SO_NOSIGPIPE |
397 | |
|
398 | 0 | return (fd); |
399 | 0 | } |
400 | | |
401 | | |
402 | | // |
403 | | // 'httpAddrLookup()' - Lookup the hostname associated with the address. |
404 | | // |
405 | | |
406 | | char * // O - Host name |
407 | | httpAddrLookup( |
408 | | const http_addr_t *addr, // I - Address to lookup |
409 | | char *name, // I - Host name buffer |
410 | | size_t namelen) // I - Size of name buffer |
411 | 0 | { |
412 | 0 | _cups_globals_t *cg = _cupsGlobals(); |
413 | | // Global data |
414 | | |
415 | |
|
416 | 0 | DEBUG_printf("httpAddrLookup(addr=%p, name=%p, namelen=%u)", (void *)addr, (void *)name, (unsigned)namelen); |
417 | | |
418 | | // Range check input... |
419 | 0 | if (!addr || !name || namelen <= 2) |
420 | 0 | { |
421 | 0 | if (name && namelen >= 1) |
422 | 0 | *name = '\0'; |
423 | |
|
424 | 0 | return (NULL); |
425 | 0 | } |
426 | | |
427 | 0 | #ifdef AF_LOCAL |
428 | 0 | if (addr->addr.sa_family == AF_LOCAL) |
429 | 0 | { |
430 | 0 | cupsCopyString(name, addr->un.sun_path, (size_t)namelen); |
431 | 0 | return (name); |
432 | 0 | } |
433 | 0 | #endif // AF_LOCAL |
434 | | |
435 | | // Optimize lookups for localhost/loopback addresses... |
436 | 0 | if (httpAddrIsLocalhost(addr)) |
437 | 0 | { |
438 | 0 | cupsCopyString(name, "localhost", (size_t)namelen); |
439 | 0 | return (name); |
440 | 0 | } |
441 | | |
442 | 0 | #ifdef HAVE_RES_INIT |
443 | | // If the previous lookup failed, re-initialize the resolver to prevent |
444 | | // temporary network errors from persisting. This *should* be handled by |
445 | | // the resolver libraries, but apparently the glibc folks do not agree. |
446 | | // |
447 | | // We set a flag at the end of this function if we encounter an error that |
448 | | // requires reinitialization of the resolver functions. We then call |
449 | | // res_init() if the flag is set on the next call here or in httpAddrLookup(). |
450 | 0 | if (cg->need_res_init) |
451 | 0 | { |
452 | 0 | res_init(); |
453 | |
|
454 | 0 | cg->need_res_init = 0; |
455 | 0 | } |
456 | 0 | #endif // HAVE_RES_INIT |
457 | | |
458 | | // Fall back on httpAddrGetString if getnameinfo fails... |
459 | 0 | int error = getnameinfo(&addr->addr, (socklen_t)httpAddrGetLength(addr), name, (socklen_t)namelen, NULL, 0, 0); |
460 | |
|
461 | 0 | if (error) |
462 | 0 | { |
463 | 0 | if (error == EAI_FAIL) |
464 | 0 | cg->need_res_init = 1; |
465 | |
|
466 | 0 | return (httpAddrGetString(addr, name, namelen)); |
467 | 0 | } |
468 | | |
469 | 0 | DEBUG_printf("2httpAddrLookup: returning \"%s\"...", name); |
470 | |
|
471 | 0 | return (name); |
472 | 0 | } |
473 | | |
474 | | |
475 | | // |
476 | | // 'httpGetHostname()' - Get the FQDN for the connection or local system. |
477 | | // |
478 | | // When "http" points to a connected socket, return the hostname or address that |
479 | | // was used in the call to @link httpConnect@ or the address of the client for |
480 | | // the connection from @link httpAcceptConnection@. |
481 | | // |
482 | | // When "http" is `NULL`, return the FQDN for the local system. |
483 | | // |
484 | | |
485 | | const char * // O - FQDN for connection or system |
486 | | httpGetHostname(http_t *http, // I - HTTP connection or NULL |
487 | | char *s, // I - String buffer for name |
488 | | size_t slen) // I - Size of buffer |
489 | 0 | { |
490 | 0 | if (http) |
491 | 0 | { |
492 | | // Return the connection address... |
493 | 0 | if (!s || slen <= 1) |
494 | 0 | { |
495 | 0 | if (http->hostname[0] == '/') |
496 | 0 | return ("localhost"); |
497 | 0 | else |
498 | 0 | return (http->hostname); |
499 | 0 | } |
500 | 0 | else if (http->hostname[0] == '/') |
501 | 0 | cupsCopyString(s, "localhost", (size_t)slen); |
502 | 0 | else |
503 | 0 | cupsCopyString(s, http->hostname, (size_t)slen); |
504 | 0 | } |
505 | 0 | else |
506 | 0 | { |
507 | | // Return the hostname... |
508 | 0 | if (!s || slen <= 1) |
509 | 0 | return (NULL); |
510 | | |
511 | 0 | if (gethostname(s, (size_t)slen) < 0) |
512 | 0 | cupsCopyString(s, "localhost", (size_t)slen); |
513 | |
|
514 | 0 | if (!strchr(s, '.')) |
515 | 0 | { |
516 | | #ifdef HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME |
517 | | // The hostname is not a FQDN, so use the local hostname from the |
518 | | // SystemConfiguration framework... |
519 | | SCDynamicStoreRef sc = SCDynamicStoreCreate(kCFAllocatorDefault, |
520 | | CFSTR("libcups"), NULL, NULL); |
521 | | // System configuration data |
522 | | CFStringRef local = sc ? SCDynamicStoreCopyLocalHostName(sc) : NULL; |
523 | | // Local host name |
524 | | char localStr[1024]; // Local host name C string |
525 | | |
526 | | if (local && CFStringGetCString(local, localStr, sizeof(localStr), |
527 | | kCFStringEncodingUTF8)) |
528 | | { |
529 | | // Append ".local." to the hostname we get... |
530 | | snprintf(s, (size_t)slen, "%s.local.", localStr); |
531 | | } |
532 | | |
533 | | if (local) |
534 | | CFRelease(local); |
535 | | if (sc) |
536 | | CFRelease(sc); |
537 | | |
538 | | #else |
539 | | // The hostname is not a FQDN, so look it up... |
540 | 0 | struct hostent *host; // Host entry to get FQDN |
541 | |
|
542 | 0 | if ((host = gethostbyname(s)) != NULL && host->h_name) |
543 | 0 | { |
544 | | // Use the resolved hostname... |
545 | 0 | cupsCopyString(s, host->h_name, (size_t)slen); |
546 | 0 | } |
547 | 0 | #endif // HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME |
548 | 0 | } |
549 | | |
550 | | // Make sure .local hostnames end with a period... |
551 | 0 | if (strlen(s) > 6 && !strcmp(s + strlen(s) - 6, ".local")) |
552 | 0 | cupsConcatString(s, ".", (size_t)slen); |
553 | 0 | } |
554 | | |
555 | | // Convert the hostname to lowercase as needed... |
556 | 0 | if (s[0] != '/') |
557 | 0 | { |
558 | 0 | char *ptr; // Pointer into string |
559 | |
|
560 | 0 | for (ptr = s; *ptr; ptr ++) |
561 | 0 | *ptr = (char)_cups_tolower((int)*ptr); |
562 | 0 | } |
563 | | |
564 | | // Return the hostname with as much domain info as we have... |
565 | 0 | return (s); |
566 | 0 | } |
567 | | |
568 | | |
569 | | // |
570 | | // 'httpResolveHostname()' - Resolve the hostname of the HTTP connection |
571 | | // address. |
572 | | // |
573 | | |
574 | | const char * // O - Resolved hostname or `NULL` |
575 | | httpResolveHostname(http_t *http, // I - HTTP connection |
576 | | char *buffer, // I - Hostname buffer |
577 | | size_t bufsize) // I - Size of buffer |
578 | 0 | { |
579 | 0 | if (!http) |
580 | 0 | return (NULL); |
581 | | |
582 | 0 | if (isdigit(http->hostname[0] & 255) || http->hostname[0] == '[') |
583 | 0 | { |
584 | 0 | char temp[1024]; // Temporary string |
585 | |
|
586 | 0 | if (httpAddrLookup(http->hostaddr, temp, sizeof(temp))) |
587 | 0 | cupsCopyString(http->hostname, temp, sizeof(http->hostname)); |
588 | 0 | else |
589 | 0 | return (NULL); |
590 | 0 | } |
591 | | |
592 | 0 | if (buffer) |
593 | 0 | { |
594 | 0 | if (http->hostname[0] == '/') |
595 | 0 | cupsCopyString(buffer, "localhost", bufsize); |
596 | 0 | else |
597 | 0 | cupsCopyString(buffer, http->hostname, bufsize); |
598 | |
|
599 | 0 | return (buffer); |
600 | 0 | } |
601 | 0 | else if (http->hostname[0] == '/') |
602 | 0 | return ("localhost"); |
603 | 0 | else |
604 | 0 | return (http->hostname); |
605 | 0 | } |
606 | | |
607 | | |
608 | | // |
609 | | // 'httpAddrSetPort()' - Set the port number associated with an address. |
610 | | // |
611 | | |
612 | | void |
613 | | httpAddrSetPort(http_addr_t *addr, // I - Address |
614 | | int port) // I - Port |
615 | 0 | { |
616 | 0 | if (!addr || port <= 0) |
617 | 0 | return; |
618 | | |
619 | 0 | #ifdef AF_INET6 |
620 | 0 | if (addr->addr.sa_family == AF_INET6) |
621 | 0 | addr->ipv6.sin6_port = htons(port); |
622 | 0 | else |
623 | 0 | #endif // AF_INET6 |
624 | 0 | if (addr->addr.sa_family == AF_INET) |
625 | 0 | addr->ipv4.sin_port = htons(port); |
626 | 0 | } |