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