Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/winhttp/tests/notification.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/dlls/winhttp/tests/notification.c b/dlls/winhttp/tests/notification.c index 72cef89a618..ce585087370 100644 --- a/dlls/winhttp/tests/notification.c +++ b/dlls/winhttp/tests/notification.c @@ -671,7 +671,7 @@ static const struct notification websocket_test[] = { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING, NF_SIGNAL } };
-static void test_websocket(void) +static void test_websocket(BOOL secure) { HANDLE session, connection, request, socket, event; WINHTTP_WEB_SOCKET_BUFFER_TYPE type; @@ -680,6 +680,7 @@ static void test_websocket(void) struct info info, *context = &info; char buffer[1024]; USHORT close_status; + DWORD protocols, flags;
if (!pWinHttpWebSocketCompleteUpgrade) { @@ -703,6 +704,13 @@ static void test_websocket(void) unload = FALSE; }
+ if (secure) + { + protocols = WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2; + ret = WinHttpSetOption(session, WINHTTP_OPTION_SECURE_PROTOCOLS, &protocols, sizeof(protocols)); + ok(ret, "failed to set protocols %u\n", GetLastError()); + } + SetLastError( 0xdeadbeef ); WinHttpSetStatusCallback( session, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 ); err = GetLastError(); @@ -723,11 +731,19 @@ static void test_websocket(void)
setup_test( &info, winhttp_open_request, __LINE__ ); SetLastError( 0xdeadbeef ); - request = WinHttpOpenRequest( connection, NULL, L"/", NULL, NULL, NULL, 0 ); + request = WinHttpOpenRequest( connection, NULL, L"/", NULL, NULL, NULL, secure ? WINHTTP_FLAG_SECURE : 0); err = GetLastError(); ok( request != NULL, "got %u\n", err ); ok( err == ERROR_SUCCESS, "got %u\n", err );
+ if (secure) + { + flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | + SECURITY_FLAG_IGNORE_CERT_CN_INVALID; + ret = WinHttpSetOption(request, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags)); + ok(ret, "failed to set security flags %u\n", GetLastError()); + } + ret = WinHttpSetOption( request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0 ); ok( ret, "got %u\n", GetLastError() );
@@ -1380,7 +1396,10 @@ START_TEST (notification) test_connection_cache(); test_redirect(); test_async(); - test_websocket(); + test_websocket( FALSE ); + winetest_push_context( "secure" ); + test_websocket( TRUE ); + winetest_pop_context(); test_recursion();
si.event = CreateEventW( NULL, 0, 0, NULL );
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- Websockets are full duplex and sends and receives already go to different queues. Thus sends and receives may race on the SSL buffer.
dlls/winhttp/net.c | 34 +++++++++++++++++++++------------- dlls/winhttp/winhttp_private.h | 2 +- 2 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/dlls/winhttp/net.c b/dlls/winhttp/net.c index 3016608404a..68aee036734 100644 --- a/dlls/winhttp/net.c +++ b/dlls/winhttp/net.c @@ -250,7 +250,8 @@ void netconn_close( struct netconn *conn ) if (conn->secure) { free( conn->peek_msg_mem ); - free(conn->ssl_buf); + free(conn->ssl_read_buf); + free(conn->ssl_write_buf); free(conn->extra_buf); DeleteSecurityContext(&conn->ssl_ctx); } @@ -365,8 +366,13 @@ DWORD netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD secur break; }
- conn->ssl_buf = malloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer); - if(!conn->ssl_buf) { + conn->ssl_read_buf = malloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer); + if(!conn->ssl_read_buf) { + res = ERROR_OUTOFMEMORY; + break; + } + conn->ssl_write_buf = malloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer); + if(!conn->ssl_write_buf) { res = ERROR_OUTOFMEMORY; break; } @@ -377,8 +383,10 @@ DWORD netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD secur
if(status != SEC_E_OK || res != ERROR_SUCCESS) { WARN("Failed to initialize security context: %08x\n", status); - free(conn->ssl_buf); - conn->ssl_buf = NULL; + free(conn->ssl_read_buf); + conn->ssl_read_buf = NULL; + free(conn->ssl_write_buf); + conn->ssl_write_buf = NULL; DeleteSecurityContext(&ctx); return ERROR_WINHTTP_SECURE_CHANNEL_ERROR; } @@ -393,9 +401,9 @@ DWORD netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD secur static DWORD send_ssl_chunk( struct netconn *conn, const void *msg, size_t size ) { SecBuffer bufs[4] = { - {conn->ssl_sizes.cbHeader, SECBUFFER_STREAM_HEADER, conn->ssl_buf}, - {size, SECBUFFER_DATA, conn->ssl_buf+conn->ssl_sizes.cbHeader}, - {conn->ssl_sizes.cbTrailer, SECBUFFER_STREAM_TRAILER, conn->ssl_buf+conn->ssl_sizes.cbHeader+size}, + {conn->ssl_sizes.cbHeader, SECBUFFER_STREAM_HEADER, conn->ssl_write_buf}, + {size, SECBUFFER_DATA, conn->ssl_write_buf+conn->ssl_sizes.cbHeader}, + {conn->ssl_sizes.cbTrailer, SECBUFFER_STREAM_TRAILER, conn->ssl_write_buf+conn->ssl_sizes.cbHeader+size}, {0, SECBUFFER_EMPTY, NULL} }; SecBufferDesc buf_desc = {SECBUFFER_VERSION, ARRAY_SIZE(bufs), bufs}; @@ -408,7 +416,7 @@ static DWORD send_ssl_chunk( struct netconn *conn, const void *msg, size_t size return res; }
- if (sock_send( conn->socket, conn->ssl_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, 0 ) < 1) { WARN("send failed\n"); return WSAGetLastError(); @@ -456,13 +464,13 @@ static DWORD read_ssl_chunk( struct netconn *conn, void *buf, SIZE_T buf_size, S assert(conn->extra_len < ssl_buf_size);
if(conn->extra_len) { - memcpy(conn->ssl_buf, conn->extra_buf, conn->extra_len); + memcpy(conn->ssl_read_buf, conn->extra_buf, conn->extra_len); buf_len = conn->extra_len; conn->extra_len = 0; free(conn->extra_buf); conn->extra_buf = NULL; }else { - if ((buf_len = sock_recv( conn->socket, conn->ssl_buf + conn->extra_len, ssl_buf_size - conn->extra_len, 0)) < 0) + if ((buf_len = sock_recv( conn->socket, conn->ssl_read_buf + conn->extra_len, ssl_buf_size - conn->extra_len, 0)) < 0) return WSAGetLastError();
if (!buf_len) @@ -479,7 +487,7 @@ static DWORD read_ssl_chunk( struct netconn *conn, void *buf, SIZE_T buf_size, S memset(bufs, 0, sizeof(bufs)); bufs[0].BufferType = SECBUFFER_DATA; bufs[0].cbBuffer = buf_len; - bufs[0].pvBuffer = conn->ssl_buf; + bufs[0].pvBuffer = conn->ssl_read_buf;
switch ((res = DecryptMessage( &conn->ssl_ctx, &buf_desc, 0, NULL ))) { @@ -498,7 +506,7 @@ static DWORD read_ssl_chunk( struct netconn *conn, void *buf, SIZE_T buf_size, S case SEC_E_INCOMPLETE_MESSAGE: assert(buf_len < ssl_buf_size);
- if ((size = sock_recv( conn->socket, conn->ssl_buf + buf_len, ssl_buf_size - buf_len, 0 )) < 1) + if ((size = sock_recv( conn->socket, conn->ssl_read_buf + buf_len, ssl_buf_size - buf_len, 0 )) < 1) return SEC_E_INCOMPLETE_MESSAGE;
buf_len += size; diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h index 291a38e7bdd..1538a61da6d 100644 --- a/dlls/winhttp/winhttp_private.h +++ b/dlls/winhttp/winhttp_private.h @@ -108,7 +108,7 @@ struct netconn ULONGLONG keep_until; CtxtHandle ssl_ctx; SecPkgContext_StreamSizes ssl_sizes; - char *ssl_buf; + char *ssl_read_buf, *ssl_write_buf; char *extra_buf; size_t extra_len; char *peek_msg;
Signed-off-by: Hans Leidekker hans@codeweavers.com
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/winhttp/request.c | 58 ++++++++++++++++++++++++++-------- dlls/winhttp/winhttp_private.h | 4 +++ 2 files changed, 48 insertions(+), 14 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index d76edfa71d7..907ee538f54 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -3063,6 +3063,7 @@ static void socket_destroy( struct object_header *hdr ) stop_queue( &socket->recv_q );
release_object( &socket->request->hdr ); + free( socket->send_frame_buffer ); free( socket ); }
@@ -3142,10 +3143,12 @@ static DWORD send_bytes( struct socket *socket, char *bytes, int len ) static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHORT status, const char *buf, DWORD buflen, BOOL final ) { - DWORD i = 0, j, ret, offset = 2, len = buflen; - char hdr[14], byte, *mask = NULL; + DWORD i = 0, j, offset = 2, len = buflen; + DWORD buffer_size, ret = 0, send_size; + char hdr[14], *mask = NULL; + char *ptr;
- TRACE("sending %02x frame\n", opcode); + TRACE( "sending %02x frame, len %u.\n", opcode, len );
if (opcode == SOCKET_OPCODE_CLOSE) len += sizeof(status);
@@ -3171,29 +3174,56 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR offset += 8; }
- if ((ret = send_bytes( socket, hdr, offset ))) return ret; + buffer_size = len + offset; + if (len) buffer_size += 4; + assert( buffer_size - len < MAX_FRAME_BUFFER_SIZE ); + if (buffer_size > socket->send_frame_buffer_size && socket->send_frame_buffer_size < MAX_FRAME_BUFFER_SIZE) + { + DWORD new_size; + void *new; + + new_size = min( buffer_size, MAX_FRAME_BUFFER_SIZE ); + if (!(new = realloc( socket->send_frame_buffer, new_size ))) + { + ERR("Out of memory, buffer_size %u.\n", buffer_size); + return ERROR_OUTOFMEMORY; + } + socket->send_frame_buffer = new; + socket->send_frame_buffer_size = new_size; + } + ptr = socket->send_frame_buffer; + + memcpy(ptr, hdr, offset); + ptr += offset; if (len) { mask = &hdr[offset]; RtlGenRandom( mask, 4 ); - if ((ret = send_bytes( socket, mask, 4 ))) return ret; + memcpy( ptr, mask, 4 ); + ptr += 4; }
if (opcode == SOCKET_OPCODE_CLOSE) /* prepend status code */ { - byte = (status >> 8) ^ mask[i++ % 4]; - if ((ret = send_bytes( socket, &byte, 1 ))) return ret; - - byte = (status & 0xff) ^ mask[i++ % 4]; - if ((ret = send_bytes( socket, &byte, 1 ))) return ret; + *ptr++ = (status >> 8) ^ mask[i++ % 4]; + *ptr++ = (status & 0xff) ^ mask[i++ % 4]; }
- for (j = 0; j < buflen; j++) + offset = ptr - socket->send_frame_buffer; + send_size = offset + buflen; + while (1) { - byte = buf[j] ^ mask[i++ % 4]; - if ((ret = send_bytes( socket, &byte, 1 ))) return ret; - } + j = 0; + while (j < buflen && offset < MAX_FRAME_BUFFER_SIZE) + socket->send_frame_buffer[offset++] = buf[j++] ^ mask[i++ % 4]; + + if ((ret = send_bytes( socket, socket->send_frame_buffer, offset ))) return ret;
+ if (!(send_size -= offset)) break; + offset = 0; + buf += j; + buflen -= j; + } return ERROR_SUCCESS; }
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h index 1538a61da6d..557ee766735 100644 --- a/dlls/winhttp/winhttp_private.h +++ b/dlls/winhttp/winhttp_private.h @@ -248,6 +248,8 @@ struct socket USHORT status; char reason[123]; DWORD reason_len; + char *send_frame_buffer; + unsigned int send_frame_buffer_size; };
struct send_request @@ -398,4 +400,6 @@ static inline char *strdupWA_sized( const WCHAR *src, DWORD size )
extern HINSTANCE winhttp_instance DECLSPEC_HIDDEN;
+#define MAX_FRAME_BUFFER_SIZE 65536 + #endif /* _WINE_WINHTTP_PRIVATE_H_ */
Signed-off-by: Hans Leidekker hans@codeweavers.com
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/winhttp/request.c | 2 +- dlls/winhttp/tests/notification.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index 907ee538f54..f215b984f6e 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -3554,7 +3554,7 @@ DWORD WINAPI WinHttpWebSocketReceive( HINTERNET hsocket, void *buf, DWORD len, D release_object( &socket->hdr ); return ERROR_WINHTTP_INCORRECT_HANDLE_TYPE; } - if (socket->state != SOCKET_STATE_OPEN) + if (socket->state > SOCKET_STATE_SHUTDOWN) { release_object( &socket->hdr ); return ERROR_WINHTTP_INCORRECT_HANDLE_STATE; diff --git a/dlls/winhttp/tests/notification.c b/dlls/winhttp/tests/notification.c index ce585087370..6b0e11023da 100644 --- a/dlls/winhttp/tests/notification.c +++ b/dlls/winhttp/tests/notification.c @@ -659,9 +659,9 @@ static const struct notification websocket_test[] = { winhttp_receive_response, WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE, 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_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_shutdown, WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE, NF_SIGNAL }, { winhttp_websocket_close, WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE, NF_SIGNAL }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING }, { winhttp_close_handle, WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION, NF_WINE_ALLOW }, @@ -793,6 +793,11 @@ static void test_websocket(BOOL secure) ok( err == ERROR_SUCCESS, "got %u\n", err ); WaitForSingleObject( info.wait, INFINITE );
+ setup_test( &info, winhttp_websocket_shutdown, __LINE__ ); + err = pWinHttpWebSocketShutdown( socket, 1000, (void *)"success", sizeof("success") ); + ok( err == ERROR_SUCCESS, "got %u\n", err ); + WaitForSingleObject( info.wait, INFINITE ); + setup_test( &info, winhttp_websocket_receive, __LINE__ ); buffer[0] = 0; size = 0xdeadbeef; @@ -815,11 +820,6 @@ static void test_websocket(BOOL secure) ok( type == 0xdeadbeef, "got %u\n", type ); ok( buffer[0] == 'h', "unexpected data\n" );
- setup_test( &info, winhttp_websocket_shutdown, __LINE__ ); - err = pWinHttpWebSocketShutdown( socket, 1000, (void *)"success", sizeof("success") ); - ok( err == ERROR_SUCCESS, "got %u\n", err ); - WaitForSingleObject( info.wait, INFINITE ); - setup_test( &info, winhttp_websocket_close, __LINE__ ); ret = pWinHttpWebSocketClose( socket, 1000, (void *)"success", sizeof("success") ); ok( err == ERROR_SUCCESS, "got %u\n", err );
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=105509
Your paranoid android.
=== w8adm (32 bit report) ===
winhttp: notification.c:239: Test failed: failed to send request 12007 notification.c:241: Test failed: unexpected function 3, expected 4. probably some notifications were missing notification.c:243: Test failed: failed to receive response 12019 notification.c:247: Test failed: failed unexpectedly 12019 notification.c:248: Test failed: request failed unexpectedly 2147348480 notification.c:251: Test failed: unexpected function 3, expected 13. probably some notifications were missing notification.c:111: Test failed: 251: expected status 0x00000002 got 0x00000800 notification.c:112: Test failed: 251: expected function 3 got 13 notification: Timeout
Signed-off-by: Hans Leidekker hans@codeweavers.com
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/winhttp/request.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index f215b984f6e..af04292ea06 100644 --- a/dlls/winhttp/request.c +++ b/dlls/winhttp/request.c @@ -3328,7 +3328,7 @@ DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_ return ret; }
-static DWORD receive_bytes( struct socket *socket, char *buf, DWORD len, DWORD *ret_len ) +static DWORD receive_bytes( struct socket *socket, char *buf, DWORD len, DWORD *ret_len, BOOL read_full_buffer ) { DWORD err, size = 0, needed = len; char *ptr = buf; @@ -3342,8 +3342,17 @@ static DWORD receive_bytes( struct socket *socket, char *buf, DWORD len, DWORD * needed -= size; ptr += size; } - if ((err = netconn_recv( socket->request->netconn, ptr, needed, 0, &received ))) return err; - if ((*ret_len = size + received) != len) return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; + while (size != len) + { + if ((err = netconn_recv( socket->request->netconn, ptr, needed, 0, &received ))) return err; + if (!received) break; + size += received; + if (!read_full_buffer) break; + needed -= received; + ptr += received; + } + *ret_len = size; + if (size != len && (read_full_buffer || !size)) return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; return ERROR_SUCCESS; }
@@ -3368,7 +3377,7 @@ static DWORD receive_frame( struct socket *socket, DWORD *ret_len, enum socket_o DWORD ret, len, count; char hdr[2];
- if ((ret = receive_bytes( socket, hdr, sizeof(hdr), &count ))) return ret; + if ((ret = receive_bytes( socket, hdr, sizeof(hdr), &count, TRUE ))) return ret; if ((hdr[0] & RESERVED_BIT) || (hdr[1] & MASK_BIT) || !is_supported_opcode( hdr[0] & 0xf )) { return ERROR_WINHTTP_INVALID_SERVER_RESPONSE; @@ -3380,13 +3389,13 @@ static DWORD receive_frame( struct socket *socket, DWORD *ret_len, enum socket_o if (len == 126) { USHORT len16; - if ((ret = receive_bytes( socket, (char *)&len16, sizeof(len16), &count ))) return ret; + if ((ret = receive_bytes( socket, (char *)&len16, sizeof(len16), &count, TRUE ))) return ret; len = RtlUshortByteSwap( len16 ); } else if (len == 127) { ULONGLONG len64; - if ((ret = receive_bytes( socket, (char *)&len64, sizeof(len64), &count ))) return ret; + if ((ret = receive_bytes( socket, (char *)&len64, sizeof(len64), &count, TRUE ))) return ret; if ((len64 = RtlUlonglongByteSwap( len64 )) > ~0u) return ERROR_NOT_SUPPORTED; len = len64; } @@ -3434,7 +3443,7 @@ static DWORD socket_drain( struct socket *socket ) while (socket->read_size) { char buf[1024]; - if ((ret = receive_bytes( socket, buf, min(socket->read_size, sizeof(buf)), &count ))) return ret; + if ((ret = receive_bytes( socket, buf, min(socket->read_size, sizeof(buf)), &count, TRUE ))) return ret; socket->read_size -= count; } return ERROR_SUCCESS; @@ -3496,9 +3505,12 @@ static DWORD socket_receive( struct socket *socket, void *buf, DWORD len, DWORD if (ret) break; } } - if (!ret) ret = receive_bytes( socket, buf, min(len, socket->read_size), &count ); + if (!ret) ret = receive_bytes( socket, buf, min(len, socket->read_size), &count, FALSE ); if (!ret) { + if (count < socket->read_size) + WARN("Short read.\n"); + socket->read_size -= count; if (!async) { @@ -3685,9 +3697,9 @@ static DWORD socket_close( struct socket *socket, USHORT status, const void *rea if (count) { DWORD reason_len = count - sizeof(socket->status); - if ((ret = receive_bytes( socket, (char *)&socket->status, sizeof(socket->status), &count ))) goto done; + if ((ret = receive_bytes( socket, (char *)&socket->status, sizeof(socket->status), &count, TRUE ))) goto done; socket->status = RtlUshortByteSwap( socket->status ); - if ((ret = receive_bytes( socket, socket->reason, reason_len, &socket->reason_len ))) goto done; + if ((ret = receive_bytes( socket, socket->reason, reason_len, &socket->reason_len, TRUE ))) goto done; } socket->state = SOCKET_STATE_CLOSED;
Signed-off-by: Hans Leidekker hans@codeweavers.com
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=105506
Your paranoid android.
=== w8adm (32 bit report) ===
winhttp: notification.c:239: Test failed: failed to send request 12007 notification.c:241: Test failed: unexpected function 3, expected 4. probably some notifications were missing notification.c:243: Test failed: failed to receive response 12019 notification.c:247: Test failed: failed unexpectedly 12019 notification.c:248: Test failed: request failed unexpectedly 2147348480 notification.c:251: Test failed: unexpected function 3, expected 13. probably some notifications were missing notification.c:111: Test failed: 251: expected status 0x00000002 got 0x00000800 notification.c:112: Test failed: 251: expected function 3 got 13 notification: Timeout