Jacek Caban : winhttp: Added schannel-based netconn_recv implementation.

Alexandre Julliard julliard at winehq.org
Thu Jan 24 12:59:48 CST 2013


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

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Wed Jan 23 15:49:29 2013 +0100

winhttp: Added schannel-based netconn_recv implementation.

---

 dlls/secur32/schannel.c        |    2 +-
 dlls/winhttp/net.c             |  148 +++++++++++++++++++++++++++++++++++++++-
 dlls/winhttp/winhttp_private.h |    1 +
 3 files changed, 148 insertions(+), 3 deletions(-)

diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c
index 37af15e..bf64fcd 100644
--- a/dlls/secur32/schannel.c
+++ b/dlls/secur32/schannel.c
@@ -1134,7 +1134,7 @@ static SECURITY_STATUS SEC_ENTRY schan_DecryptMessage(PCtxtHandle context_handle
         if (status != SEC_E_OK)
         {
             HeapFree(GetProcessHeap(), 0, data);
-            ERR("Returning %d\n", status);
+            ERR("Returning %x\n", status);
             return status;
         }
 
diff --git a/dlls/winhttp/net.c b/dlls/winhttp/net.c
index 5581a6f..664bef7 100644
--- a/dlls/winhttp/net.c
+++ b/dlls/winhttp/net.c
@@ -666,6 +666,8 @@ BOOL netconn_close( netconn_t *conn )
 
         conn->ssl_conn = NULL;
 #else
+        heap_free(conn->ssl_buf);
+        conn->ssl_buf = NULL;
         heap_free(conn->extra_buf);
         conn->extra_buf = NULL;
         conn->extra_len = 0;
@@ -880,12 +882,20 @@ fail:
                 WARN("Could not get cert\n");
                 break;
             }
+
+            conn->ssl_buf = heap_alloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer);
+            if(!conn->ssl_buf) {
+                res = GetLastError();
+                break;
+            }
         }
     }
 
 
     if(status != SEC_E_OK || res != ERROR_SUCCESS) {
         WARN("Failed to initialize security context failed: %08x\n", status);
+        heap_free(conn->ssl_buf);
+        conn->ssl_buf = NULL;
         DeleteSecurityContext(&ctx);
         set_last_error(res ? res : ERROR_WINHTTP_SECURE_CHANNEL_ERROR);
         return FALSE;
@@ -921,6 +931,103 @@ BOOL netconn_send( netconn_t *conn, const void *msg, size_t len, int flags, int
     return TRUE;
 }
 
+#ifndef SONAME_LIBSSL
+
+static BOOL read_ssl_chunk(netconn_t *conn, void *buf, SIZE_T buf_size, 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;
+    int i;
+    SECURITY_STATUS res;
+
+    assert(conn->extra_len < ssl_buf_size);
+
+    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;
+        }
+
+        if(!buf_len) {
+            *eof = TRUE;
+            return TRUE;
+        }
+    }
+
+    *ret_size = 0;
+    *eof = FALSE;
+
+    do {
+        memset(bufs, 0, sizeof(bufs));
+        bufs[0].BufferType = SECBUFFER_DATA;
+        bufs[0].cbBuffer = buf_len;
+        bufs[0].pvBuffer = conn->ssl_buf;
+
+        res = DecryptMessage(&conn->ssl_ctx, &buf_desc, 0, NULL);
+        switch(res) {
+        case SEC_E_OK:
+            break;
+        case SEC_I_CONTEXT_EXPIRED:
+            TRACE("context expired\n");
+            *eof = TRUE;
+            return TRUE;
+        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;
+
+            buf_len += size;
+            continue;
+        default:
+            WARN("failed: %08x\n", res);
+            return FALSE;
+        }
+    } while(res != SEC_E_OK);
+
+    for(i=0; i < sizeof(bufs)/sizeof(*bufs); i++) {
+        if(bufs[i].BufferType == SECBUFFER_DATA) {
+            size = min(buf_size, bufs[i].cbBuffer);
+            memcpy(buf, bufs[i].pvBuffer, size);
+            if(size < bufs[i].cbBuffer) {
+                assert(!conn->peek_len);
+                conn->peek_msg_mem = conn->peek_msg = heap_alloc(bufs[i].cbBuffer - size);
+                if(!conn->peek_msg)
+                    return FALSE;
+                conn->peek_len = bufs[i].cbBuffer-size;
+                memcpy(conn->peek_msg, (char*)bufs[i].pvBuffer+size, conn->peek_len);
+            }
+
+            *ret_size = size;
+        }
+    }
+
+    for(i=0; i < sizeof(bufs)/sizeof(*bufs); i++) {
+        if(bufs[i].BufferType == SECBUFFER_EXTRA) {
+            conn->extra_buf = heap_alloc(bufs[i].cbBuffer);
+            if(!conn->extra_buf)
+                return FALSE;
+
+            conn->extra_len = bufs[i].cbBuffer;
+            memcpy(conn->extra_buf, bufs[i].pvBuffer, conn->extra_len);
+        }
+    }
+
+    return TRUE;
+}
+
+#endif
+
 BOOL netconn_recv( netconn_t *conn, void *buf, size_t len, int flags, int *recvd )
 {
     *recvd = 0;
@@ -931,16 +1038,23 @@ BOOL netconn_recv( netconn_t *conn, void *buf, size_t len, int flags, int *recvd
     {
 #ifdef SONAME_LIBSSL
         int ret;
+#else
+        SIZE_T size, cread;
+        BOOL res, eof;
+#endif
 
         if (flags & ~(MSG_PEEK | MSG_WAITALL))
             FIXME("SSL_read does not support the following flags: %08x\n", flags);
 
+#ifdef SONAME_LIBSSL
         /* this ugly hack is all for MSG_PEEK */
         if (flags & MSG_PEEK && !conn->peek_msg)
         {
             if (!(conn->peek_msg = conn->peek_msg_mem = heap_alloc( len + 1 ))) return FALSE;
         }
-        else if (flags & MSG_PEEK && conn->peek_msg)
+        else
+#endif
+        if (flags & MSG_PEEK && conn->peek_msg)
         {
             if (len < conn->peek_len) FIXME("buffer isn't big enough, should we wrap?\n");
             *recvd = min( len, conn->peek_len );
@@ -963,6 +1077,7 @@ BOOL netconn_recv( netconn_t *conn, void *buf, size_t len, int flags, int *recvd
             /* check if we have enough data from the peek buffer */
             if (!(flags & MSG_WAITALL) || (*recvd == len)) return TRUE;
         }
+#ifdef SONAME_LIBSSL
         ret = pSSL_read( conn->ssl_conn, (char *)buf + *recvd, len - *recvd );
         if (ret < 0)
             return FALSE;
@@ -988,7 +1103,36 @@ BOOL netconn_recv( netconn_t *conn, void *buf, size_t len, int flags, int *recvd
         *recvd += ret;
         return TRUE;
 #else
-        return FALSE;
+        size = *recvd;
+
+        do {
+            res = read_ssl_chunk(conn, (BYTE*)buf+size, len-size, &cread, &eof);
+            if(!res) {
+                WARN("read_ssl_chunk failed\n");
+                if(!size)
+                    return FALSE;
+                break;
+            }
+
+            if(eof) {
+                TRACE("EOF\n");
+                break;
+            }
+
+            size += cread;
+        }while(!size || ((flags & MSG_WAITALL) && size < len));
+
+        if(size && (flags & MSG_PEEK)) {
+            conn->peek_msg_mem = conn->peek_msg = heap_alloc(size);
+            if(!conn->peek_msg)
+                return FALSE;
+
+            memcpy(conn->peek_msg, buf, size);
+        }
+
+        TRACE("received %ld bytes\n", size);
+        *recvd = size;
+        return TRUE;
 #endif
     }
     if ((*recvd = recv( conn->socket, buf, len, flags )) == -1)
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h
index c5ac903..b24fbd1 100644
--- a/dlls/winhttp/winhttp_private.h
+++ b/dlls/winhttp/winhttp_private.h
@@ -132,6 +132,7 @@ typedef struct
     void *ssl_conn;
     CtxtHandle ssl_ctx;
     SecPkgContext_StreamSizes ssl_sizes;
+    char *ssl_buf;
     char *extra_buf;
     size_t extra_len;
     char *peek_msg;




More information about the wine-cvs mailing list