xref: /PHP-8.3/main/network.c (revision d65c8003)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Author: Stig Venaas <venaas@uninett.no>                              |
14    | Streams work by Wez Furlong <wez@thebrainroom.com>                   |
15    +----------------------------------------------------------------------+
16  */
17 
18 /*#define DEBUG_MAIN_NETWORK 1*/
19 
20 #include "php.h"
21 
22 #include <stddef.h>
23 #include <errno.h>
24 
25 
26 #ifdef PHP_WIN32
27 # include <Ws2tcpip.h>
28 # include "win32/inet.h"
29 # include "win32/winutil.h"
30 # define O_RDONLY _O_RDONLY
31 # include "win32/param.h"
32 #else
33 #include <sys/param.h>
34 #endif
35 
36 #include <sys/types.h>
37 #if HAVE_SYS_SOCKET_H
38 #include <sys/socket.h>
39 #endif
40 
41 #ifndef _FCNTL_H
42 #include <fcntl.h>
43 #endif
44 
45 #ifdef HAVE_SYS_SELECT_H
46 #include <sys/select.h>
47 #endif
48 #if HAVE_POLL_H
49 #include <poll.h>
50 #elif HAVE_SYS_POLL_H
51 #include <sys/poll.h>
52 #endif
53 
54 
55 #ifndef PHP_WIN32
56 #include <netinet/in.h>
57 #include <netdb.h>
58 #if HAVE_ARPA_INET_H
59 #include <arpa/inet.h>
60 #endif
61 #endif
62 
63 #ifndef HAVE_INET_ATON
64 int inet_aton(const char *, struct in_addr *);
65 #endif
66 
67 #include "php_network.h"
68 
69 #if defined(PHP_WIN32) || defined(__riscos__)
70 #undef AF_UNIX
71 #endif
72 
73 #if defined(AF_UNIX)
74 #include <sys/un.h>
75 #endif
76 
77 #include "ext/standard/file.h"
78 
79 #ifdef PHP_WIN32
80 # include "win32/time.h"
81 # define SOCK_ERR INVALID_SOCKET
82 # define SOCK_CONN_ERR SOCKET_ERROR
83 # define PHP_TIMEOUT_ERROR_VALUE		WSAETIMEDOUT
84 
85 #if HAVE_IPV6
86 const struct in6_addr in6addr_any = {0}; /* IN6ADDR_ANY_INIT; */
87 #endif
88 
89 #else
90 # define SOCK_ERR -1
91 # define SOCK_CONN_ERR -1
92 # define PHP_TIMEOUT_ERROR_VALUE		ETIMEDOUT
93 #endif
94 
95 #if HAVE_GETADDRINFO
96 #ifdef HAVE_GAI_STRERROR
97 #  define PHP_GAI_STRERROR(x) (gai_strerror(x))
98 #else
99 #  define PHP_GAI_STRERROR(x) (php_gai_strerror(x))
100 /* {{{ php_gai_strerror */
php_gai_strerror(int code)101 static const char *php_gai_strerror(int code)
102 {
103 	static struct {
104 		int code;
105 		const char *msg;
106 	} values[] = {
107 #  ifdef EAI_ADDRFAMILY
108 		{EAI_ADDRFAMILY, "Address family for hostname not supported"},
109 #  endif
110 		{EAI_AGAIN, "Temporary failure in name resolution"},
111 		{EAI_BADFLAGS, "Bad value for ai_flags"},
112 		{EAI_FAIL, "Non-recoverable failure in name resolution"},
113 		{EAI_FAMILY, "ai_family not supported"},
114 		{EAI_MEMORY, "Memory allocation failure"},
115 #  ifdef EAI_NODATA
116 		{EAI_NODATA, "No address associated with hostname"},
117 #  endif
118 		{EAI_NONAME, "Name or service not known"},
119 		{EAI_SERVICE, "Servname not supported for ai_socktype"},
120 		{EAI_SOCKTYPE, "ai_socktype not supported"},
121 		{EAI_SYSTEM, "System error"},
122 		{0, NULL}
123 	};
124 	int i;
125 
126 	for (i = 0; values[i].msg != NULL; i++) {
127 		if (values[i].code == code) {
128 			return (char *)values[i].msg;
129 		}
130 	}
131 
132 	return "Unknown error";
133 }
134 /* }}} */
135 #endif
136 #endif
137 
138 /* {{{ php_network_freeaddresses */
php_network_freeaddresses(struct sockaddr ** sal)139 PHPAPI void php_network_freeaddresses(struct sockaddr **sal)
140 {
141 	struct sockaddr **sap;
142 
143 	if (sal == NULL)
144 		return;
145 	for (sap = sal; *sap != NULL; sap++)
146 		efree(*sap);
147 	efree(sal);
148 }
149 /* }}} */
150 
151 /* {{{ php_network_getaddresses
152  * Returns number of addresses, 0 for none/error
153  */
php_network_getaddresses(const char * host,int socktype,struct sockaddr *** sal,zend_string ** error_string)154 PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, zend_string **error_string)
155 {
156 	struct sockaddr **sap;
157 	int n;
158 #if HAVE_GETADDRINFO
159 # if HAVE_IPV6
160 	static int ipv6_borked = -1; /* the way this is used *is* thread safe */
161 # endif
162 	struct addrinfo hints, *res, *sai;
163 #else
164 	struct hostent *host_info;
165 	struct in_addr in;
166 #endif
167 
168 	if (host == NULL) {
169 		return 0;
170 	}
171 #if HAVE_GETADDRINFO
172 	memset(&hints, '\0', sizeof(hints));
173 
174 	hints.ai_family = AF_INET; /* default to regular inet (see below) */
175 	hints.ai_socktype = socktype;
176 
177 # if HAVE_IPV6
178 	/* probe for a working IPv6 stack; even if detected as having v6 at compile
179 	 * time, at runtime some stacks are slow to resolve or have other issues
180 	 * if they are not correctly configured.
181 	 * static variable use is safe here since simple store or fetch operations
182 	 * are atomic and because the actual probe process is not in danger of
183 	 * collisions or race conditions. */
184 	if (ipv6_borked == -1) {
185 		int s;
186 
187 		s = socket(PF_INET6, SOCK_DGRAM, 0);
188 		if (s == SOCK_ERR) {
189 			ipv6_borked = 1;
190 		} else {
191 			ipv6_borked = 0;
192 			closesocket(s);
193 		}
194 	}
195 	hints.ai_family = ipv6_borked ? AF_INET : AF_UNSPEC;
196 # endif
197 
198 	if ((n = getaddrinfo(host, NULL, &hints, &res))) {
199 		if (error_string) {
200 			/* free error string received during previous iteration (if any) */
201 			if (*error_string) {
202 				zend_string_release_ex(*error_string, 0);
203 			}
204 			*error_string = strpprintf(0, "php_network_getaddresses: getaddrinfo for %s failed: %s", host, PHP_GAI_STRERROR(n));
205 			php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string));
206 		} else {
207 			php_error_docref(NULL, E_WARNING, "php_network_getaddresses: getaddrinfo for %s failed: %s", host, PHP_GAI_STRERROR(n));
208 		}
209 		return 0;
210 	} else if (res == NULL) {
211 		if (error_string) {
212 			/* free error string received during previous iteration (if any) */
213 			if (*error_string) {
214 				zend_string_release_ex(*error_string, 0);
215 			}
216 			*error_string = strpprintf(0, "php_network_getaddresses: getaddrinfo for %s failed (null result pointer) errno=%d", host, errno);
217 			php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string));
218 		} else {
219 			php_error_docref(NULL, E_WARNING, "php_network_getaddresses: getaddrinfo for %s failed (null result pointer)", host);
220 		}
221 		return 0;
222 	}
223 
224 	sai = res;
225 	for (n = 1; (sai = sai->ai_next) != NULL; n++)
226 		;
227 
228 	*sal = safe_emalloc((n + 1), sizeof(*sal), 0);
229 	sai = res;
230 	sap = *sal;
231 
232 	do {
233 		*sap = emalloc(sai->ai_addrlen);
234 		memcpy(*sap, sai->ai_addr, sai->ai_addrlen);
235 		sap++;
236 	} while ((sai = sai->ai_next) != NULL);
237 
238 	freeaddrinfo(res);
239 #else
240 #ifdef HAVE_INET_PTON
241 	if (!inet_pton(AF_INET, host, &in)) {
242 #else
243 	if (!inet_aton(host, &in)) {
244 #endif
245 		if(strlen(host) > MAXFQDNLEN) {
246 			host_info = NULL;
247 			errno = E2BIG;
248 		} else {
249 			host_info = php_network_gethostbyname(host);
250 		}
251 		if (host_info == NULL) {
252 			if (error_string) {
253 				/* free error string received during previous iteration (if any) */
254 				if (*error_string) {
255 					zend_string_release_ex(*error_string, 0);
256 				}
257 				*error_string = strpprintf(0, "php_network_getaddresses: gethostbyname failed. errno=%d", errno);
258 				php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string));
259 			} else {
260 				php_error_docref(NULL, E_WARNING, "php_network_getaddresses: gethostbyname failed");
261 			}
262 			return 0;
263 		}
264 		in = *((struct in_addr *) host_info->h_addr);
265 	}
266 
267 	*sal = safe_emalloc(2, sizeof(*sal), 0);
268 	sap = *sal;
269 	*sap = emalloc(sizeof(struct sockaddr_in));
270 	(*sap)->sa_family = AF_INET;
271 	((struct sockaddr_in *)*sap)->sin_addr = in;
272 	sap++;
273 	n = 1;
274 #endif
275 
276 	*sap = NULL;
277 	return n;
278 }
279 /* }}} */
280 
281 #ifndef O_NONBLOCK
282 #define O_NONBLOCK O_NDELAY
283 #endif
284 
285 #ifdef PHP_WIN32
286 typedef u_long php_non_blocking_flags_t;
287 #  define SET_SOCKET_BLOCKING_MODE(sock, save) \
288 	save = TRUE; ioctlsocket(sock, FIONBIO, &save)
289 #  define RESTORE_SOCKET_BLOCKING_MODE(sock, save) \
290 	ioctlsocket(sock, FIONBIO, &save)
291 #else
292 typedef int php_non_blocking_flags_t;
293 #  define SET_SOCKET_BLOCKING_MODE(sock, save) \
294 	 save = fcntl(sock, F_GETFL, 0); \
295 	 fcntl(sock, F_SETFL, save | O_NONBLOCK)
296 #  define RESTORE_SOCKET_BLOCKING_MODE(sock, save) \
297 	 fcntl(sock, F_SETFL, save)
298 #endif
299 
300 /* Connect to a socket using an interruptible connect with optional timeout.
301  * Optionally, the connect can be made asynchronously, which will implicitly
302  * enable non-blocking mode on the socket.
303  * */
304 /* {{{ php_network_connect_socket */
305 PHPAPI int php_network_connect_socket(php_socket_t sockfd,
306 		const struct sockaddr *addr,
307 		socklen_t addrlen,
308 		int asynchronous,
309 		struct timeval *timeout,
310 		zend_string **error_string,
311 		int *error_code)
312 {
313 	php_non_blocking_flags_t orig_flags;
314 	int n;
315 	int error = 0;
316 	socklen_t len;
317 	int ret = 0;
318 
319 	SET_SOCKET_BLOCKING_MODE(sockfd, orig_flags);
320 
321 	if ((n = connect(sockfd, addr, addrlen)) != 0) {
322 		error = php_socket_errno();
323 
324 		if (error_code) {
325 			*error_code = error;
326 		}
327 
328 		if (error != EINPROGRESS) {
329 			if (error_string) {
330 				*error_string = php_socket_error_str(error);
331 			}
332 
333 			return -1;
334 		}
335 		if (asynchronous && error == EINPROGRESS) {
336 			/* this is fine by us */
337 			return 0;
338 		}
339 	}
340 
341 	if (n == 0) {
342 		goto ok;
343 	}
344 # ifdef PHP_WIN32
345 	/* The documentation for connect() says in case of non-blocking connections
346 	 * the select function reports success in the writefds set and failure in
347 	 * the exceptfds set. Indeed, using PHP_POLLREADABLE results in select
348 	 * failing only due to the timeout and not immediately as would be
349 	 * expected when a connection is actively refused. This way,
350 	 * php_pollfd_for will return a mask with POLLOUT if the connection
351 	 * is successful and with POLLPRI otherwise. */
352 	if ((n = php_pollfd_for(sockfd, POLLOUT|POLLPRI, timeout)) == 0) {
353 #else
354 	if ((n = php_pollfd_for(sockfd, PHP_POLLREADABLE|POLLOUT, timeout)) == 0) {
355 #endif
356 		error = PHP_TIMEOUT_ERROR_VALUE;
357 	}
358 
359 	if (n > 0) {
360 		len = sizeof(error);
361 		/*
362 		   BSD-derived systems set errno correctly
363 		   Solaris returns -1 from getsockopt in case of error
364 		   */
365 		if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char*)&error, &len) != 0) {
366 			ret = -1;
367 		}
368 	} else {
369 		/* whoops: sockfd has disappeared */
370 		ret = -1;
371 	}
372 
373 ok:
374 	if (!asynchronous) {
375 		/* back to blocking mode */
376 		RESTORE_SOCKET_BLOCKING_MODE(sockfd, orig_flags);
377 	}
378 
379 	if (error_code) {
380 		*error_code = error;
381 	}
382 
383 	if (error) {
384 		ret = -1;
385 		if (error_string) {
386 			*error_string = php_socket_error_str(error);
387 		}
388 	}
389 	return ret;
390 }
391 /* }}} */
392 
393 /* {{{ sub_times */
394 static inline void sub_times(struct timeval a, struct timeval b, struct timeval *result)
395 {
396 	result->tv_usec = a.tv_usec - b.tv_usec;
397 	if (result->tv_usec < 0L) {
398 		a.tv_sec--;
399 		result->tv_usec += 1000000L;
400 	}
401 	result->tv_sec = a.tv_sec - b.tv_sec;
402 	if (result->tv_sec < 0L) {
403 		result->tv_sec++;
404 		result->tv_usec -= 1000000L;
405 	}
406 }
407 /* }}} */
408 
409 /* Bind to a local IP address.
410  * Returns the bound socket, or -1 on failure.
411  * */
412 /* {{{ php_network_bind_socket_to_local_addr */
413 php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port,
414 		int socktype, long sockopts, zend_string **error_string, int *error_code
415 		)
416 {
417 	int num_addrs, n, err = 0;
418 	php_socket_t sock;
419 	struct sockaddr **sal, **psal, *sa;
420 	socklen_t socklen;
421 	int sockoptval = 1;
422 
423 	num_addrs = php_network_getaddresses(host, socktype, &psal, error_string);
424 
425 	if (num_addrs == 0) {
426 		/* could not resolve address(es) */
427 		return -1;
428 	}
429 
430 	for (sal = psal; *sal != NULL; sal++) {
431 		sa = *sal;
432 
433 		switch (sa->sa_family) {
434 #if HAVE_GETADDRINFO && HAVE_IPV6
435 			case AF_INET6:
436 				((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
437 				socklen = sizeof(struct sockaddr_in6);
438 				break;
439 #endif
440 			case AF_INET:
441 				((struct sockaddr_in *)sa)->sin_port = htons(port);
442 				socklen = sizeof(struct sockaddr_in);
443 				break;
444 			default:
445 				/* Unsupported family, skip to the next */
446 				continue;
447 		}
448 
449 		/* create a socket for this address */
450 		sock = socket(sa->sa_family, socktype, 0);
451 
452 		if (sock == SOCK_ERR) {
453 			continue;
454 		}
455 
456 		/* attempt to bind */
457 
458 #ifdef SO_REUSEADDR
459 		setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&sockoptval, sizeof(sockoptval));
460 #endif
461 #ifdef IPV6_V6ONLY
462 		if (sockopts & STREAM_SOCKOP_IPV6_V6ONLY) {
463 			int ipv6_val = !!(sockopts & STREAM_SOCKOP_IPV6_V6ONLY_ENABLED);
464 			setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6_val, sizeof(sockoptval));
465 		}
466 #endif
467 #ifdef SO_REUSEPORT
468 		if (sockopts & STREAM_SOCKOP_SO_REUSEPORT) {
469 			setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char*)&sockoptval, sizeof(sockoptval));
470 		}
471 #endif
472 #ifdef SO_BROADCAST
473 		if (sockopts & STREAM_SOCKOP_SO_BROADCAST) {
474 			setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&sockoptval, sizeof(sockoptval));
475 		}
476 #endif
477 #ifdef TCP_NODELAY
478 		if (sockopts & STREAM_SOCKOP_TCP_NODELAY) {
479 			setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&sockoptval, sizeof(sockoptval));
480 		}
481 #endif
482 
483 		n = bind(sock, sa, socklen);
484 
485 		if (n != SOCK_CONN_ERR) {
486 			goto bound;
487 		}
488 
489 		err = php_socket_errno();
490 
491 		closesocket(sock);
492 	}
493 	sock = -1;
494 
495 	if (error_code) {
496 		*error_code = err;
497 	}
498 	if (error_string) {
499 		*error_string = php_socket_error_str(err);
500 	}
501 
502 bound:
503 
504 	php_network_freeaddresses(psal);
505 
506 	return sock;
507 
508 }
509 /* }}} */
510 
511 PHPAPI int php_network_parse_network_address_with_port(const char *addr, zend_long addrlen, struct sockaddr *sa, socklen_t *sl)
512 {
513 	char *colon;
514 	char *tmp;
515 	int ret = FAILURE;
516 	short port;
517 	struct sockaddr_in *in4 = (struct sockaddr_in*)sa;
518 	struct sockaddr **psal;
519 	int n;
520 	zend_string *errstr = NULL;
521 #if HAVE_IPV6
522 	struct sockaddr_in6 *in6 = (struct sockaddr_in6*)sa;
523 
524 	memset(in6, 0, sizeof(struct sockaddr_in6));
525 #else
526 	memset(in4, 0, sizeof(struct sockaddr_in));
527 #endif
528 
529 	if (*addr == '[') {
530 		colon = memchr(addr + 1, ']', addrlen-1);
531 		if (!colon || colon[1] != ':') {
532 			return FAILURE;
533 		}
534 		port = atoi(colon + 2);
535 		addr++;
536 	} else {
537 		colon = memchr(addr, ':', addrlen);
538 		if (!colon) {
539 			return FAILURE;
540 		}
541 		port = atoi(colon + 1);
542 	}
543 
544 	tmp = estrndup(addr, colon - addr);
545 
546 	/* first, try interpreting the address as a numeric address */
547 
548 #if HAVE_IPV6 && HAVE_INET_PTON
549 	if (inet_pton(AF_INET6, tmp, &in6->sin6_addr) > 0) {
550 		in6->sin6_port = htons(port);
551 		in6->sin6_family = AF_INET6;
552 		*sl = sizeof(struct sockaddr_in6);
553 		ret = SUCCESS;
554 		goto out;
555 	}
556 #endif
557 #ifdef HAVE_INET_PTON
558 	if (inet_pton(AF_INET, tmp, &in4->sin_addr) > 0) {
559 #else
560 	if (inet_aton(tmp, &in4->sin_addr) > 0) {
561 #endif
562 		in4->sin_port = htons(port);
563 		in4->sin_family = AF_INET;
564 		*sl = sizeof(struct sockaddr_in);
565 		ret = SUCCESS;
566 		goto out;
567 	}
568 
569 	/* looks like we'll need to resolve it */
570 	n = php_network_getaddresses(tmp, SOCK_DGRAM, &psal, &errstr);
571 
572 	if (n == 0) {
573 		if (errstr) {
574 			php_error_docref(NULL, E_WARNING, "Failed to resolve `%s': %s", tmp, ZSTR_VAL(errstr));
575 			zend_string_release_ex(errstr, 0);
576 		}
577 		goto out;
578 	}
579 
580 	/* copy the details from the first item */
581 	switch ((*psal)->sa_family) {
582 #if HAVE_GETADDRINFO && HAVE_IPV6
583 		case AF_INET6:
584 			*in6 = **(struct sockaddr_in6**)psal;
585 			in6->sin6_port = htons(port);
586 			*sl = sizeof(struct sockaddr_in6);
587 			ret = SUCCESS;
588 			break;
589 #endif
590 		case AF_INET:
591 			*in4 = **(struct sockaddr_in**)psal;
592 			in4->sin_port = htons(port);
593 			*sl = sizeof(struct sockaddr_in);
594 			ret = SUCCESS;
595 			break;
596 	}
597 
598 	php_network_freeaddresses(psal);
599 
600 out:
601 	efree(tmp);
602 	return ret;
603 }
604 
605 
606 PHPAPI void php_network_populate_name_from_sockaddr(
607 		/* input address */
608 		struct sockaddr *sa, socklen_t sl,
609 		/* output readable address */
610 		zend_string **textaddr,
611 		/* output address */
612 		struct sockaddr **addr,
613 		socklen_t *addrlen
614 		)
615 {
616 	if (addr) {
617 		*addr = emalloc(sl);
618 		memcpy(*addr, sa, sl);
619 		*addrlen = sl;
620 	}
621 
622 	if (textaddr) {
623 #ifdef HAVE_INET_NTOP
624 		char abuf[256];
625 #endif
626 		const char *buf = NULL;
627 
628 		switch (sa->sa_family) {
629 			case AF_INET:
630 				/* generally not thread safe, but it *is* thread safe under win32 */
631 #ifdef HAVE_INET_NTOP
632 				buf = inet_ntop(AF_INET, &((struct sockaddr_in*)sa)->sin_addr, (char *)&abuf, sizeof(abuf));
633 #else
634 				buf = inet_ntoa(((struct sockaddr_in*)sa)->sin_addr);
635 #endif
636 				if (buf) {
637 					*textaddr = strpprintf(0, "%s:%d",
638 						buf, ntohs(((struct sockaddr_in*)sa)->sin_port));
639 				}
640 
641 				break;
642 
643 #if HAVE_IPV6 && HAVE_INET_NTOP
644 			case AF_INET6:
645 				buf = (char*)inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, (char *)&abuf, sizeof(abuf));
646 				if (buf) {
647 					*textaddr = strpprintf(0, "[%s]:%d",
648 						buf, ntohs(((struct sockaddr_in6*)sa)->sin6_port));
649 				}
650 
651 				break;
652 #endif
653 #ifdef AF_UNIX
654 			case AF_UNIX:
655 				{
656 					struct sockaddr_un *ua = (struct sockaddr_un*)sa;
657 
658 					if (ua->sun_path[0] == '\0') {
659 						/* abstract name */
660 						int len = sl - sizeof(sa_family_t);
661 						*textaddr = zend_string_init((char*)ua->sun_path, len, 0);
662 					} else {
663 						int len = strlen(ua->sun_path);
664 						*textaddr = zend_string_init((char*)ua->sun_path, len, 0);
665 					}
666 				}
667 				break;
668 #endif
669 
670 		}
671 
672 	}
673 }
674 
675 PHPAPI int php_network_get_peer_name(php_socket_t sock,
676 		zend_string **textaddr,
677 		struct sockaddr **addr,
678 		socklen_t *addrlen
679 		)
680 {
681 	php_sockaddr_storage sa;
682 	socklen_t sl = sizeof(sa);
683 	memset(&sa, 0, sizeof(sa));
684 
685 	if (getpeername(sock, (struct sockaddr*)&sa, &sl) == 0) {
686 		php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
687 				textaddr,
688 				addr, addrlen
689 				);
690 		return 0;
691 	}
692 	return -1;
693 }
694 
695 PHPAPI int php_network_get_sock_name(php_socket_t sock,
696 		zend_string **textaddr,
697 		struct sockaddr **addr,
698 		socklen_t *addrlen
699 		)
700 {
701 	php_sockaddr_storage sa;
702 	socklen_t sl = sizeof(sa);
703 	memset(&sa, 0, sizeof(sa));
704 
705 	if (getsockname(sock, (struct sockaddr*)&sa, &sl) == 0) {
706 		php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
707 				textaddr,
708 				addr, addrlen
709 				);
710 		return 0;
711 	}
712 	return -1;
713 
714 }
715 
716 
717 /* Accept a client connection from a server socket,
718  * using an optional timeout.
719  * Returns the peer address in addr/addrlen (it will emalloc
720  * these, so be sure to efree the result).
721  * If you specify textaddr, a text-printable
722  * version of the address will be emalloc'd and returned.
723  * */
724 
725 /* {{{ php_network_accept_incoming */
726 PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
727 		zend_string **textaddr,
728 		struct sockaddr **addr,
729 		socklen_t *addrlen,
730 		struct timeval *timeout,
731 		zend_string **error_string,
732 		int *error_code,
733 		int tcp_nodelay
734 		)
735 {
736 	php_socket_t clisock = -1;
737 	int error = 0, n;
738 	php_sockaddr_storage sa;
739 	socklen_t sl;
740 
741 	n = php_pollfd_for(srvsock, PHP_POLLREADABLE, timeout);
742 
743 	if (n == 0) {
744 		error = PHP_TIMEOUT_ERROR_VALUE;
745 	} else if (n == -1) {
746 		error = php_socket_errno();
747 	} else {
748 		sl = sizeof(sa);
749 
750 		clisock = accept(srvsock, (struct sockaddr*)&sa, &sl);
751 
752 		if (clisock != SOCK_ERR) {
753 			php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
754 					textaddr,
755 					addr, addrlen
756 					);
757 			if (tcp_nodelay) {
758 #ifdef TCP_NODELAY
759 				setsockopt(clisock, IPPROTO_TCP, TCP_NODELAY, (char*)&tcp_nodelay, sizeof(tcp_nodelay));
760 #endif
761 			}
762 		} else {
763 			error = php_socket_errno();
764 		}
765 	}
766 
767 	if (error_code) {
768 		*error_code = error;
769 	}
770 	if (error_string) {
771 		*error_string = php_socket_error_str(error);
772 	}
773 
774 	return clisock;
775 }
776 /* }}} */
777 
778 
779 /* Connect to a remote host using an interruptible connect with optional timeout.
780  * Optionally, the connect can be made asynchronously, which will implicitly
781  * enable non-blocking mode on the socket.
782  * Returns the connected (or connecting) socket, or -1 on failure.
783  * */
784 
785 /* {{{ php_network_connect_socket_to_host */
786 php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port,
787 		int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string,
788 		int *error_code, const char *bindto, unsigned short bindport, long sockopts
789 		)
790 {
791 	int num_addrs, n, fatal = 0;
792 	php_socket_t sock;
793 	struct sockaddr **sal, **psal, *sa;
794 	struct timeval working_timeout;
795 	socklen_t socklen;
796 #if HAVE_GETTIMEOFDAY
797 	struct timeval limit_time, time_now;
798 #endif
799 
800 	num_addrs = php_network_getaddresses(host, socktype, &psal, error_string);
801 
802 	if (num_addrs == 0) {
803 		/* could not resolve address(es) */
804 		return -1;
805 	}
806 
807 	if (timeout) {
808 		memcpy(&working_timeout, timeout, sizeof(working_timeout));
809 #if HAVE_GETTIMEOFDAY
810 		gettimeofday(&limit_time, NULL);
811 		limit_time.tv_sec += working_timeout.tv_sec;
812 		limit_time.tv_usec += working_timeout.tv_usec;
813 		if (limit_time.tv_usec >= 1000000) {
814 			limit_time.tv_usec -= 1000000;
815 			limit_time.tv_sec++;
816 		}
817 #endif
818 	}
819 
820 	for (sal = psal; !fatal && *sal != NULL; sal++) {
821 		sa = *sal;
822 
823 		switch (sa->sa_family) {
824 #if HAVE_GETADDRINFO && HAVE_IPV6
825 			case AF_INET6:
826 				if (!bindto || strchr(bindto, ':')) {
827 					((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
828 					socklen = sizeof(struct sockaddr_in6);
829 				} else {
830 					/* Expect IPV4 address, skip to the next */
831 					continue;
832 				}
833 				break;
834 #endif
835 			case AF_INET:
836 				((struct sockaddr_in *)sa)->sin_port = htons(port);
837 				socklen = sizeof(struct sockaddr_in);
838 				if (bindto && (strchr(bindto, ':') || !strcmp(bindto, "0"))) {
839 					/* IPV4 sock can not bind to IPV6 address */
840 					bindto = NULL;
841 				}
842 				break;
843 			default:
844 				/* Unsupported family, skip to the next */
845 				continue;
846 		}
847 
848 		/* create a socket for this address */
849 		sock = socket(sa->sa_family, socktype, 0);
850 
851 		if (sock == SOCK_ERR) {
852 			continue;
853 		}
854 
855 			/* make a connection attempt */
856 
857 		if (bindto) {
858 			union {
859 				struct sockaddr common;
860 				struct sockaddr_in in4;
861 #if HAVE_IPV6 && HAVE_INET_PTON
862 				struct sockaddr_in6 in6;
863 #endif
864 			} local_address;
865 			int local_address_len = 0;
866 
867 			if (sa->sa_family == AF_INET) {
868 #ifdef HAVE_INET_PTON
869 				if (inet_pton(AF_INET, bindto, &local_address.in4.sin_addr) == 1) {
870 #else
871 				if (inet_aton(bindto, &local_address.in4.sin_addr)) {
872 #endif
873 					local_address_len = sizeof(struct sockaddr_in);
874 					local_address.in4.sin_family = sa->sa_family;
875 					local_address.in4.sin_port = htons(bindport);
876 					memset(&(local_address.in4.sin_zero), 0, sizeof(local_address.in4.sin_zero));
877 				}
878 			}
879 #if HAVE_IPV6 && HAVE_INET_PTON
880 			else { /* IPV6 */
881 				if (inet_pton(AF_INET6, bindto, &local_address.in6.sin6_addr) == 1) {
882 					local_address_len = sizeof(struct sockaddr_in6);
883 					local_address.in6.sin6_family = sa->sa_family;
884 					local_address.in6.sin6_port = htons(bindport);
885 				}
886 			}
887 #endif
888 #ifdef IP_BIND_ADDRESS_NO_PORT
889 			{
890 				int val = 1;
891 				(void) setsockopt(sock, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &val, sizeof(val));
892 			}
893 #endif
894 			if (local_address_len == 0) {
895 				php_error_docref(NULL, E_WARNING, "Invalid IP Address: %s", bindto);
896 			} else if (bind(sock, &local_address.common, local_address_len)) {
897 				php_error_docref(NULL, E_WARNING, "Failed to bind to '%s:%d', system said: %s", bindto, bindport, strerror(errno));
898 			}
899 		}
900 		/* free error string received during previous iteration (if any) */
901 		if (error_string && *error_string) {
902 			zend_string_release_ex(*error_string, 0);
903 			*error_string = NULL;
904 		}
905 
906 #ifdef SO_BROADCAST
907 		{
908 			int val = 1;
909 			if (sockopts & STREAM_SOCKOP_SO_BROADCAST) {
910 				setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&val, sizeof(val));
911 			}
912 		}
913 #endif
914 
915 #ifdef TCP_NODELAY
916 		{
917 			int val = 1;
918 			if (sockopts & STREAM_SOCKOP_TCP_NODELAY) {
919 				setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&val, sizeof(val));
920 			}
921 		}
922 #endif
923 		n = php_network_connect_socket(sock, sa, socklen, asynchronous,
924 				timeout ? &working_timeout : NULL,
925 				error_string, error_code);
926 
927 		if (n != -1) {
928 			goto connected;
929 		}
930 
931 		/* adjust timeout for next attempt */
932 #if HAVE_GETTIMEOFDAY
933 		if (timeout) {
934 			gettimeofday(&time_now, NULL);
935 
936 			if (!timercmp(&time_now, &limit_time, <)) {
937 				/* time limit expired; don't attempt any further connections */
938 				fatal = 1;
939 			} else {
940 				/* work out remaining time */
941 				sub_times(limit_time, time_now, &working_timeout);
942 			}
943 		}
944 #else
945 		if (error_code && *error_code == PHP_TIMEOUT_ERROR_VALUE) {
946 			/* Don't even bother trying to connect to the next alternative;
947 				* we have no way to determine how long we have already taken
948 				* and it is quite likely that the next attempt will fail too. */
949 			fatal = 1;
950 		} else {
951 			/* re-use the same initial timeout.
952 				* Not the best thing, but in practice it should be good-enough */
953 			if (timeout) {
954 				memcpy(&working_timeout, timeout, sizeof(working_timeout));
955 			}
956 		}
957 #endif
958 
959 		closesocket(sock);
960 	}
961 	sock = -1;
962 
963 connected:
964 
965 	php_network_freeaddresses(psal);
966 
967 	return sock;
968 }
969 /* }}} */
970 
971 /* {{{ php_any_addr
972  * Fills any (wildcard) address into php_sockaddr_storage
973  */
974 PHPAPI void php_any_addr(int family, php_sockaddr_storage *addr, unsigned short port)
975 {
976 	memset(addr, 0, sizeof(php_sockaddr_storage));
977 	switch (family) {
978 #if HAVE_IPV6
979 	case AF_INET6: {
980 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr;
981 		sin6->sin6_family = AF_INET6;
982 		sin6->sin6_port = htons(port);
983 		sin6->sin6_addr = in6addr_any;
984 		break;
985 	}
986 #endif
987 	case AF_INET: {
988 		struct sockaddr_in *sin = (struct sockaddr_in *) addr;
989 		sin->sin_family = AF_INET;
990 		sin->sin_port = htons(port);
991 		sin->sin_addr.s_addr = htonl(INADDR_ANY);
992 		break;
993 	}
994 	}
995 }
996 /* }}} */
997 
998 /* {{{ php_sockaddr_size
999  * Returns the size of struct sockaddr_xx for the family
1000  */
1001 PHPAPI int php_sockaddr_size(php_sockaddr_storage *addr)
1002 {
1003 	switch (((struct sockaddr *)addr)->sa_family) {
1004 	case AF_INET:
1005 		return sizeof(struct sockaddr_in);
1006 #if HAVE_IPV6
1007 	case AF_INET6:
1008 		return sizeof(struct sockaddr_in6);
1009 #endif
1010 #ifdef AF_UNIX
1011 	case AF_UNIX:
1012 		return sizeof(struct sockaddr_un);
1013 #endif
1014 	default:
1015 		return 0;
1016 	}
1017 }
1018 /* }}} */
1019 
1020 /* Given a socket error code, if buf == NULL:
1021  *   emallocs storage for the error message and returns
1022  * else
1023  *   sprintf message into provided buffer and returns buf
1024  */
1025 /* {{{ php_socket_strerror */
1026 PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize)
1027 {
1028 #ifndef PHP_WIN32
1029 	char *errstr;
1030 
1031 	errstr = strerror(err);
1032 	if (buf == NULL) {
1033 		buf = estrdup(errstr);
1034 	} else {
1035 		strncpy(buf, errstr, bufsize);
1036 		buf[bufsize?(bufsize-1):0] = 0;
1037 	}
1038 	return buf;
1039 #else
1040 	char *sysbuf = php_win32_error_to_msg(err);
1041 	if (!sysbuf[0]) {
1042 		sysbuf = "Unknown Error";
1043 	}
1044 
1045 	if (buf == NULL) {
1046 		buf = estrdup(sysbuf);
1047 	} else {
1048 		strncpy(buf, sysbuf, bufsize);
1049 		buf[bufsize?(bufsize-1):0] = 0;
1050 	}
1051 
1052 	php_win32_error_msg_free(sysbuf);
1053 
1054 	return buf;
1055 #endif
1056 }
1057 /* }}} */
1058 
1059 /* {{{ php_socket_error_str */
1060 PHPAPI zend_string *php_socket_error_str(long err)
1061 {
1062 #ifndef PHP_WIN32
1063 	char *errstr;
1064 
1065 	errstr = strerror(err);
1066 	return zend_string_init(errstr, strlen(errstr), 0);
1067 #else
1068 	zend_string *ret;
1069 
1070 	char *sysbuf = php_win32_error_to_msg(err);
1071 	if (!sysbuf[0]) {
1072 		sysbuf = "Unknown Error";
1073 	}
1074 
1075 	ret = zend_string_init(sysbuf, strlen(sysbuf), 0);
1076 
1077 	php_win32_error_msg_free(sysbuf);
1078 
1079 	return ret;
1080 #endif
1081 }
1082 /* }}} */
1083 
1084 /* deprecated */
1085 PHPAPI php_stream *_php_stream_sock_open_from_socket(php_socket_t socket, const char *persistent_id STREAMS_DC)
1086 {
1087 	php_stream *stream;
1088 	php_netstream_data_t *sock;
1089 
1090 	sock = pemalloc(sizeof(php_netstream_data_t), persistent_id ? 1 : 0);
1091 	memset(sock, 0, sizeof(php_netstream_data_t));
1092 
1093 	sock->is_blocked = 1;
1094 	sock->timeout.tv_sec = FG(default_socket_timeout);
1095 	sock->timeout.tv_usec = 0;
1096 	sock->socket = socket;
1097 
1098 	stream = php_stream_alloc_rel(&php_stream_generic_socket_ops, sock, persistent_id, "r+");
1099 
1100 	if (stream == NULL) {
1101 		pefree(sock, persistent_id ? 1 : 0);
1102 	} else {
1103 		stream->flags |= PHP_STREAM_FLAG_AVOID_BLOCKING;
1104 	}
1105 
1106 	return stream;
1107 }
1108 
1109 PHPAPI php_stream *_php_stream_sock_open_host(const char *host, unsigned short port,
1110 		int socktype, struct timeval *timeout, const char *persistent_id STREAMS_DC)
1111 {
1112 	char *res;
1113 	zend_long reslen;
1114 	php_stream *stream;
1115 
1116 	reslen = spprintf(&res, 0, "tcp://%s:%d", host, port);
1117 
1118 	stream = php_stream_xport_create(res, reslen, REPORT_ERRORS,
1119 			STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, persistent_id, timeout, NULL, NULL, NULL);
1120 
1121 	efree(res);
1122 
1123 	return stream;
1124 }
1125 
1126 PHPAPI int php_set_sock_blocking(php_socket_t socketd, int block)
1127 {
1128 	int ret = SUCCESS;
1129 
1130 #ifdef PHP_WIN32
1131 	u_long flags;
1132 
1133 	/* with ioctlsocket, a non-zero sets nonblocking, a zero sets blocking */
1134 	flags = !block;
1135 	if (ioctlsocket(socketd, FIONBIO, &flags) == SOCKET_ERROR) {
1136 		ret = FAILURE;
1137 	}
1138 #else
1139 	int myflag = 0;
1140 	int flags = fcntl(socketd, F_GETFL);
1141 
1142 #ifdef O_NONBLOCK
1143 	myflag = O_NONBLOCK; /* POSIX version */
1144 #elif defined(O_NDELAY)
1145 	myflag = O_NDELAY;   /* old non-POSIX version */
1146 #endif
1147 	if (!block) {
1148 		flags |= myflag;
1149 	} else {
1150 		flags &= ~myflag;
1151 	}
1152 	if (fcntl(socketd, F_SETFL, flags) == -1) {
1153 		ret = FAILURE;
1154 	}
1155 #endif
1156 	return ret;
1157 }
1158 
1159 PHPAPI void _php_emit_fd_setsize_warning(int max_fd)
1160 {
1161 
1162 #ifdef PHP_WIN32
1163 	php_error_docref(NULL, E_WARNING,
1164 		"PHP needs to be recompiled with a larger value of FD_SETSIZE.\n"
1165 		"If this binary is from an official www.php.net package, file a bug report\n"
1166 		"at https://github.com/php/php-src/issues, including the following information:\n"
1167 		"FD_SETSIZE=%d, but you are using %d.\n"
1168 		" --enable-fd-setsize=%d is recommended, but you may want to set it\n"
1169 		"to match to maximum number of sockets each script will work with at\n"
1170 		"one time, in order to avoid seeing this error again at a later date.",
1171 		FD_SETSIZE, max_fd, (max_fd + 128) & ~127);
1172 #else
1173 	php_error_docref(NULL, E_WARNING,
1174 		"You MUST recompile PHP with a larger value of FD_SETSIZE.\n"
1175 		"It is set to %d, but you have descriptors numbered at least as high as %d.\n"
1176 		" --enable-fd-setsize=%d is recommended, but you may want to set it\n"
1177 		"to equal the maximum number of open files supported by your system,\n"
1178 		"in order to avoid seeing this error again at a later date.",
1179 		FD_SETSIZE, max_fd, (max_fd + 1024) & ~1023);
1180 #endif
1181 }
1182 
1183 #if defined(PHP_USE_POLL_2_EMULATION)
1184 
1185 /* emulate poll(2) using select(2), safely. */
1186 
1187 PHPAPI int php_poll2(php_pollfd *ufds, unsigned int nfds, int timeout)
1188 {
1189 	fd_set rset, wset, eset;
1190 	php_socket_t max_fd = SOCK_ERR; /* effectively unused on Windows */
1191 	unsigned int i;
1192 	int n;
1193 	struct timeval tv;
1194 
1195 #ifndef PHP_WIN32
1196 	/* check the highest numbered descriptor */
1197 	for (i = 0; i < nfds; i++) {
1198 		if (ufds[i].fd > max_fd)
1199 			max_fd = ufds[i].fd;
1200 	}
1201 #endif
1202 
1203 	if (!PHP_SAFE_MAX_FD(max_fd, nfds + 1)) {
1204 #ifdef PHP_WIN32
1205 		WSASetLastError(WSAEINVAL);
1206 #else
1207 		errno = ERANGE;
1208 #endif
1209 		return -1;
1210 	}
1211 
1212 	FD_ZERO(&rset);
1213 	FD_ZERO(&wset);
1214 	FD_ZERO(&eset);
1215 
1216 	for (i = 0; i < nfds; i++) {
1217 		if (ufds[i].events & PHP_POLLREADABLE) {
1218 			PHP_SAFE_FD_SET(ufds[i].fd, &rset);
1219 		}
1220 		if (ufds[i].events & POLLOUT) {
1221 			PHP_SAFE_FD_SET(ufds[i].fd, &wset);
1222 		}
1223 		if (ufds[i].events & POLLPRI) {
1224 			PHP_SAFE_FD_SET(ufds[i].fd, &eset);
1225 		}
1226 	}
1227 
1228 	if (timeout >= 0) {
1229 		tv.tv_sec = timeout / 1000;
1230 		tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000;
1231 	}
1232 /* Resetting/initializing */
1233 #ifdef PHP_WIN32
1234 	WSASetLastError(0);
1235 #else
1236 	errno = 0;
1237 #endif
1238 	n = select(max_fd + 1, &rset, &wset, &eset, timeout >= 0 ? &tv : NULL);
1239 
1240 	if (n >= 0) {
1241 		for (i = 0; i < nfds; i++) {
1242 			ufds[i].revents = 0;
1243 
1244 			if (PHP_SAFE_FD_ISSET(ufds[i].fd, &rset)) {
1245 				/* could be POLLERR or POLLHUP but can't tell without probing */
1246 				ufds[i].revents |= POLLIN;
1247 			}
1248 			if (PHP_SAFE_FD_ISSET(ufds[i].fd, &wset)) {
1249 				ufds[i].revents |= POLLOUT;
1250 			}
1251 			if (PHP_SAFE_FD_ISSET(ufds[i].fd, &eset)) {
1252 				ufds[i].revents |= POLLPRI;
1253 			}
1254 		}
1255 	}
1256 	return n;
1257 }
1258 #endif
1259 
1260 #if defined(HAVE_GETHOSTBYNAME_R)
1261 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_6
1262 struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen)
1263 {
1264 	struct hostent *hp;
1265 	int herr,res;
1266 
1267 	if (*hstbuflen == 0) {
1268 		*hstbuflen = 1024;
1269 		*tmphstbuf = (char *)malloc (*hstbuflen);
1270 	}
1271 
1272 	while (( res =
1273 		gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&hp,&herr))
1274 		&& (errno == ERANGE)) {
1275 		/* Enlarge the buffer. */
1276 		*hstbuflen *= 2;
1277 		*tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen);
1278 	}
1279 
1280 	if (res != SUCCESS) {
1281 		return NULL;
1282 	}
1283 
1284 	return hp;
1285 }
1286 #endif
1287 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_5
1288 struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen)
1289 {
1290 	struct hostent *hp;
1291 	int herr;
1292 
1293 	if (*hstbuflen == 0) {
1294 		*hstbuflen = 1024;
1295 		*tmphstbuf = (char *)malloc (*hstbuflen);
1296 	}
1297 
1298 	while ((NULL == ( hp =
1299 		gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&herr)))
1300 		&& (errno == ERANGE)) {
1301 		/* Enlarge the buffer. */
1302 		*hstbuflen *= 2;
1303 		*tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen);
1304 	}
1305 	return hp;
1306 }
1307 #endif
1308 #ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
1309 struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen)
1310 {
1311 	if (*hstbuflen == 0) {
1312 		*hstbuflen = sizeof(struct hostent_data);
1313 		*tmphstbuf = (char *)malloc (*hstbuflen);
1314 	} else {
1315 		if (*hstbuflen < sizeof(struct hostent_data)) {
1316 			*hstbuflen = sizeof(struct hostent_data);
1317 			*tmphstbuf = (char *)realloc(*tmphstbuf, *hstbuflen);
1318 		}
1319 	}
1320 	memset((void *)(*tmphstbuf),0,*hstbuflen);
1321 
1322 	if (SUCCESS != gethostbyname_r(host,hostbuf,(struct hostent_data *)*tmphstbuf)) {
1323 		return NULL;
1324 	}
1325 
1326 	return hostbuf;
1327 }
1328 #endif
1329 #endif
1330 
1331 PHPAPI struct hostent*	php_network_gethostbyname(const char *name) {
1332 #if !defined(HAVE_GETHOSTBYNAME_R)
1333 	return gethostbyname(name);
1334 #else
1335 	if (FG(tmp_host_buf)) {
1336 		free(FG(tmp_host_buf));
1337 	}
1338 
1339 	FG(tmp_host_buf) = NULL;
1340 	FG(tmp_host_buf_len) = 0;
1341 
1342 	memset(&FG(tmp_host_info), 0, sizeof(struct hostent));
1343 
1344 	return gethostname_re(name, &FG(tmp_host_info), &FG(tmp_host_buf), &FG(tmp_host_buf_len));
1345 #endif
1346 }
1347