s3:smbd: let default_sys_recvfile() and sys_recvfile() cope with non-blocking sockets.
[samba.git] / source3 / lib / recvfile.c
index 500a7e43399f003bc7f60bd1de41ba35037dd50f..bffe07f75cd4c54fdcc79649f8f8dc8a5926b4ef 100644 (file)
@@ -75,8 +75,33 @@ static ssize_t default_sys_recvfile(int fromfd,
                ssize_t read_ret;
                size_t toread = MIN(bufsize,count - total);
 
-               /* Read from socket - ignore EINTR. */
-               read_ret = sys_read(fromfd, buffer, toread);
+               /*
+                * Read from socket - ignore EINTR.
+                * Can't use sys_read() as that also
+                * ignores EAGAIN and EWOULDBLOCK.
+                */
+               do {
+                       read_ret = read(fromfd, buffer, toread);
+               } while (read_ret == -1 && errno == EINTR);
+
+#if defined(EWOULDBLOCK)
+               if (read_ret == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+#else
+               if (read_ret == -1 && (errno == EAGAIN)) {
+#endif
+                       /*
+                        * fromfd socket is in non-blocking mode.
+                        * If we already read some and wrote
+                        * it successfully, return that.
+                        * Only return -1 if this is the first read
+                        * attempt. Caller will handle both cases.
+                        */
+                       if (total_written != 0) {
+                               return total_written;
+                       }
+                       return -1;
+               }
+
                if (read_ret <= 0) {
                        /* EOF or socket error. */
                        return -1;
@@ -184,6 +209,23 @@ ssize_t sys_recvfile(int fromfd,
                                return default_sys_recvfile(fromfd, tofd,
                                                            offset, count);
                        }
+#if defined(EWOULDBLOCK)
+                       if (errno == EAGAIN || errno == EWOULDBLOCK) {
+#else
+                       if (errno == EAGAIN) {
+#endif
+                               /*
+                                * fromfd socket is in non-blocking mode.
+                                * If we already read some and wrote
+                                * it successfully, return that.
+                                * Only return -1 if this is the first read
+                                * attempt. Caller will handle both cases.
+                                */
+                               if (total_written != 0) {
+                                       return total_written;
+                               }
+                               return -1;
+                       }
                        break;
                }