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