summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--ext/standard/tests/streams/bug79000.phpt19
-rw-r--r--main/streams/xp_socket.c40
3 files changed, 46 insertions, 17 deletions
diff --git a/NEWS b/NEWS
index 47e4e05b6a..4fb147ffa5 100644
--- a/NEWS
+++ b/NEWS
@@ -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);