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