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