diff options
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | ext/standard/tests/streams/bug79000.phpt | 19 | ||||
-rw-r--r-- | main/streams/xp_socket.c | 40 |
3 files changed, 46 insertions, 17 deletions
@@ -28,6 +28,10 @@ PHP NEWS - Spl: . Fixed bug #78976 (SplFileObject::fputcsv returns -1 on failure). (cmb) +- Standard: + . Fixed bug #79000 (Non-blocking socket stream reports EAGAIN as error). + (Nikita) + 18 Dec 2019, PHP 7.4.1 - Core: diff --git a/ext/standard/tests/streams/bug79000.phpt b/ext/standard/tests/streams/bug79000.phpt new file mode 100644 index 0000000000..f2209f2570 --- /dev/null +++ b/ext/standard/tests/streams/bug79000.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #79000: Non-blocking socket stream reports EAGAIN as error +--SKIPIF-- +<?php +if (PHP_OS_FAMILY == 'Windows') die('skip Not for Windows'); +?> +--FILE-- +<?php + +[$sock1, $sock2] = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP); +$str = str_repeat('a', 1000000); +stream_set_blocking($sock1, false); +var_dump(fwrite($sock1, $str)); +var_dump(fwrite($sock1, $str)); + +?> +--EXPECTF-- +int(%d) +int(%d) diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c index 511e1570d1..56fc4fcd4f 100644 --- a/main/streams/xp_socket.c +++ b/main/streams/xp_socket.c @@ -75,30 +75,36 @@ retry: didwrite = send(sock->socket, buf, XP_SOCK_BUF_SIZE(count), (sock->is_blocked && ptimeout) ? MSG_DONTWAIT : 0); if (didwrite <= 0) { - int err = php_socket_errno(); char *estr; + int err = php_socket_errno(); + if (err == EWOULDBLOCK || err == EAGAIN) { + if (sock->is_blocked) { + int retval; - if (sock->is_blocked && (err == EWOULDBLOCK || err == EAGAIN)) { - int retval; - - sock->timeout_event = 0; + sock->timeout_event = 0; - do { - retval = php_pollfd_for(sock->socket, POLLOUT, ptimeout); + do { + retval = php_pollfd_for(sock->socket, POLLOUT, ptimeout); - if (retval == 0) { - sock->timeout_event = 1; - break; - } + if (retval == 0) { + sock->timeout_event = 1; + break; + } - if (retval > 0) { - /* writable now; retry */ - goto retry; - } + if (retval > 0) { + /* writable now; retry */ + goto retry; + } - err = php_socket_errno(); - } while (err == EINTR); + err = php_socket_errno(); + } while (err == EINTR); + } else { + /* EWOULDBLOCK/EAGAIN is not an error for a non-blocking stream. + * Report zero byte write instead. */ + return 0; + } } + estr = php_socket_strerror(err, NULL, 0); php_error_docref(NULL, E_NOTICE, "send of " ZEND_LONG_FMT " bytes failed with errno=%d %s", (zend_long)count, err, estr); |