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