winhttp: Allow synchronous nonblocking send in WinHttpWebSocketSend() when possible.
Signed-off-by: Paul Gofman <pgofman@codeweavers.com> Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
ad5d011f58
commit
9ef1e44914
|
@ -32,15 +32,23 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
|
WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
|
||||||
|
|
||||||
static int sock_send(int fd, const void *msg, size_t len, int flags)
|
static int sock_send(int fd, const void *msg, size_t len, WSAOVERLAPPED *ovr)
|
||||||
{
|
{
|
||||||
int ret;
|
WSABUF wsabuf;
|
||||||
do
|
DWORD size;
|
||||||
|
DWORD err;
|
||||||
|
|
||||||
|
wsabuf.len = len;
|
||||||
|
wsabuf.buf = (void *)msg;
|
||||||
|
|
||||||
|
if (!WSASend( (SOCKET)fd, &wsabuf, 1, &size, 0, ovr, NULL ))
|
||||||
{
|
{
|
||||||
if ((ret = send(fd, msg, len, flags)) == -1) WARN("send error %u\n", WSAGetLastError());
|
assert( size == len );
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
while(ret == -1 && WSAGetLastError() == WSAEINTR);
|
err = WSAGetLastError();
|
||||||
return ret;
|
if (!(ovr && err == WSA_IO_PENDING)) WARN( "send error %u\n", err );
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sock_recv(int fd, void *msg, size_t len, int flags)
|
static int sock_recv(int fd, void *msg, size_t len, int flags)
|
||||||
|
@ -190,7 +198,7 @@ DWORD netconn_create( struct hostdata *host, const struct sockaddr_storage *sock
|
||||||
if (!(conn = calloc( 1, sizeof(*conn) ))) return ERROR_OUTOFMEMORY;
|
if (!(conn = calloc( 1, sizeof(*conn) ))) return ERROR_OUTOFMEMORY;
|
||||||
conn->host = host;
|
conn->host = host;
|
||||||
conn->sockaddr = *sockaddr;
|
conn->sockaddr = *sockaddr;
|
||||||
if ((conn->socket = socket( sockaddr->ss_family, SOCK_STREAM, 0 )) == -1)
|
if ((conn->socket = WSASocketW( sockaddr->ss_family, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED )) == -1)
|
||||||
{
|
{
|
||||||
ret = WSAGetLastError();
|
ret = WSAGetLastError();
|
||||||
WARN("unable to create socket (%u)\n", ret);
|
WARN("unable to create socket (%u)\n", ret);
|
||||||
|
@ -290,7 +298,7 @@ DWORD netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD secur
|
||||||
|
|
||||||
TRACE("sending %u bytes\n", out_buf.cbBuffer);
|
TRACE("sending %u bytes\n", out_buf.cbBuffer);
|
||||||
|
|
||||||
size = sock_send(conn->socket, out_buf.pvBuffer, out_buf.cbBuffer, 0);
|
size = sock_send(conn->socket, out_buf.pvBuffer, out_buf.cbBuffer, NULL);
|
||||||
if(size != out_buf.cbBuffer) {
|
if(size != out_buf.cbBuffer) {
|
||||||
ERR("send failed\n");
|
ERR("send failed\n");
|
||||||
res = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
|
res = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
|
||||||
|
@ -398,7 +406,7 @@ DWORD netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD secur
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD send_ssl_chunk( struct netconn *conn, const void *msg, size_t size )
|
static DWORD send_ssl_chunk( struct netconn *conn, const void *msg, size_t size, WSAOVERLAPPED *ovr )
|
||||||
{
|
{
|
||||||
SecBuffer bufs[4] = {
|
SecBuffer bufs[4] = {
|
||||||
{conn->ssl_sizes.cbHeader, SECBUFFER_STREAM_HEADER, conn->ssl_write_buf},
|
{conn->ssl_sizes.cbHeader, SECBUFFER_STREAM_HEADER, conn->ssl_write_buf},
|
||||||
|
@ -416,7 +424,8 @@ static DWORD send_ssl_chunk( struct netconn *conn, const void *msg, size_t size
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sock_send( conn->socket, conn->ssl_write_buf, bufs[0].cbBuffer + bufs[1].cbBuffer + bufs[2].cbBuffer, 0 ) < 1)
|
if (sock_send( conn->socket, conn->ssl_write_buf,
|
||||||
|
bufs[0].cbBuffer + bufs[1].cbBuffer + bufs[2].cbBuffer, ovr ) < 1)
|
||||||
{
|
{
|
||||||
WARN("send failed\n");
|
WARN("send failed\n");
|
||||||
return WSAGetLastError();
|
return WSAGetLastError();
|
||||||
|
@ -425,7 +434,7 @@ static DWORD send_ssl_chunk( struct netconn *conn, const void *msg, size_t size
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD netconn_send( struct netconn *conn, const void *msg, size_t len, int *sent )
|
DWORD netconn_send( struct netconn *conn, const void *msg, size_t len, int *sent, WSAOVERLAPPED *ovr )
|
||||||
{
|
{
|
||||||
if (conn->secure)
|
if (conn->secure)
|
||||||
{
|
{
|
||||||
|
@ -433,11 +442,13 @@ DWORD netconn_send( struct netconn *conn, const void *msg, size_t len, int *sent
|
||||||
size_t chunk_size;
|
size_t chunk_size;
|
||||||
DWORD res;
|
DWORD res;
|
||||||
|
|
||||||
|
if (ovr && len > conn->ssl_sizes.cbMaximumMessage) return WSAEWOULDBLOCK;
|
||||||
|
|
||||||
*sent = 0;
|
*sent = 0;
|
||||||
while (len)
|
while (len)
|
||||||
{
|
{
|
||||||
chunk_size = min( len, conn->ssl_sizes.cbMaximumMessage );
|
chunk_size = min( len, conn->ssl_sizes.cbMaximumMessage );
|
||||||
if ((res = send_ssl_chunk( conn, ptr, chunk_size )))
|
if ((res = send_ssl_chunk( conn, ptr, chunk_size, ovr )))
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
*sent += chunk_size;
|
*sent += chunk_size;
|
||||||
|
@ -448,7 +459,7 @@ DWORD netconn_send( struct netconn *conn, const void *msg, size_t len, int *sent
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*sent = sock_send( conn->socket, msg, len, 0 )) < 0) return WSAGetLastError();
|
if ((*sent = sock_send( conn->socket, msg, len, ovr )) < 0) return WSAGetLastError();
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1286,7 +1286,7 @@ static DWORD secure_proxy_connect( struct request *request )
|
||||||
if (!strA) return ERROR_OUTOFMEMORY;
|
if (!strA) return ERROR_OUTOFMEMORY;
|
||||||
|
|
||||||
len = strlen( strA );
|
len = strlen( strA );
|
||||||
ret = netconn_send( request->netconn, strA, len, &bytes_sent );
|
ret = netconn_send( request->netconn, strA, len, &bytes_sent, NULL );
|
||||||
free( strA );
|
free( strA );
|
||||||
if (!ret) ret = read_reply( request );
|
if (!ret) ret = read_reply( request );
|
||||||
|
|
||||||
|
@ -2138,13 +2138,13 @@ static DWORD send_request( struct request *request, const WCHAR *headers, DWORD
|
||||||
|
|
||||||
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, NULL, 0 );
|
send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST, NULL, 0 );
|
||||||
|
|
||||||
ret = netconn_send( request->netconn, wire_req, len, &bytes_sent );
|
ret = netconn_send( request->netconn, wire_req, len, &bytes_sent, NULL );
|
||||||
free( wire_req );
|
free( wire_req );
|
||||||
if (ret) goto end;
|
if (ret) goto end;
|
||||||
|
|
||||||
if (optional_len)
|
if (optional_len)
|
||||||
{
|
{
|
||||||
if ((ret = netconn_send( request->netconn, optional, optional_len, &bytes_sent ))) goto end;
|
if ((ret = netconn_send( request->netconn, optional, optional_len, &bytes_sent, NULL ))) goto end;
|
||||||
request->optional = optional;
|
request->optional = optional;
|
||||||
request->optional_len = optional_len;
|
request->optional_len = optional_len;
|
||||||
len += optional_len;
|
len += optional_len;
|
||||||
|
@ -2972,7 +2972,7 @@ static DWORD write_data( struct request *request, const void *buffer, DWORD to_w
|
||||||
DWORD ret;
|
DWORD ret;
|
||||||
int num_bytes;
|
int num_bytes;
|
||||||
|
|
||||||
ret = netconn_send( request->netconn, buffer, to_write, &num_bytes );
|
ret = netconn_send( request->netconn, buffer, to_write, &num_bytes, NULL );
|
||||||
|
|
||||||
if (async)
|
if (async)
|
||||||
{
|
{
|
||||||
|
@ -3127,11 +3127,11 @@ HINTERNET WINAPI WinHttpWebSocketCompleteUpgrade( HINTERNET hrequest, DWORD_PTR
|
||||||
return hsocket;
|
return hsocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD send_bytes( struct socket *socket, char *bytes, int len )
|
static DWORD send_bytes( struct socket *socket, char *bytes, int len, WSAOVERLAPPED *ovr )
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
DWORD err;
|
DWORD err;
|
||||||
if ((err = netconn_send( socket->request->netconn, bytes, len, &count ))) return err;
|
if ((err = netconn_send( socket->request->netconn, bytes, len, &count, ovr ))) return err;
|
||||||
return (count == len) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR;
|
return (count == len) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3141,7 +3141,7 @@ static DWORD send_bytes( struct socket *socket, char *bytes, int len )
|
||||||
#define CONTROL_BIT (1 << 3)
|
#define CONTROL_BIT (1 << 3)
|
||||||
|
|
||||||
static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHORT status, const char *buf,
|
static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHORT status, const char *buf,
|
||||||
DWORD buflen, BOOL final )
|
DWORD buflen, BOOL final, WSAOVERLAPPED *ovr )
|
||||||
{
|
{
|
||||||
DWORD i = 0, j, offset = 2, len = buflen;
|
DWORD i = 0, j, offset = 2, len = buflen;
|
||||||
DWORD buffer_size, ret = 0, send_size;
|
DWORD buffer_size, ret = 0, send_size;
|
||||||
|
@ -3177,6 +3177,7 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR
|
||||||
buffer_size = len + offset;
|
buffer_size = len + offset;
|
||||||
if (len) buffer_size += 4;
|
if (len) buffer_size += 4;
|
||||||
assert( buffer_size - len < MAX_FRAME_BUFFER_SIZE );
|
assert( buffer_size - len < MAX_FRAME_BUFFER_SIZE );
|
||||||
|
if (ovr && buffer_size > MAX_FRAME_BUFFER_SIZE) return WSAEWOULDBLOCK;
|
||||||
if (buffer_size > socket->send_frame_buffer_size && socket->send_frame_buffer_size < MAX_FRAME_BUFFER_SIZE)
|
if (buffer_size > socket->send_frame_buffer_size && socket->send_frame_buffer_size < MAX_FRAME_BUFFER_SIZE)
|
||||||
{
|
{
|
||||||
DWORD new_size;
|
DWORD new_size;
|
||||||
|
@ -3217,7 +3218,7 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR
|
||||||
while (j < buflen && offset < MAX_FRAME_BUFFER_SIZE)
|
while (j < buflen && offset < MAX_FRAME_BUFFER_SIZE)
|
||||||
socket->send_frame_buffer[offset++] = buf[j++] ^ mask[i++ % 4];
|
socket->send_frame_buffer[offset++] = buf[j++] ^ mask[i++ % 4];
|
||||||
|
|
||||||
if ((ret = send_bytes( socket, socket->send_frame_buffer, offset ))) return ret;
|
if ((ret = send_bytes( socket, socket->send_frame_buffer, offset, ovr ))) return ret;
|
||||||
|
|
||||||
if (!(send_size -= offset)) break;
|
if (!(send_size -= offset)) break;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
@ -3227,6 +3228,16 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DWORD complete_send_frame( struct socket *socket, WSAOVERLAPPED *ovr )
|
||||||
|
{
|
||||||
|
DWORD retflags, len;
|
||||||
|
|
||||||
|
if (!WSAGetOverlappedResult( socket->request->netconn->socket, ovr, &len, TRUE, &retflags ))
|
||||||
|
return WSAGetLastError();
|
||||||
|
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static void send_io_complete( struct object_header *hdr )
|
static void send_io_complete( struct object_header *hdr )
|
||||||
{
|
{
|
||||||
LONG count = InterlockedDecrement( &hdr->pending_sends );
|
LONG count = InterlockedDecrement( &hdr->pending_sends );
|
||||||
|
@ -3265,11 +3276,12 @@ static void socket_send_complete( struct socket *socket, DWORD ret, WINHTTP_WEB_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD socket_send( struct socket *socket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, const void *buf, DWORD len )
|
static DWORD socket_send( struct socket *socket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, const void *buf, DWORD len,
|
||||||
|
WSAOVERLAPPED *ovr )
|
||||||
{
|
{
|
||||||
enum socket_opcode opcode = map_buffer_type( type );
|
enum socket_opcode opcode = map_buffer_type( type );
|
||||||
|
|
||||||
return send_frame( socket, opcode, 0, buf, len, TRUE );
|
return send_frame( socket, opcode, 0, buf, len, TRUE, ovr );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CALLBACK task_socket_send( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work )
|
static void CALLBACK task_socket_send( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work )
|
||||||
|
@ -3278,7 +3290,10 @@ static void CALLBACK task_socket_send( TP_CALLBACK_INSTANCE *instance, void *ctx
|
||||||
DWORD ret;
|
DWORD ret;
|
||||||
|
|
||||||
TRACE("running %p\n", work);
|
TRACE("running %p\n", work);
|
||||||
ret = socket_send( s->socket, s->type, s->buf, s->len );
|
|
||||||
|
if (s->complete_async) ret = complete_send_frame( s->socket, &s->ovr );
|
||||||
|
else ret = socket_send( s->socket, s->type, s->buf, s->len, NULL );
|
||||||
|
|
||||||
send_io_complete( &s->socket->hdr );
|
send_io_complete( &s->socket->hdr );
|
||||||
socket_send_complete( s->socket, ret, s->type, s->len );
|
socket_send_complete( s->socket, ret, s->type, s->len );
|
||||||
|
|
||||||
|
@ -3289,7 +3304,7 @@ static void CALLBACK task_socket_send( TP_CALLBACK_INSTANCE *instance, void *ctx
|
||||||
DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, void *buf, DWORD len )
|
DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, void *buf, DWORD len )
|
||||||
{
|
{
|
||||||
struct socket *socket;
|
struct socket *socket;
|
||||||
DWORD ret;
|
DWORD ret = 0;
|
||||||
|
|
||||||
TRACE("%p, %u, %p, %u\n", hsocket, type, buf, len);
|
TRACE("%p, %u, %p, %u\n", hsocket, type, buf, len);
|
||||||
|
|
||||||
|
@ -3314,24 +3329,53 @@ DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_
|
||||||
|
|
||||||
if (socket->request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
|
if (socket->request->connect->hdr.flags & WINHTTP_FLAG_ASYNC)
|
||||||
{
|
{
|
||||||
|
BOOL async_send, complete_async = FALSE;
|
||||||
struct socket_send *s;
|
struct socket_send *s;
|
||||||
|
|
||||||
if (!(s = malloc( sizeof(*s) ))) return FALSE;
|
if (!(s = malloc( sizeof(*s) )))
|
||||||
|
{
|
||||||
|
release_object( &socket->hdr );
|
||||||
|
return ERROR_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
async_send = InterlockedIncrement( &socket->hdr.pending_sends ) > 1 || socket->hdr.recursion_count >= 3;
|
||||||
|
if (!async_send)
|
||||||
|
{
|
||||||
|
memset( &s->ovr, 0, sizeof(s->ovr) );
|
||||||
|
if ((ret = socket_send( socket, type, buf, len, &s->ovr )) == WSA_IO_PENDING)
|
||||||
|
{
|
||||||
|
async_send = TRUE;
|
||||||
|
complete_async = TRUE;
|
||||||
|
}
|
||||||
|
else if (ret == WSAEWOULDBLOCK) async_send = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (async_send)
|
||||||
|
{
|
||||||
|
s->complete_async = complete_async;
|
||||||
s->socket = socket;
|
s->socket = socket;
|
||||||
s->type = type;
|
s->type = type;
|
||||||
s->buf = buf;
|
s->buf = buf;
|
||||||
s->len = len;
|
s->len = len;
|
||||||
|
|
||||||
addref_object( &socket->hdr );
|
addref_object( &socket->hdr );
|
||||||
InterlockedIncrement( &socket->hdr.pending_sends );
|
|
||||||
if ((ret = queue_task( &socket->send_q, task_socket_send, s )))
|
if ((ret = queue_task( &socket->send_q, task_socket_send, s )))
|
||||||
{
|
{
|
||||||
InterlockedDecrement( &socket->hdr.pending_sends );
|
InterlockedDecrement( &socket->hdr.pending_sends );
|
||||||
release_object( &socket->hdr );
|
release_object( &socket->hdr );
|
||||||
free( s );
|
free( s );
|
||||||
}
|
}
|
||||||
|
else ++socket->hdr.pending_sends;
|
||||||
}
|
}
|
||||||
else ret = socket_send( socket, type, buf, len );
|
else
|
||||||
|
{
|
||||||
|
InterlockedDecrement( &socket->hdr.pending_sends );
|
||||||
|
free( s );
|
||||||
|
socket_send_complete( socket, ret, type, len );
|
||||||
|
ret = ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else ret = socket_send( socket, type, buf, len, NULL );
|
||||||
|
|
||||||
release_object( &socket->hdr );
|
release_object( &socket->hdr );
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -3418,7 +3462,7 @@ static void CALLBACK task_socket_send_pong( TP_CALLBACK_INSTANCE *instance, void
|
||||||
struct socket_send *s = ctx;
|
struct socket_send *s = ctx;
|
||||||
|
|
||||||
TRACE("running %p\n", work);
|
TRACE("running %p\n", work);
|
||||||
send_frame( s->socket, SOCKET_OPCODE_PONG, 0, NULL, 0, TRUE );
|
send_frame( s->socket, SOCKET_OPCODE_PONG, 0, NULL, 0, TRUE, NULL );
|
||||||
send_io_complete( &s->socket->hdr );
|
send_io_complete( &s->socket->hdr );
|
||||||
|
|
||||||
release_object( &s->socket->hdr );
|
release_object( &s->socket->hdr );
|
||||||
|
@ -3445,7 +3489,7 @@ static DWORD socket_send_pong( struct socket *socket )
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
return send_frame( socket, SOCKET_OPCODE_PONG, 0, NULL, 0, TRUE );
|
return send_frame( socket, SOCKET_OPCODE_PONG, 0, NULL, 0, TRUE, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD socket_drain( struct socket *socket )
|
static DWORD socket_drain( struct socket *socket )
|
||||||
|
@ -3611,7 +3655,7 @@ static DWORD socket_shutdown( struct socket *socket, USHORT status, const void *
|
||||||
DWORD ret;
|
DWORD ret;
|
||||||
|
|
||||||
stop_queue( &socket->send_q );
|
stop_queue( &socket->send_q );
|
||||||
if (!(ret = send_frame( socket, SOCKET_OPCODE_CLOSE, status, reason, len, TRUE )))
|
if (!(ret = send_frame( socket, SOCKET_OPCODE_CLOSE, status, reason, len, TRUE, NULL )))
|
||||||
{
|
{
|
||||||
socket->state = SOCKET_STATE_SHUTDOWN;
|
socket->state = SOCKET_STATE_SHUTDOWN;
|
||||||
}
|
}
|
||||||
|
@ -3697,7 +3741,7 @@ static DWORD socket_close( struct socket *socket, USHORT status, const void *rea
|
||||||
if (socket->state < SOCKET_STATE_SHUTDOWN)
|
if (socket->state < SOCKET_STATE_SHUTDOWN)
|
||||||
{
|
{
|
||||||
stop_queue( &socket->send_q );
|
stop_queue( &socket->send_q );
|
||||||
if ((ret = send_frame( socket, SOCKET_OPCODE_CLOSE, status, reason, len, TRUE ))) goto done;
|
if ((ret = send_frame( socket, SOCKET_OPCODE_CLOSE, status, reason, len, TRUE, NULL ))) goto done;
|
||||||
socket->state = SOCKET_STATE_SHUTDOWN;
|
socket->state = SOCKET_STATE_SHUTDOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@ struct notification
|
||||||
#define NF_ALLOW 0x0001 /* notification may or may not happen */
|
#define NF_ALLOW 0x0001 /* notification may or may not happen */
|
||||||
#define NF_WINE_ALLOW 0x0002 /* wine sends notification when it should not */
|
#define NF_WINE_ALLOW 0x0002 /* wine sends notification when it should not */
|
||||||
#define NF_SIGNAL 0x0004 /* signal wait handle when notified */
|
#define NF_SIGNAL 0x0004 /* signal wait handle when notified */
|
||||||
|
#define NF_MAIN_THREAD 0x0008 /* the operation completes synchronously and callback is called from the main thread */
|
||||||
|
|
||||||
struct info
|
struct info
|
||||||
{
|
{
|
||||||
|
@ -71,6 +72,7 @@ struct info
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
HANDLE wait;
|
HANDLE wait;
|
||||||
unsigned int line;
|
unsigned int line;
|
||||||
|
DWORD main_thread_id;
|
||||||
DWORD last_thread_id;
|
DWORD last_thread_id;
|
||||||
DWORD last_status;
|
DWORD last_status;
|
||||||
};
|
};
|
||||||
|
@ -111,6 +113,12 @@ static void CALLBACK check_notification( HINTERNET handle, DWORD_PTR context, DW
|
||||||
ok(status_ok, "%u: expected status 0x%08x got 0x%08x\n", info->line, info->test[info->index].status, status);
|
ok(status_ok, "%u: expected status 0x%08x got 0x%08x\n", info->line, info->test[info->index].status, status);
|
||||||
ok(function_ok, "%u: expected function %u got %u\n", info->line, info->test[info->index].function, info->function);
|
ok(function_ok, "%u: expected function %u got %u\n", info->line, info->test[info->index].function, info->function);
|
||||||
|
|
||||||
|
if (info->test[info->index].flags & NF_MAIN_THREAD)
|
||||||
|
{
|
||||||
|
ok(GetCurrentThreadId() == info->main_thread_id, "%u: expected callback to be called from the same thread\n",
|
||||||
|
info->line);
|
||||||
|
}
|
||||||
|
|
||||||
if (status_ok && function_ok && info->test[info->index++].flags & NF_SIGNAL)
|
if (status_ok && function_ok && info->test[info->index++].flags & NF_SIGNAL)
|
||||||
{
|
{
|
||||||
SetEvent( info->wait );
|
SetEvent( info->wait );
|
||||||
|
@ -184,6 +192,7 @@ static void setup_test( struct info *info, enum api function, unsigned int line
|
||||||
info->test[info->index].function, function);
|
info->test[info->index].function, function);
|
||||||
info->last_thread_id = 0xdeadbeef;
|
info->last_thread_id = 0xdeadbeef;
|
||||||
info->last_status = 0xdeadbeef;
|
info->last_status = 0xdeadbeef;
|
||||||
|
info->main_thread_id = GetCurrentThreadId();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void end_test( struct info *info, unsigned int line )
|
static void end_test( struct info *info, unsigned int line )
|
||||||
|
@ -658,8 +667,8 @@ static const struct notification websocket_test[] =
|
||||||
{ winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED },
|
{ winhttp_receive_response, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED },
|
||||||
{ winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL },
|
{ winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, NF_SIGNAL },
|
||||||
{ winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, NF_SIGNAL },
|
{ winhttp_websocket_complete_upgrade, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, NF_SIGNAL },
|
||||||
{ winhttp_websocket_send, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, NF_SIGNAL },
|
{ winhttp_websocket_send, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, NF_MAIN_THREAD | NF_SIGNAL },
|
||||||
{ winhttp_websocket_send, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, NF_SIGNAL },
|
{ winhttp_websocket_send, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, NF_MAIN_THREAD | NF_SIGNAL },
|
||||||
{ winhttp_websocket_shutdown, WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE, NF_SIGNAL },
|
{ winhttp_websocket_shutdown, WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE, NF_SIGNAL },
|
||||||
{ winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL },
|
{ winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL },
|
||||||
{ winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL },
|
{ winhttp_websocket_receive, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, NF_SIGNAL },
|
||||||
|
@ -792,6 +801,9 @@ static void test_websocket(BOOL secure)
|
||||||
|
|
||||||
for (i = 0; i < 2; ++i)
|
for (i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
|
/* The send is executed synchronously (even if sending a reasonably big buffer exceeding SSL buffer size).
|
||||||
|
* It is possible to trigger queueing the send into another thread but that involves sending a considerable
|
||||||
|
* amount of big enough buffers. */
|
||||||
setup_test( &info, winhttp_websocket_send, __LINE__ );
|
setup_test( &info, winhttp_websocket_send, __LINE__ );
|
||||||
err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE,
|
err = pWinHttpWebSocketSend( socket, WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE,
|
||||||
(void*)"hello", sizeof("hello") );
|
(void*)"hello", sizeof("hello") );
|
||||||
|
|
|
@ -297,6 +297,8 @@ struct socket_send
|
||||||
WINHTTP_WEB_SOCKET_BUFFER_TYPE type;
|
WINHTTP_WEB_SOCKET_BUFFER_TYPE type;
|
||||||
const void *buf;
|
const void *buf;
|
||||||
DWORD len;
|
DWORD len;
|
||||||
|
WSAOVERLAPPED ovr;
|
||||||
|
BOOL complete_async;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct socket_receive
|
struct socket_receive
|
||||||
|
@ -331,7 +333,7 @@ ULONG netconn_query_data_available( struct netconn * ) DECLSPEC_HIDDEN;
|
||||||
DWORD netconn_recv( struct netconn *, void *, size_t, int, int * ) DECLSPEC_HIDDEN;
|
DWORD netconn_recv( struct netconn *, void *, size_t, int, int * ) DECLSPEC_HIDDEN;
|
||||||
DWORD netconn_resolve( WCHAR *, INTERNET_PORT, struct sockaddr_storage *, int ) DECLSPEC_HIDDEN;
|
DWORD netconn_resolve( WCHAR *, INTERNET_PORT, struct sockaddr_storage *, int ) DECLSPEC_HIDDEN;
|
||||||
DWORD netconn_secure_connect( struct netconn *, WCHAR *, DWORD, CredHandle *, BOOL ) DECLSPEC_HIDDEN;
|
DWORD netconn_secure_connect( struct netconn *, WCHAR *, DWORD, CredHandle *, BOOL ) DECLSPEC_HIDDEN;
|
||||||
DWORD netconn_send( struct netconn *, const void *, size_t, int * ) DECLSPEC_HIDDEN;
|
DWORD netconn_send( struct netconn *, const void *, size_t, int *, WSAOVERLAPPED * ) DECLSPEC_HIDDEN;
|
||||||
DWORD netconn_set_timeout( struct netconn *, BOOL, int ) DECLSPEC_HIDDEN;
|
DWORD netconn_set_timeout( struct netconn *, BOOL, int ) DECLSPEC_HIDDEN;
|
||||||
BOOL netconn_is_alive( struct netconn * ) DECLSPEC_HIDDEN;
|
BOOL netconn_is_alive( struct netconn * ) DECLSPEC_HIDDEN;
|
||||||
const void *netconn_get_certificate( struct netconn * ) DECLSPEC_HIDDEN;
|
const void *netconn_get_certificate( struct netconn * ) DECLSPEC_HIDDEN;
|
||||||
|
|
Loading…
Reference in New Issue