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