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