php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
xp_socket.c
Go to the documentation of this file.
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: Wez Furlong <wez@thebrainroom.com> |
14 +----------------------------------------------------------------------+
15*/
16
17#include "php.h"
18#include "ext/standard/file.h"
20#include "php_network.h"
21
22#if defined(PHP_WIN32) || defined(__riscos__)
23# undef AF_UNIX
24#endif
25
26#ifdef AF_UNIX
27#include <sys/un.h>
28#endif
29
30#ifndef MSG_DONTWAIT
31# define MSG_DONTWAIT 0
32#endif
33
34#ifndef MSG_PEEK
35# define MSG_PEEK 0
36#endif
37
38#ifdef PHP_WIN32
39/* send/recv family on windows expects int */
40# define XP_SOCK_BUF_SIZE(sz) (((sz) > INT_MAX) ? INT_MAX : (int)(sz))
41#else
42# define XP_SOCK_BUF_SIZE(sz) (sz)
43#endif
44
47static const php_stream_ops php_stream_udp_socket_ops;
48#ifdef AF_UNIX
49static const php_stream_ops php_stream_unix_socket_ops;
50static const php_stream_ops php_stream_unixdg_socket_ops;
51#endif
52
53
54static int php_tcp_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam);
55
56/* {{{ Generic socket stream operations */
57static ssize_t php_sockop_write(php_stream *stream, const char *buf, size_t count)
58{
60 ssize_t didwrite;
61 struct timeval *ptimeout;
62
63 if (!sock || sock->socket == -1) {
64 return 0;
65 }
66
67 if (sock->timeout.tv_sec == -1)
68 ptimeout = NULL;
69 else
70 ptimeout = &sock->timeout;
71
72retry:
73 didwrite = send(sock->socket, buf, XP_SOCK_BUF_SIZE(count), (sock->is_blocked && ptimeout) ? MSG_DONTWAIT : 0);
74
75 if (didwrite <= 0) {
76 char *estr;
77 int err = php_socket_errno();
78
80 if (sock->is_blocked) {
81 int retval;
82
83 sock->timeout_event = 0;
84
85 do {
86 retval = php_pollfd_for(sock->socket, POLLOUT, ptimeout);
87
88 if (retval == 0) {
89 sock->timeout_event = 1;
90 break;
91 }
92
93 if (retval > 0) {
94 /* writable now; retry */
95 goto retry;
96 }
97
99 } while (err == EINTR);
100 } else {
101 /* EWOULDBLOCK/EAGAIN is not an error for a non-blocking stream.
102 * Report zero byte write instead. */
103 return 0;
104 }
105 }
106
107 if (!(stream->flags & PHP_STREAM_FLAG_SUPPRESS_ERRORS)) {
108 estr = php_socket_strerror(err, NULL, 0);
110 "Send of " ZEND_LONG_FMT " bytes failed with errno=%d %s",
111 (zend_long)count, err, estr);
112 efree(estr);
113 }
114 }
115
116 if (didwrite > 0) {
118 }
119
120 return didwrite;
121}
122
123static void php_sock_stream_wait_for_data(php_stream *stream, php_netstream_data_t *sock, bool has_buffered_data)
124{
125 int retval;
126 struct timeval *ptimeout, zero_timeout;
127
128 if (!sock || sock->socket == -1) {
129 return;
130 }
131
132 sock->timeout_event = 0;
133
134 if (has_buffered_data) {
135 /* If there is already buffered data, use no timeout. */
136 zero_timeout.tv_sec = 0;
137 zero_timeout.tv_usec = 0;
138 ptimeout = &zero_timeout;
139 } else if (sock->timeout.tv_sec == -1) {
140 ptimeout = NULL;
141 } else {
142 ptimeout = &sock->timeout;
143 }
144
145 while(1) {
146 retval = php_pollfd_for(sock->socket, PHP_POLLREADABLE, ptimeout);
147
148 if (retval == 0)
149 sock->timeout_event = 1;
150
151 if (retval >= 0)
152 break;
153
154 if (php_socket_errno() != EINTR)
155 break;
156 }
157}
158
159static ssize_t php_sockop_read(php_stream *stream, char *buf, size_t count)
160{
162
163 if (!sock || sock->socket == -1) {
164 return -1;
165 }
166
167 int recv_flags = 0;
168 /* Special handling for blocking read. */
169 if (sock->is_blocked) {
170 /* Find out if there is any data buffered from the previous read. */
171 bool has_buffered_data = stream->has_buffered_data;
172 /* No need to wait if there is any data buffered or no timeout. */
173 bool dont_wait = has_buffered_data ||
174 (sock->timeout.tv_sec == 0 && sock->timeout.tv_usec == 0);
175 /* Set MSG_DONTWAIT if no wait is needed or there is unlimited timeout which was
176 * added by fix for #41984 committed in 9343c5404. */
177 if (dont_wait || sock->timeout.tv_sec != -1) {
178 recv_flags = MSG_DONTWAIT;
179 }
180 /* If the wait is needed or it is a platform without MSG_DONTWAIT support (e.g. Windows),
181 * then poll for data. */
182 if (!dont_wait || MSG_DONTWAIT == 0) {
183 php_sock_stream_wait_for_data(stream, sock, has_buffered_data);
184 if (sock->timeout_event) {
185 /* It is ok to timeout if there is any data buffered so return 0, otherwise -1. */
186 return has_buffered_data ? 0 : -1;
187 }
188 }
189 }
190
191 ssize_t nr_bytes = recv(sock->socket, buf, XP_SOCK_BUF_SIZE(count), recv_flags);
192 int err = php_socket_errno();
193
194 if (nr_bytes < 0) {
196 nr_bytes = 0;
197 } else {
198 stream->eof = 1;
199 }
200 } else if (nr_bytes == 0) {
201 stream->eof = 1;
202 }
203
204 if (nr_bytes > 0) {
206 }
207
208 return nr_bytes;
209}
210
211
212static int php_sockop_close(php_stream *stream, int close_handle)
213{
215#ifdef PHP_WIN32
216 int n;
217#endif
218
219 if (!sock) {
220 return 0;
221 }
222
223 if (close_handle) {
224
225#ifdef PHP_WIN32
226 if (sock->socket == -1)
227 sock->socket = SOCK_ERR;
228#endif
229 if (sock->socket != SOCK_ERR) {
230#ifdef PHP_WIN32
231 /* prevent more data from coming in */
232 shutdown(sock->socket, SHUT_RD);
233
234 /* try to make sure that the OS sends all data before we close the connection.
235 * Essentially, we are waiting for the socket to become writeable, which means
236 * that all pending data has been sent.
237 * We use a small timeout which should encourage the OS to send the data,
238 * but at the same time avoid hanging indefinitely.
239 * */
240 do {
241 n = php_pollfd_for_ms(sock->socket, POLLOUT, 500);
242 } while (n == -1 && php_socket_errno() == EINTR);
243#endif
244 closesocket(sock->socket);
245 sock->socket = SOCK_ERR;
246 }
247
248 }
249
250 pefree(sock, php_stream_is_persistent(stream));
251
252 return 0;
253}
254
255static int php_sockop_flush(php_stream *stream)
256{
257#if 0
259 return fsync(sock->socket);
260#endif
261 return 0;
262}
263
264static int php_sockop_stat(php_stream *stream, php_stream_statbuf *ssb)
265{
266#ifdef ZEND_WIN32
267 return 0;
268#else
270
271 return zend_fstat(sock->socket, &ssb->sb);
272#endif
273}
274
275static inline int sock_sendto(php_netstream_data_t *sock, const char *buf, size_t buflen, int flags,
276 struct sockaddr *addr, socklen_t addrlen
277 )
278{
279 int ret;
280 if (addr) {
281 ret = sendto(sock->socket, buf, XP_SOCK_BUF_SIZE(buflen), flags, addr, XP_SOCK_BUF_SIZE(addrlen));
282
283 return (ret == SOCK_CONN_ERR) ? -1 : ret;
284 }
285#ifdef PHP_WIN32
286 return ((ret = send(sock->socket, buf, buflen > INT_MAX ? INT_MAX : (int)buflen, flags)) == SOCK_CONN_ERR) ? -1 : ret;
287#else
288 return ((ret = send(sock->socket, buf, buflen, flags)) == SOCK_CONN_ERR) ? -1 : ret;
289#endif
290}
291
292static inline int sock_recvfrom(php_netstream_data_t *sock, char *buf, size_t buflen, int flags,
293 zend_string **textaddr,
294 struct sockaddr **addr, socklen_t *addrlen
295 )
296{
297 int ret;
298 int want_addr = textaddr || addr;
299
300 if (want_addr) {
302 socklen_t sl = sizeof(sa);
303 ret = recvfrom(sock->socket, buf, XP_SOCK_BUF_SIZE(buflen), flags, (struct sockaddr*)&sa, &sl);
304 ret = (ret == SOCK_CONN_ERR) ? -1 : ret;
305#ifdef PHP_WIN32
306 /* POSIX discards excess bytes without signalling failure; emulate this on Windows */
307 if (ret == -1 && WSAGetLastError() == WSAEMSGSIZE) {
308 ret = buflen;
309 }
310#endif
311 if (sl) {
312 php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
313 textaddr, addr, addrlen);
314 } else {
315 if (textaddr) {
316 *textaddr = ZSTR_EMPTY_ALLOC();
317 }
318 if (addr) {
319 *addr = NULL;
320 *addrlen = 0;
321 }
322 }
323 } else {
324 ret = recv(sock->socket, buf, XP_SOCK_BUF_SIZE(buflen), flags);
325 ret = (ret == SOCK_CONN_ERR) ? -1 : ret;
326 }
327
328 return ret;
329}
330
331static int php_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam)
332{
333 int oldmode, flags;
336
337 if (!sock) {
339 }
340
341 switch(option) {
343 {
344 struct timeval tv;
345 char buf;
346 int alive = 1;
347
348 if (value == -1) {
349 if (sock->timeout.tv_sec == -1) {
350 tv.tv_sec = FG(default_socket_timeout);
351 tv.tv_usec = 0;
352 } else {
353 tv = sock->timeout;
354 }
355 } else {
356 tv.tv_sec = value;
357 tv.tv_usec = 0;
358 }
359
360 if (sock->socket == -1) {
361 alive = 0;
362 } else if (
363 (
364 value == 0 &&
365 !(stream->flags & PHP_STREAM_FLAG_NO_IO) &&
366 ((MSG_DONTWAIT != 0) || !sock->is_blocked)
367 ) ||
368 php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0
369 ) {
370 /* the poll() call was skipped if the socket is non-blocking (or MSG_DONTWAIT is available) and if the timeout is zero */
371#ifdef PHP_WIN32
372 int ret;
373#else
374 ssize_t ret;
375#endif
376
377 ret = recv(sock->socket, &buf, sizeof(buf), MSG_PEEK|MSG_DONTWAIT);
378 if (0 == ret) {
379 /* the counterpart did properly shutdown */
380 alive = 0;
381 } else if (0 > ret) {
382 int err = php_socket_errno();
383 if (err != EWOULDBLOCK && err != EMSGSIZE && err != EAGAIN) {
384 /* there was an unrecoverable error */
385 alive = 0;
386 }
387 }
388 }
390 }
391
393 oldmode = sock->is_blocked;
394 if (SUCCESS == php_set_sock_blocking(sock->socket, value)) {
395 sock->is_blocked = value;
396 return oldmode;
397 }
399
401 sock->timeout = *(struct timeval*)ptrparam;
402 sock->timeout_event = 0;
404
406 add_assoc_bool((zval *)ptrparam, "timed_out", sock->timeout_event);
407 add_assoc_bool((zval *)ptrparam, "blocked", sock->is_blocked);
408 add_assoc_bool((zval *)ptrparam, "eof", stream->eof);
410
412 xparam = (php_stream_xport_param *)ptrparam;
413
414 switch (xparam->op) {
415 case STREAM_XPORT_OP_LISTEN:
416 xparam->outputs.returncode = (listen(sock->socket, xparam->inputs.backlog) == 0) ? 0: -1;
418
419 case STREAM_XPORT_OP_GET_NAME:
421 xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
422 xparam->want_addr ? &xparam->outputs.addr : NULL,
423 xparam->want_addr ? &xparam->outputs.addrlen : NULL
424 );
426
427 case STREAM_XPORT_OP_GET_PEER_NAME:
429 xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
430 xparam->want_addr ? &xparam->outputs.addr : NULL,
431 xparam->want_addr ? &xparam->outputs.addrlen : NULL
432 );
434
435 case STREAM_XPORT_OP_SEND:
436 flags = 0;
437 if ((xparam->inputs.flags & STREAM_OOB) == STREAM_OOB) {
438 flags |= MSG_OOB;
439 }
440 xparam->outputs.returncode = sock_sendto(sock,
441 xparam->inputs.buf, xparam->inputs.buflen,
442 flags,
443 xparam->inputs.addr,
444 xparam->inputs.addrlen);
445 if (xparam->outputs.returncode == -1) {
448 "%s\n", err);
449 efree(err);
450 }
452
453 case STREAM_XPORT_OP_RECV:
454 flags = 0;
455 if ((xparam->inputs.flags & STREAM_OOB) == STREAM_OOB) {
456 flags |= MSG_OOB;
457 }
458 if ((xparam->inputs.flags & STREAM_PEEK) == STREAM_PEEK) {
459 flags |= MSG_PEEK;
460 }
461 xparam->outputs.returncode = sock_recvfrom(sock,
462 xparam->inputs.buf, xparam->inputs.buflen,
463 flags,
464 xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
465 xparam->want_addr ? &xparam->outputs.addr : NULL,
466 xparam->want_addr ? &xparam->outputs.addrlen : NULL
467 );
469
470
471#ifdef HAVE_SHUTDOWN
472# ifndef SHUT_RD
473# define SHUT_RD 0
474# endif
475# ifndef SHUT_WR
476# define SHUT_WR 1
477# endif
478# ifndef SHUT_RDWR
479# define SHUT_RDWR 2
480# endif
481 case STREAM_XPORT_OP_SHUTDOWN: {
482 static const int shutdown_how[] = {SHUT_RD, SHUT_WR, SHUT_RDWR};
483
484 xparam->outputs.returncode = shutdown(sock->socket, shutdown_how[xparam->how]);
486 }
487#endif
488
489 default:
490 break;
491 }
492 }
493
495}
496
497static int php_sockop_cast(php_stream *stream, int castas, void **ret)
498{
500
501 if (!sock) {
502 return FAILURE;
503 }
504
505 switch(castas) {
507 if (ret) {
508 *(FILE**)ret = fdopen(sock->socket, stream->mode);
509 if (*ret)
510 return SUCCESS;
511 return FAILURE;
512 }
513 return SUCCESS;
515 case PHP_STREAM_AS_FD:
517 if (ret)
518 *(php_socket_t *)ret = sock->socket;
519 return SUCCESS;
520 default:
521 return FAILURE;
522 }
523}
524/* }}} */
525
526/* These may look identical, but we need them this way so that
527 * we can determine which type of socket we are dealing with
528 * by inspecting stream->ops.
529 * A "useful" side-effect is that the user's scripts can then
530 * make similar decisions using stream_get_meta_data.
531 * */
533 php_sockop_write, php_sockop_read,
534 php_sockop_close, php_sockop_flush,
535 "generic_socket",
536 NULL, /* seek */
537 php_sockop_cast,
538 php_sockop_stat,
539 php_sockop_set_option,
540};
541
542
544 php_sockop_write, php_sockop_read,
545 php_sockop_close, php_sockop_flush,
546 "tcp_socket",
547 NULL, /* seek */
548 php_sockop_cast,
549 php_sockop_stat,
550 php_tcp_sockop_set_option,
551};
552
553static const php_stream_ops php_stream_udp_socket_ops = {
554 php_sockop_write, php_sockop_read,
555 php_sockop_close, php_sockop_flush,
556 "udp_socket",
557 NULL, /* seek */
558 php_sockop_cast,
559 php_sockop_stat,
560 php_tcp_sockop_set_option,
561};
562
563#ifdef AF_UNIX
564static const php_stream_ops php_stream_unix_socket_ops = {
565 php_sockop_write, php_sockop_read,
566 php_sockop_close, php_sockop_flush,
567 "unix_socket",
568 NULL, /* seek */
569 php_sockop_cast,
570 php_sockop_stat,
571 php_tcp_sockop_set_option,
572};
573static const php_stream_ops php_stream_unixdg_socket_ops = {
574 php_sockop_write, php_sockop_read,
575 php_sockop_close, php_sockop_flush,
576 "udg_socket",
577 NULL, /* seek */
578 php_sockop_cast,
579 php_sockop_stat,
580 php_tcp_sockop_set_option,
581};
582#endif
583
584
585/* network socket operations */
586
587#ifdef AF_UNIX
588static inline int parse_unix_address(php_stream_xport_param *xparam, struct sockaddr_un *unix_addr)
589{
590 memset(unix_addr, 0, sizeof(*unix_addr));
591 unix_addr->sun_family = AF_UNIX;
592
593 /* Abstract namespace does not need to be NUL-terminated, while path-based
594 * sockets should be. */
595 bool is_abstract_ns = xparam->inputs.namelen > 0 && xparam->inputs.name[0] == '\0';
596 unsigned long max_length = is_abstract_ns ? sizeof(unix_addr->sun_path) : sizeof(unix_addr->sun_path) - 1;
597
598 /* we need to be binary safe on systems that support an abstract
599 * namespace */
600 if (xparam->inputs.namelen > max_length) {
601 /* On linux, when the path begins with a NUL byte we are
602 * referring to an abstract namespace. In theory we should
603 * allow an extra byte below, since we don't need the NULL.
604 * BUT, to get into this branch of code, the name is too long,
605 * so we don't care. */
606 xparam->inputs.namelen = max_length;
607 php_error_docref(NULL, E_NOTICE,
608 "socket path exceeded the maximum allowed length of %lu bytes "
609 "and was truncated", max_length);
610 }
611
612 memcpy(unix_addr->sun_path, xparam->inputs.name, xparam->inputs.namelen);
613
614 return 1;
615}
616#endif
617
618static inline char *parse_ip_address_ex(const char *str, size_t str_len, int *portno, int get_err, zend_string **err)
619{
620 char *colon;
621 char *host = NULL;
622
623#ifdef HAVE_IPV6
624 char *p;
625
626 if (*(str) == '[' && str_len > 1) {
627 /* IPV6 notation to specify raw address with port (i.e. [fe80::1]:80) */
628 p = memchr(str + 1, ']', str_len - 2);
629 if (!p || *(p + 1) != ':') {
630 if (get_err) {
631 *err = strpprintf(0, "Failed to parse IPv6 address \"%s\"", str);
632 }
633 return NULL;
634 }
635 *portno = atoi(p + 2);
636 return estrndup(str + 1, p - str - 1);
637 }
638#endif
639 if (str_len) {
640 colon = memchr(str, ':', str_len - 1);
641 } else {
642 colon = NULL;
643 }
644 if (colon) {
645 *portno = atoi(colon + 1);
646 host = estrndup(str, colon - str);
647 } else {
648 if (get_err) {
649 *err = strpprintf(0, "Failed to parse address \"%s\"", str);
650 }
651 return NULL;
652 }
653
654 return host;
655}
656
657static inline char *parse_ip_address(php_stream_xport_param *xparam, int *portno)
658{
659 return parse_ip_address_ex(xparam->inputs.name, xparam->inputs.namelen, portno, xparam->want_errortext, &xparam->outputs.error_text);
660}
661
662static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t *sock,
664{
665 char *host = NULL;
666 int portno, err;
667 long sockopts = STREAM_SOCKOP_NONE;
668 zval *tmpzval = NULL;
669
670#ifdef AF_UNIX
671 if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) {
672 struct sockaddr_un unix_addr;
673
674 sock->socket = socket(PF_UNIX, stream->ops == &php_stream_unix_socket_ops ? SOCK_STREAM : SOCK_DGRAM, 0);
675
676 if (sock->socket == SOCK_ERR) {
677 if (xparam->want_errortext) {
678 xparam->outputs.error_text = strpprintf(0, "Failed to create unix%s socket %s",
679 stream->ops == &php_stream_unix_socket_ops ? "" : "datagram",
680 strerror(errno));
681 }
682 return -1;
683 }
684
685 parse_unix_address(xparam, &unix_addr);
686
687 return bind(sock->socket, (const struct sockaddr *)&unix_addr,
688 (socklen_t) XtOffsetOf(struct sockaddr_un, sun_path) + xparam->inputs.namelen);
689 }
690#endif
691
692 host = parse_ip_address(xparam, &portno);
693
694 if (host == NULL) {
695 return -1;
696 }
697
698#ifdef IPV6_V6ONLY
699 if (PHP_STREAM_CONTEXT(stream)
700 && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "ipv6_v6only")) != NULL
701 && Z_TYPE_P(tmpzval) != IS_NULL
702 ) {
703 sockopts |= STREAM_SOCKOP_IPV6_V6ONLY;
704 sockopts |= STREAM_SOCKOP_IPV6_V6ONLY_ENABLED * zend_is_true(tmpzval);
705 }
706#endif
707
708#ifdef SO_REUSEPORT
709 if (PHP_STREAM_CONTEXT(stream)
710 && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_reuseport")) != NULL
711 && zend_is_true(tmpzval)
712 ) {
713 sockopts |= STREAM_SOCKOP_SO_REUSEPORT;
714 }
715#endif
716
717#ifdef SO_BROADCAST
718 if (stream->ops == &php_stream_udp_socket_ops /* SO_BROADCAST is only applicable for UDP */
719 && PHP_STREAM_CONTEXT(stream)
720 && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_broadcast")) != NULL
721 && zend_is_true(tmpzval)
722 ) {
723 sockopts |= STREAM_SOCKOP_SO_BROADCAST;
724 }
725#endif
726
728 stream->ops == &php_stream_udp_socket_ops ? SOCK_DGRAM : SOCK_STREAM,
729 sockopts,
730 xparam->want_errortext ? &xparam->outputs.error_text : NULL,
731 &err
732 );
733
734 if (host) {
735 efree(host);
736 }
737
738 return sock->socket == -1 ? -1 : 0;
739}
740
741static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_t *sock,
743{
744 char *host = NULL, *bindto = NULL;
745 int portno, bindport = 0;
746 int err = 0;
747 int ret;
748 zval *tmpzval = NULL;
749 long sockopts = STREAM_SOCKOP_NONE;
750
751#ifdef AF_UNIX
752 if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) {
753 struct sockaddr_un unix_addr;
754
755 sock->socket = socket(PF_UNIX, stream->ops == &php_stream_unix_socket_ops ? SOCK_STREAM : SOCK_DGRAM, 0);
756
757 if (sock->socket == SOCK_ERR) {
758 if (xparam->want_errortext) {
759 xparam->outputs.error_text = strpprintf(0, "Failed to create unix socket");
760 }
761 return -1;
762 }
763
764 parse_unix_address(xparam, &unix_addr);
765
767 (const struct sockaddr *)&unix_addr, (socklen_t) XtOffsetOf(struct sockaddr_un, sun_path) + xparam->inputs.namelen,
768 xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC, xparam->inputs.timeout,
769 xparam->want_errortext ? &xparam->outputs.error_text : NULL,
770 &err);
771
772 xparam->outputs.error_code = err;
773
774 goto out;
775 }
776#endif
777
778 host = parse_ip_address(xparam, &portno);
779
780 if (host == NULL) {
781 return -1;
782 }
783
784 if (PHP_STREAM_CONTEXT(stream) && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "bindto")) != NULL) {
785 if (Z_TYPE_P(tmpzval) != IS_STRING) {
786 if (xparam->want_errortext) {
787 xparam->outputs.error_text = strpprintf(0, "local_addr context option is not a string.");
788 }
789 efree(host);
790 return -1;
791 }
792 bindto = parse_ip_address_ex(Z_STRVAL_P(tmpzval), Z_STRLEN_P(tmpzval), &bindport, xparam->want_errortext, &xparam->outputs.error_text);
793 }
794
795#ifdef SO_BROADCAST
796 if (stream->ops == &php_stream_udp_socket_ops /* SO_BROADCAST is only applicable for UDP */
797 && PHP_STREAM_CONTEXT(stream)
798 && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_broadcast")) != NULL
799 && zend_is_true(tmpzval)
800 ) {
801 sockopts |= STREAM_SOCKOP_SO_BROADCAST;
802 }
803#endif
804
805 if (stream->ops != &php_stream_udp_socket_ops /* TCP_NODELAY is only applicable for TCP */
806#ifdef AF_UNIX
807 && stream->ops != &php_stream_unix_socket_ops
808 && stream->ops != &php_stream_unixdg_socket_ops
809#endif
810 && PHP_STREAM_CONTEXT(stream)
811 && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay")) != NULL
812 && zend_is_true(tmpzval)
813 ) {
814 sockopts |= STREAM_SOCKOP_TCP_NODELAY;
815 }
816
817 /* Note: the test here for php_stream_udp_socket_ops is important, because we
818 * want the default to be TCP sockets so that the openssl extension can
819 * re-use this code. */
820
821 sock->socket = php_network_connect_socket_to_host(host, portno,
822 stream->ops == &php_stream_udp_socket_ops ? SOCK_DGRAM : SOCK_STREAM,
823 xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC,
824 xparam->inputs.timeout,
825 xparam->want_errortext ? &xparam->outputs.error_text : NULL,
826 &err,
827 bindto,
828 bindport,
829 sockopts
830 );
831
832 ret = sock->socket == -1 ? -1 : 0;
833 xparam->outputs.error_code = err;
834
835 if (host) {
836 efree(host);
837 }
838 if (bindto) {
839 efree(bindto);
840 }
841
842#ifdef AF_UNIX
843out:
844#endif
845
846 if (ret >= 0 && xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC && err == EINPROGRESS) {
847 /* indicates pending connection */
848 return 1;
849 }
850
851 return ret;
852}
853
854static inline int php_tcp_sockop_accept(php_stream *stream, php_netstream_data_t *sock,
856{
857 int clisock;
858 bool nodelay = 0;
859 zval *tmpzval = NULL;
860
861 xparam->outputs.client = NULL;
862
863 if ((NULL != PHP_STREAM_CONTEXT(stream)) &&
864 (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay")) != NULL &&
865 zend_is_true(tmpzval)) {
866 nodelay = 1;
867 }
868
869 clisock = php_network_accept_incoming(sock->socket,
870 xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
871 xparam->want_addr ? &xparam->outputs.addr : NULL,
872 xparam->want_addr ? &xparam->outputs.addrlen : NULL,
873 xparam->inputs.timeout,
874 xparam->want_errortext ? &xparam->outputs.error_text : NULL,
875 &xparam->outputs.error_code,
876 nodelay);
877
878 if (clisock >= 0) {
879 php_netstream_data_t *clisockdata = (php_netstream_data_t*) emalloc(sizeof(*clisockdata));
880
881 memcpy(clisockdata, sock, sizeof(*clisockdata));
882 clisockdata->socket = clisock;
883#ifdef __linux__
884 /* O_NONBLOCK is not inherited on Linux */
885 clisockdata->is_blocked = 1;
886#endif
887
888 xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+");
889 if (xparam->outputs.client) {
890 xparam->outputs.client->ctx = stream->ctx;
891 if (stream->ctx) {
892 GC_ADDREF(stream->ctx);
893 }
894 }
895 }
896
897 return xparam->outputs.client == NULL ? -1 : 0;
898}
899
900static int php_tcp_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam)
901{
904
905 switch(option) {
907 xparam = (php_stream_xport_param *)ptrparam;
908
909 switch(xparam->op) {
910 case STREAM_XPORT_OP_CONNECT:
911 case STREAM_XPORT_OP_CONNECT_ASYNC:
912 xparam->outputs.returncode = php_tcp_sockop_connect(stream, sock, xparam);
914
915 case STREAM_XPORT_OP_BIND:
916 xparam->outputs.returncode = php_tcp_sockop_bind(stream, sock, xparam);
918
919
920 case STREAM_XPORT_OP_ACCEPT:
921 xparam->outputs.returncode = php_tcp_sockop_accept(stream, sock, xparam STREAMS_CC);
923 default:
924 /* fall through */
925 ;
926 }
927 }
928 return php_sockop_set_option(stream, option, value, ptrparam);
929}
930
931
932PHPAPI php_stream *php_stream_generic_socket_factory(const char *proto, size_t protolen,
933 const char *resourcename, size_t resourcenamelen,
934 const char *persistent_id, int options, int flags,
935 struct timeval *timeout,
937{
938 php_stream *stream = NULL;
940 const php_stream_ops *ops;
941
942 /* which type of socket ? */
943 if (strncmp(proto, "tcp", protolen) == 0) {
945 } else if (strncmp(proto, "udp", protolen) == 0) {
946 ops = &php_stream_udp_socket_ops;
947 }
948#ifdef AF_UNIX
949 else if (strncmp(proto, "unix", protolen) == 0) {
950 ops = &php_stream_unix_socket_ops;
951 } else if (strncmp(proto, "udg", protolen) == 0) {
952 ops = &php_stream_unixdg_socket_ops;
953 }
954#endif
955 else {
956 /* should never happen */
957 return NULL;
958 }
959
960 sock = pemalloc(sizeof(php_netstream_data_t), persistent_id ? 1 : 0);
961 memset(sock, 0, sizeof(php_netstream_data_t));
962
963 sock->is_blocked = 1;
964 sock->timeout.tv_sec = FG(default_socket_timeout);
965 sock->timeout.tv_usec = 0;
966
967 /* we don't know the socket until we have determined if we are binding or
968 * connecting */
969 sock->socket = -1;
970
971 stream = php_stream_alloc_rel(ops, sock, persistent_id, "r+");
972
973 if (stream == NULL) {
974 pefree(sock, persistent_id ? 1 : 0);
975 return NULL;
976 }
977
978 return stream;
979}
sizeof(Countable|array $value, int $mode=COUNT_NORMAL)
fsync($stream)
count(Countable|array $value, int $mode=COUNT_NORMAL)
unsigned int socklen_t
Definition fastcgi.c:87
zend_long n
Definition ffi.c:4979
memcpy(ptr1, ptr2, size)
char * err
Definition ffi.c:3029
memset(ptr, 0, type->size)
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
const php_stream_filter_ops * ops
Definition filters.c:1899
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
PHPAPI zend_result php_set_sock_blocking(php_socket_t socketd, bool block)
Definition network.c:1145
PHPAPI int 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)
Definition network.c:334
PHPAPI char * php_socket_strerror(long err, char *buf, size_t bufsize)
Definition network.c:1045
PHPAPI void php_network_populate_name_from_sockaddr(struct sockaddr *sa, socklen_t sl, zend_string **textaddr, struct sockaddr **addr, socklen_t *addrlen)
Definition network.c:643
#define SOCK_CONN_ERR
Definition network.c:86
#define SOCK_ERR
Definition network.c:85
PHPAPI int php_network_get_sock_name(php_socket_t sock, zend_string **textaddr, struct sockaddr **addr, socklen_t *addrlen)
Definition network.c:726
PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock, zend_string **textaddr, struct sockaddr **addr, socklen_t *addrlen, struct timeval *timeout, zend_string **error_string, int *error_code, int tcp_nodelay)
Definition network.c:757
php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port, int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string, int *error_code, const char *bindto, unsigned short bindport, long sockopts)
Definition network.c:816
php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port, int socktype, long sockopts, zend_string **error_string, int *error_code)
Definition network.c:454
PHPAPI int php_network_get_peer_name(php_socket_t sock, zend_string **textaddr, struct sockaddr **addr, socklen_t *addrlen)
Definition network.c:706
#define INT_MAX
Definition php.h:237
#define PHPAPI
Definition php.h:71
PHP_JSON_API size_t int options
Definition php_json.h:102
struct _php_netstream_data_t php_netstream_data_t
#define STREAM_SOCKOP_IPV6_V6ONLY
const php_stream_ops php_stream_generic_socket_ops
Definition xp_socket.c:532
#define shutdown(s, n)
Definition php_network.h:30
#define EWOULDBLOCK
Definition php_network.h:47
#define SHUT_RDWR
Definition php_network.h:88
#define STREAM_SOCKOP_IPV6_V6ONLY_ENABLED
#define STREAM_SOCKOP_TCP_NODELAY
#define POLLOUT
#define STREAM_SOCKOP_SO_BROADCAST
#define PHP_POLLREADABLE
PHPAPI const php_stream_ops php_stream_socket_ops
Definition xp_socket.c:543
#define STREAM_SOCKOP_NONE
#define POLLPRI
#define php_socket_errno()
Definition php_network.h:60
#define PHP_IS_TRANSIENT_ERROR(err)
Definition php_network.h:54
#define SHUT_WR
Definition php_network.h:87
int php_socket_t
#define SHUT_RD
Definition php_network.h:86
#define STREAM_SOCKOP_SO_REUSEPORT
#define closesocket
Definition php_network.h:24
#define php_stream_notify_progress_increment(context, dsofar, dmax)
PHPAPI zval * php_stream_context_get_option(php_stream_context *context, const char *wrappername, const char *optionname)
Definition streams.c:2407
PHPAPI php_stream_transport_factory_func php_stream_generic_socket_factory
struct _php_stream_xport_param php_stream_xport_param
@ STREAM_PEEK
struct _php_stream php_stream
Definition php_streams.h:96
struct _php_stream_context php_stream_context
Definition php_streams.h:98
#define PHP_STREAM_OPTION_BLOCKING
#define PHP_STREAM_AS_FD_FOR_SELECT
#define STREAMS_DC
Definition php_streams.h:53
#define STREAMS_CC
Definition php_streams.h:54
#define php_stream_alloc_rel(ops, thisptr, persistent, mode)
Definition php_streams.h:60
#define PHP_STREAM_OPTION_XPORT_API
#define PHP_STREAM_FLAG_NO_IO
#define PHP_STREAM_OPTION_RETURN_NOTIMPL
#define PHP_STREAM_FLAG_SUPPRESS_ERRORS
#define PHP_STREAM_CONTEXT(stream)
#define php_stream_is_persistent(stream)
#define PHP_STREAM_OPTION_READ_TIMEOUT
struct _php_stream_ops php_stream_ops
#define PHP_STREAM_OPTION_META_DATA_API
#define PHP_STREAM_OPTION_RETURN_ERR
#define PHP_STREAM_OPTION_CHECK_LIVENESS
#define PHP_STREAM_AS_SOCKETD
#define PHP_STREAM_OPTION_RETURN_OK
#define PHP_STREAM_AS_FD
#define PHP_STREAM_AS_STDIO
struct _php_stream_statbuf php_stream_statbuf
struct timeval tv
Definition session.c:1280
p
Definition session.c:1105
const MSG_OOB
const SOCK_STREAM
const AF_UNIX
const SOCK_DGRAM
#define strpprintf
Definition spprintf.h:30
#define FG(v)
Definition file.h:117
struct timeval timeout
struct _php_stream_xport_param::@015355061030136034370173273234023140274215071026 inputs
struct _php_stream_xport_param::@000113327003134033162122300162113175151127354335 outputs
enum _php_stream_xport_param::@374135164235347147303334377011004260152245232316 op
const php_stream_ops * ops
uint16_t eof
uint32_t flags
zend_resource * ctx
uint16_t has_buffered_data
void * abstract
char mode[16]
Definition dce.c:49
#define EINPROGRESS
#define errno
#define EMSGSIZE
#define EAGAIN
#define MSG_PEEK
Definition xp_socket.c:35
#define MSG_DONTWAIT
Definition xp_socket.c:31
#define XP_SOCK_BUF_SIZE(sz)
Definition xp_socket.c:42
#define estrndup(s, length)
Definition zend_alloc.h:165
#define efree(ptr)
Definition zend_alloc.h:155
#define pefree(ptr, persistent)
Definition zend_alloc.h:191
#define pemalloc(size, persistent)
Definition zend_alloc.h:189
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
strncmp(string $string1, string $string2, int $length)
#define E_NOTICE
Definition zend_errors.h:26
#define E_WARNING
Definition zend_errors.h:24
int32_t zend_long
Definition zend_long.h:42
#define ZEND_LONG_FMT
Definition zend_long.h:87
struct _zend_string zend_string
ZEND_API bool ZEND_FASTCALL zend_is_true(const zval *op)
#define XtOffsetOf(s_type, field)
#define zend_fstat
Definition zend_stream.h:98
#define ZSTR_EMPTY_ALLOC()
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define IS_STRING
Definition zend_types.h:606
#define GC_ADDREF(p)
Definition zend_types.h:709
#define Z_STRLEN_P(zval_p)
Definition zend_types.h:978
#define IS_NULL
Definition zend_types.h:601
@ FAILURE
Definition zend_types.h:61
zval retval
zval * ret
value
out($f, $s)