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