Jacek Caban : wininet: Improved non-blocking mode in secure NETCON_recv.

Alexandre Julliard julliard at winehq.org
Wed Mar 5 14:12:31 CST 2014


Module: wine
Branch: master
Commit: d8948da1b4ede8f9425b8e42c3307a7eda273268
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=d8948da1b4ede8f9425b8e42c3307a7eda273268

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Wed Mar  5 18:27:53 2014 +0100

wininet: Improved non-blocking mode in secure NETCON_recv.

---

 dlls/wininet/netconnection.c |  102 ++++++++++++++++++++++++++++--------------
 1 file changed, 69 insertions(+), 33 deletions(-)

diff --git a/dlls/wininet/netconnection.c b/dlls/wininet/netconnection.c
index 4c97924..fa07a9b 100644
--- a/dlls/wininet/netconnection.c
+++ b/dlls/wininet/netconnection.c
@@ -86,6 +86,11 @@
 
 #define RESPONSE_TIMEOUT        30            /* FROM internet.c */
 
+#ifdef MSG_DONTWAIT
+#define WINE_MSG_DONTWAIT MSG_DONTWAIT
+#else
+#define WINE_MSG_DONTWAIT 0
+#endif
 
 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
 
@@ -755,37 +760,53 @@ DWORD NETCON_send(netconn_t *connection, const void *msg, size_t len, int flags,
     }
 }
 
-static BOOL read_ssl_chunk(netconn_t *conn, void *buf, SIZE_T buf_size, SIZE_T *ret_size, BOOL *eof)
+static BOOL read_ssl_chunk(netconn_t *conn, void *buf, SIZE_T buf_size, blocking_mode_t mode, SIZE_T *ret_size, BOOL *eof)
 {
     const SIZE_T ssl_buf_size = conn->ssl_sizes.cbHeader+conn->ssl_sizes.cbMaximumMessage+conn->ssl_sizes.cbTrailer;
     SecBuffer bufs[4];
     SecBufferDesc buf_desc = {SECBUFFER_VERSION, sizeof(bufs)/sizeof(*bufs), bufs};
-    SSIZE_T size, buf_len;
+    SSIZE_T size, buf_len = 0;
+    blocking_mode_t tmp_mode;
     int i;
     SECURITY_STATUS res;
 
     assert(conn->extra_len < ssl_buf_size);
 
+    /* BLOCKING_WAITALL is handled by caller */
+    if(mode == BLOCKING_WAITALL)
+        mode = BLOCKING_ALLOW;
+
     if(conn->extra_len) {
         memcpy(conn->ssl_buf, conn->extra_buf, conn->extra_len);
         buf_len = conn->extra_len;
         conn->extra_len = 0;
         heap_free(conn->extra_buf);
         conn->extra_buf = NULL;
-    }else {
-        buf_len = recv(conn->socket, conn->ssl_buf+conn->extra_len, ssl_buf_size-conn->extra_len, 0);
-        if(buf_len < 0) {
-            WARN("recv failed\n");
-            return FALSE;
-        }
+    }
 
+    tmp_mode = buf_len ? BLOCKING_DISALLOW : mode;
+    set_socket_blocking(conn->socket, tmp_mode);
+    size = recv(conn->socket, conn->ssl_buf+buf_len, ssl_buf_size-buf_len, tmp_mode == BLOCKING_ALLOW ? 0 : WINE_MSG_DONTWAIT);
+    if(size < 0) {
         if(!buf_len) {
-            *eof = TRUE;
-            return TRUE;
+            if(errno == EAGAIN || errno == EWOULDBLOCK) {
+                TRACE("would block\n");
+                return WSAEWOULDBLOCK;
+            }
+            WARN("recv failed\n");
+            return ERROR_INTERNET_CONNECTION_ABORTED;
         }
+    }else {
+        buf_len += size;
+    }
+
+    *ret_size = buf_len;
+
+    if(!buf_len) {
+        *eof = TRUE;
+        return ERROR_SUCCESS;
     }
 
-    *ret_size = 0;
     *eof = FALSE;
 
     do {
@@ -801,19 +822,34 @@ static BOOL read_ssl_chunk(netconn_t *conn, void *buf, SIZE_T buf_size, SIZE_T *
         case SEC_I_CONTEXT_EXPIRED:
             TRACE("context expired\n");
             *eof = TRUE;
-            return TRUE;
+            return ERROR_SUCCESS;
         case SEC_E_INCOMPLETE_MESSAGE:
             assert(buf_len < ssl_buf_size);
 
-            size = recv(conn->socket, conn->ssl_buf+buf_len, ssl_buf_size-buf_len, 0);
-            if(size < 1)
-                return FALSE;
+            set_socket_blocking(conn->socket, mode);
+            size = recv(conn->socket, conn->ssl_buf+buf_len, ssl_buf_size-buf_len, mode == BLOCKING_ALLOW ? 0 : WINE_MSG_DONTWAIT);
+            if(size < 1) {
+                if(size < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+                    TRACE("would block\n");
+
+                    /* FIXME: Optimize extra_buf usage. */
+                    conn->extra_buf = heap_alloc(buf_len);
+                    if(!conn->extra_buf)
+                        return ERROR_NOT_ENOUGH_MEMORY;
+
+                    conn->extra_len = buf_len;
+                    memcpy(conn->extra_buf, conn->ssl_buf, conn->extra_len);
+                    return WSAEWOULDBLOCK;
+                }
+
+                return ERROR_INTERNET_CONNECTION_ABORTED;
+            }
 
             buf_len += size;
             continue;
         default:
             WARN("failed: %08x\n", res);
-            return FALSE;
+            return ERROR_INTERNET_CONNECTION_ABORTED;
         }
     } while(res != SEC_E_OK);
 
@@ -825,7 +861,7 @@ static BOOL read_ssl_chunk(netconn_t *conn, void *buf, SIZE_T buf_size, SIZE_T *
                 assert(!conn->peek_len);
                 conn->peek_msg_mem = conn->peek_msg = heap_alloc(bufs[i].cbBuffer - size);
                 if(!conn->peek_msg)
-                    return FALSE;
+                    return ERROR_NOT_ENOUGH_MEMORY;
                 conn->peek_len = bufs[i].cbBuffer-size;
                 memcpy(conn->peek_msg, (char*)bufs[i].pvBuffer+size, conn->peek_len);
             }
@@ -838,14 +874,14 @@ static BOOL read_ssl_chunk(netconn_t *conn, void *buf, SIZE_T buf_size, SIZE_T *
         if(bufs[i].BufferType == SECBUFFER_EXTRA) {
             conn->extra_buf = heap_alloc(bufs[i].cbBuffer);
             if(!conn->extra_buf)
-                return FALSE;
+                return ERROR_NOT_ENOUGH_MEMORY;
 
             conn->extra_len = bufs[i].cbBuffer;
             memcpy(conn->extra_buf, bufs[i].pvBuffer, conn->extra_len);
         }
     }
 
-    return TRUE;
+    return ERROR_SUCCESS;
 }
 
 /******************************************************************************
@@ -867,9 +903,7 @@ DWORD NETCON_recv(netconn_t *connection, void *buf, size_t len, blocking_mode_t
         case BLOCKING_ALLOW:
             break;
         case BLOCKING_DISALLOW:
-#ifdef MSG_DONTWAIT
-            flags = MSG_DONTWAIT;
-#endif
+            flags = WINE_MSG_DONTWAIT;
             break;
         case BLOCKING_WAITALL:
             flags = MSG_WAITALL;
@@ -883,7 +917,8 @@ DWORD NETCON_recv(netconn_t *connection, void *buf, size_t len, blocking_mode_t
     else
     {
         SIZE_T size = 0, cread;
-        BOOL res, eof;
+        BOOL eof;
+        DWORD res;
 
         if(connection->peek_msg) {
             size = min(len, connection->peek_len);
@@ -900,18 +935,19 @@ DWORD NETCON_recv(netconn_t *connection, void *buf, size_t len, blocking_mode_t
                 *recvd = size;
                 return ERROR_SUCCESS;
             }
-        }
 
-        if(mode == BLOCKING_DISALLOW)
-            return WSAEWOULDBLOCK; /* FIXME: We can do better */
-        set_socket_blocking(connection->socket, BLOCKING_ALLOW);
+            mode = BLOCKING_DISALLOW;
+        }
 
         do {
-            res = read_ssl_chunk(connection, (BYTE*)buf+size, len-size, &cread, &eof);
-            if(!res) {
-                WARN("read_ssl_chunk failed\n");
-                if(!size)
-                    return ERROR_INTERNET_CONNECTION_ABORTED;
+            res = read_ssl_chunk(connection, (BYTE*)buf+size, len-size, mode, &cread, &eof);
+            if(res != ERROR_SUCCESS) {
+                if(res == WSAEWOULDBLOCK) {
+                    if(size)
+                        res = ERROR_SUCCESS;
+                }else {
+                    WARN("read_ssl_chunk failed\n");
+                }
                 break;
             }
 
@@ -925,7 +961,7 @@ DWORD NETCON_recv(netconn_t *connection, void *buf, size_t len, blocking_mode_t
 
         TRACE("received %ld bytes\n", size);
         *recvd = size;
-        return ERROR_SUCCESS;
+        return res;
     }
 }
 




More information about the wine-cvs mailing list