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