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