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