diff options
Diffstat (limited to 'main/streams/xp_socket.c')
-rw-r--r-- | main/streams/xp_socket.c | 93 |
1 files changed, 64 insertions, 29 deletions
diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c index 13ed703682..cc76ace510 100644 --- a/main/streams/xp_socket.c +++ b/main/streams/xp_socket.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2015 The PHP Group | + | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -77,10 +77,10 @@ retry: didwrite = send(sock->socket, buf, XP_SOCK_BUF_SIZE(count), (sock->is_blocked && ptimeout) ? MSG_DONTWAIT : 0); if (didwrite <= 0) { - long err = php_socket_errno(); + int err = php_socket_errno(); char *estr; - if (sock->is_blocked && err == EWOULDBLOCK) { + if (sock->is_blocked && (err == EWOULDBLOCK || err == EAGAIN)) { int retval; sock->timeout_event = 0; @@ -152,6 +152,7 @@ static size_t php_sockop_read(php_stream *stream, char *buf, size_t count) { php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract; ssize_t nr_bytes = 0; + int err; if (!sock || sock->socket == -1) { return 0; @@ -164,8 +165,9 @@ static size_t php_sockop_read(php_stream *stream, char *buf, size_t count) } nr_bytes = recv(sock->socket, buf, XP_SOCK_BUF_SIZE(count), (sock->is_blocked && sock->timeout.tv_sec != -1) ? MSG_DONTWAIT : 0); + err = php_socket_errno(); - stream->eof = (nr_bytes == 0 || (nr_bytes == -1 && php_socket_errno() != EWOULDBLOCK)); + stream->eof = (nr_bytes == 0 || (nr_bytes == -1 && err != EWOULDBLOCK && err != EAGAIN)); if (nr_bytes > 0) { php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), nr_bytes, 0); @@ -314,7 +316,17 @@ static int php_sockop_set_option(php_stream *stream, int option, int value, void if (sock->socket == -1) { alive = 0; } else if (php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) { - if (0 >= recv(sock->socket, &buf, sizeof(buf), MSG_PEEK) && php_socket_errno() != EWOULDBLOCK) { +#ifdef PHP_WIN32 + int ret; +#else + ssize_t ret; +#endif + int err; + + ret = recv(sock->socket, &buf, sizeof(buf), MSG_PEEK); + err = php_socket_errno(); + if (0 == ret || /* the counterpart did properly shutdown*/ + (0 > ret && err != EWOULDBLOCK && err != EAGAIN)) { /* there was an unrecoverable error */ alive = 0; } } @@ -623,6 +635,16 @@ static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t * return -1; } +#ifdef IPV6_V6ONLY + if (PHP_STREAM_CONTEXT(stream) + && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "ipv6_v6only")) != NULL + && Z_TYPE_P(tmpzval) != IS_NULL + ) { + sockopts |= STREAM_SOCKOP_IPV6_V6ONLY; + sockopts |= STREAM_SOCKOP_IPV6_V6ONLY_ENABLED * zend_is_true(tmpzval); + } +#endif + #ifdef SO_REUSEPORT if (PHP_STREAM_CONTEXT(stream) && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "so_reuseport")) != NULL @@ -720,6 +742,18 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_ } #endif + if (stream->ops != &php_stream_udp_socket_ops /* TCP_NODELAY is only applicable for TCP */ +#ifdef AF_UNIX + && stream->ops != &php_stream_unix_socket_ops + && stream->ops != &php_stream_unixdg_socket_ops +#endif + && PHP_STREAM_CONTEXT(stream) + && (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay")) != NULL + && zend_is_true(tmpzval) + ) { + sockopts |= STREAM_SOCKOP_TCP_NODELAY; + } + /* Note: the test here for php_stream_udp_socket_ops is important, because we * want the default to be TCP sockets so that the openssl extension can * re-use this code. */ @@ -761,36 +795,37 @@ static inline int php_tcp_sockop_accept(php_stream *stream, php_netstream_data_t php_stream_xport_param *xparam STREAMS_DC) { int clisock; + zend_bool nodelay = 0; + zval *tmpzval = NULL; xparam->outputs.client = NULL; + if ((NULL != PHP_STREAM_CONTEXT(stream)) && + (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay")) != NULL && + zend_is_true(tmpzval)) { + nodelay = 1; + } + clisock = php_network_accept_incoming(sock->socket, - xparam->want_textaddr ? &xparam->outputs.textaddr : NULL, - xparam->want_addr ? &xparam->outputs.addr : NULL, - xparam->want_addr ? &xparam->outputs.addrlen : NULL, - xparam->inputs.timeout, - xparam->want_errortext ? &xparam->outputs.error_text : NULL, - &xparam->outputs.error_code - ); + xparam->want_textaddr ? &xparam->outputs.textaddr : NULL, + xparam->want_addr ? &xparam->outputs.addr : NULL, + xparam->want_addr ? &xparam->outputs.addrlen : NULL, + xparam->inputs.timeout, + xparam->want_errortext ? &xparam->outputs.error_text : NULL, + &xparam->outputs.error_code, + nodelay); if (clisock >= 0) { - php_netstream_data_t *clisockdata; - - clisockdata = emalloc(sizeof(*clisockdata)); - - if (clisockdata == NULL) { - close(clisock); - /* technically a fatal error */ - } else { - memcpy(clisockdata, sock, sizeof(*clisockdata)); - clisockdata->socket = clisock; - - xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+"); - if (xparam->outputs.client) { - xparam->outputs.client->ctx = stream->ctx; - if (stream->ctx) { - GC_REFCOUNT(stream->ctx)++; - } + php_netstream_data_t *clisockdata = (php_netstream_data_t*) emalloc(sizeof(*clisockdata)); + + memcpy(clisockdata, sock, sizeof(*clisockdata)); + clisockdata->socket = clisock; + + xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+"); + if (xparam->outputs.client) { + xparam->outputs.client->ctx = stream->ctx; + if (stream->ctx) { + GC_REFCOUNT(stream->ctx)++; } } } |