From: Owen Rudge Subject: [PATCH 1/1] wsdapi/tests: Add tests for MatchProbeEx. Message-Id: <91b75bdf-3107-52cb-75c0-dd515ed6e1f9@codeweavers.com> Date: Thu, 21 Jun 2018 23:35:36 +0100 Signed-off-by: Owen Rudge --- dlls/wsdapi/tests/discovery.c | 194 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 193 insertions(+), 1 deletion(-) diff --git a/dlls/wsdapi/tests/discovery.c b/dlls/wsdapi/tests/discovery.c index 63033411d7..43a4b2c3a4 100644 --- a/dlls/wsdapi/tests/discovery.c +++ b/dlls/wsdapi/tests/discovery.c @@ -73,6 +73,8 @@ static const WCHAR name_cider[] = { 'C','i','d','e','r', 0 }; static HANDLE probe_event = NULL; static UUID probe_message_id; +static IWSDiscoveryPublisher *publisher_instance = NULL; + #define MAX_CACHED_MESSAGES 5 #define MAX_LISTENING_THREADS 20 @@ -232,6 +234,49 @@ static DWORD WINAPI listening_thread(LPVOID lpParam) return 0; } +static BOOL start_listening_udp_unicast(messageStorage *msgStorage, struct sockaddr_in *address) +{ + listenerThreadParams *parameter = NULL; + const DWORD receive_timeout = 500; + const UINT reuse_addr = 1; + HANDLE hThread; + SOCKET s = 0; + + /* Create the socket */ + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (s == INVALID_SOCKET) goto cleanup; + + /* Ensure the socket can be reused */ + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse_addr, sizeof(reuse_addr)) == SOCKET_ERROR) goto cleanup; + + /* Bind the socket to the local interface so we can receive data */ + if (bind(s, (struct sockaddr *) address, sizeof(struct sockaddr_in)) == SOCKET_ERROR) goto cleanup; + + /* Set a 500ms receive timeout */ + if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char *) &receive_timeout, sizeof(receive_timeout)) == SOCKET_ERROR) + goto cleanup; + + /* Allocate memory for thread parameters */ + parameter = heap_alloc(sizeof(listenerThreadParams)); + + parameter->msgStorage = msgStorage; + parameter->listeningSocket = s; + + hThread = CreateThread(NULL, 0, listening_thread, parameter, 0, NULL); + if (hThread == NULL) goto cleanup; + + msgStorage->threadHandles[msgStorage->numThreadHandles] = hThread; + msgStorage->numThreadHandles++; + + return TRUE; + +cleanup: + closesocket(s); + heap_free(parameter); + + return FALSE; +} + static void start_listening(messageStorage *msgStorage, const char *multicastAddress, const char *bindAddress) { struct addrinfo *multicastAddr = NULL, *bindAddr = NULL, *interfaceAddr = NULL; @@ -581,6 +626,8 @@ static HRESULT WINAPI IWSDiscoveryPublisherNotifyImpl_ProbeHandler(IWSDiscoveryP { static const WCHAR lager[] = {'L','a','g','e','r',0}; static const WCHAR more_info[] = {'M','o','r','e','I','n','f','o',0}; + IWSDUdpAddress *remote_addr = NULL; + HRESULT rc; ok(probe_msg->Types != NULL, "Probe message Types == NULL\n"); @@ -593,6 +640,149 @@ static HRESULT WINAPI IWSDiscoveryPublisherNotifyImpl_ProbeHandler(IWSDiscoveryP ok(probe_msg->Scopes == NULL, "Probe message Scopes != NULL\n"); verify_wsdxml_any_text("probe_msg->Any", probe_msg->Any, uri_more_tests_no_slash, prefix_grog, lager, more_info); + + rc = IWSDMessageParameters_GetRemoteAddress(pMessageParameters, (IWSDAddress **) &remote_addr); + ok(rc == S_OK, "IWSDMessageParameters_GetRemoteAddress returned %08x\n", rc); + + if (remote_addr != NULL) + { + messageStorage *msg_storage; + char endpoint_reference_string[MAX_PATH], app_sequence_string[MAX_PATH]; + LPWSTR publisherIdW = NULL, sequenceIdW = NULL; + SOCKADDR_STORAGE remote_sock; + WSDXML_ELEMENT *header_any_element, *body_any_element, *endpoint_any_element, *ref_param_any_element; + WSDXML_NAME header_any_name; + WSDXML_NAMESPACE ns; + static const WCHAR header_any_name_text[] = {'B','e','e','r',0}; + static const WCHAR header_any_text[] = {'P','u','b','l','i','s','h','T','e','s','t',0}; + static const WCHAR body_any_text[] = {'B','o','d','y','T','e','s','t',0}; + static const WCHAR endpoint_any_text[] = {'E','n','d','P','T','e','s','t',0}; + static const WCHAR ref_param_any_text[] = {'R','e','f','P','T','e','s','t',0}; + static const WCHAR uri[] = {'h','t','t','p',':','/','/','w','i','n','e','.','t','e','s','t','/',0}; + static const WCHAR prefix[] = {'w','i','n','e',0}; + BOOL probe_matches_message_seen = FALSE, endpoint_reference_seen = FALSE, app_sequence_seen = FALSE; + BOOL metadata_version_seen = FALSE, wine_ns_seen = FALSE, body_probe_matches_seen = FALSE; + BOOL types_seen = FALSE, any_header_seen = FALSE, any_body_seen = FALSE; + BOOL message_ok; + char *msg; + int i; + + rc = IWSDUdpAddress_GetSockaddr(remote_addr, &remote_sock); + ok(rc == S_OK, "IWSDMessageParameters_GetRemoteAddress returned %08x\n", rc); + + IWSDUdpAddress_Release(remote_addr); + + msg_storage = heap_alloc_zero(sizeof(messageStorage)); + if (msg_storage == NULL) goto after_matchprobe_test; + + msg_storage->running = TRUE; + InitializeCriticalSection(&msg_storage->criticalSection); + + ok(start_listening_udp_unicast(msg_storage, (struct sockaddr_in *) &remote_sock) == TRUE, + "Unable to listen on local socket for UDP messages\n"); + + publisherIdW = utf8_to_wide(publisherId); + sequenceIdW = utf8_to_wide(sequenceId); + + /* Create "any" elements for header */ + ns.Uri = uri; + ns.PreferredPrefix = prefix; + + header_any_name.LocalName = (WCHAR *) header_any_name_text; + header_any_name.Space = &ns; + + rc = WSDXMLBuildAnyForSingleElement(&header_any_name, header_any_text, &header_any_element); + ok(rc == S_OK, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc); + + rc = WSDXMLBuildAnyForSingleElement(&header_any_name, body_any_text, &body_any_element); + ok(rc == S_OK, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc); + + rc = WSDXMLBuildAnyForSingleElement(&header_any_name, endpoint_any_text, &endpoint_any_element); + ok(rc == S_OK, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc); + + rc = WSDXMLBuildAnyForSingleElement(&header_any_name, ref_param_any_text, &ref_param_any_element); + ok(rc == S_OK, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc); + + rc = IWSDiscoveryPublisher_MatchProbeEx(publisher_instance, pSoap, pMessageParameters, publisherIdW, 1, 1, 1, + sequenceIdW, probe_msg->Types, NULL, NULL, header_any_element, ref_param_any_element, NULL, + endpoint_any_element, body_any_element); + todo_wine ok(rc == S_OK, "IWSDiscoveryPublisher_MatchProbe failed with %08x\n", rc); + + WSDFreeLinkedMemory(header_any_element); + WSDFreeLinkedMemory(body_any_element); + WSDFreeLinkedMemory(endpoint_any_element); + WSDFreeLinkedMemory(ref_param_any_element); + + /* Wait up to 2 seconds for messages to be received */ + if (WaitForMultipleObjects(msg_storage->numThreadHandles, msg_storage->threadHandles, TRUE, 5000) == WAIT_TIMEOUT) + { + /* Wait up to 1 more second for threads to terminate */ + msg_storage->running = FALSE; + WaitForMultipleObjects(msg_storage->numThreadHandles, msg_storage->threadHandles, TRUE, 1000); + } + + for (i = 0; i < msg_storage->numThreadHandles; i++) + { + CloseHandle(msg_storage->threadHandles[i]); + } + + DeleteCriticalSection(&msg_storage->criticalSection); + + /* Verify we've received a message */ + todo_wine ok(msg_storage->messageCount >= 1, "No messages received\n"); + + sprintf(endpoint_reference_string, "%s" + "RefPTest" + "EndPTest", publisherId); + + sprintf(app_sequence_string, "", + sequenceId); + + message_ok = FALSE; + + /* Check we're received the correct message */ + for (i = 0; i < msg_storage->messageCount; i++) + { + msg = msg_storage->messages[i]; + message_ok = FALSE; + + probe_matches_message_seen = (strstr(msg, + "http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches") != NULL); + endpoint_reference_seen = (strstr(msg, endpoint_reference_string) != NULL); + app_sequence_seen = (strstr(msg, app_sequence_string) != NULL); + metadata_version_seen = (strstr(msg, "1") != NULL); + any_header_seen = (strstr(msg, "PublishTest") != NULL); + wine_ns_seen = (strstr(msg, "xmlns:grog=\"http://more.tests\"") != NULL); + body_probe_matches_seen = (strstr(msg, "BodyTest") != NULL); + types_seen = (strstr(msg, "grog:Cider") != NULL); + message_ok = probe_matches_message_seen && endpoint_reference_seen && app_sequence_seen && + metadata_version_seen && body_probe_matches_seen && types_seen; + + if (message_ok) break; + } + + for (i = 0; i < msg_storage->messageCount; i++) + { + heap_free(msg_storage->messages[i]); + } + + todo_wine ok(probe_matches_message_seen == TRUE, "Probe matches message not received\n"); + todo_wine ok(endpoint_reference_seen == TRUE, "EndpointReference not received\n"); + todo_wine ok(app_sequence_seen == TRUE, "AppSequence not received\n"); + todo_wine ok(metadata_version_seen == TRUE, "MetadataVersion not received\n"); + todo_wine ok(message_ok == TRUE, "ProbeMatches message metadata not received\n"); + todo_wine ok(any_header_seen == TRUE, "Custom header not received\n"); + todo_wine ok(wine_ns_seen == TRUE, "Wine namespace not received\n"); + todo_wine ok(body_probe_matches_seen == TRUE, "Body and Probe Matches elements not received\n"); + todo_wine ok(any_body_seen == TRUE, "Custom body element not received\n"); + todo_wine ok(types_seen == TRUE, "Types not received\n"); + +after_matchprobe_test: + heap_free(publisherIdW); + heap_free(sequenceIdW); + heap_free(msg_storage); + } } } @@ -755,6 +945,8 @@ static void Publish_tests(void) ok(rc == S_OK, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: %08x\n", rc); ok(publisher != NULL, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: publisher == NULL\n"); + publisher_instance = publisher; + /* Test SetAddressFamily */ rc = IWSDiscoveryPublisher_SetAddressFamily(publisher, 12345); ok(rc == E_INVALIDARG, "IWSDiscoveryPublisher_SetAddressFamily(12345) returned unexpected result: %08x\n", rc); @@ -957,7 +1149,7 @@ after_publish_test: sprintf(probe_message, testProbeMessage, probe_uuid_str); ok(send_udp_multicast_of_type(probe_message, strlen(probe_message), AF_INET) == TRUE, "Sending Probe message failed\n"); - ok(WaitForSingleObject(probe_event, 2000) == WAIT_OBJECT_0, "Probe message not received\n"); + ok(WaitForSingleObject(probe_event, 10000) == WAIT_OBJECT_0, "Probe message not received\n"); RpcStringFreeA(&probe_uuid_str); }