diff --git a/ext/standard/tests/streams/bug79000.phpt b/ext/standard/tests/streams/bug79000.phpt new file mode 100644 index 0000000000000..f2209f257085d --- /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-- + +--FILE-- + +--EXPECTF-- +int(%d) +int(%d) diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c index 511e1570d11ee..56fc4fcd4fa32 100644 --- a/main/streams/xp_socket.c +++ b/main/streams/xp_socket.c @@ -75,30 +75,36 @@ static ssize_t php_sockop_write(php_stream *stream, const char *buf, size_t coun 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);