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