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