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