mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / wsdapi / tests / discovery.c
blob2ecb3d2ccd8a878f1498e9ed149308cf6e96d6de
1 /*
2 * Web Services on Devices
3 * Discovery tests
5 * Copyright 2017-2018 Owen Rudge for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
24 #include <winsock2.h>
25 #include <ws2tcpip.h>
26 #include <windows.h>
28 #include "wine/test.h"
29 #include "wine/heap.h"
30 #include "initguid.h"
31 #include "objbase.h"
32 #include "wsdapi.h"
33 #include <netfw.h>
34 #include <iphlpapi.h>
35 #include <stdio.h>
37 #define SEND_ADDRESS_IPV4 "239.255.255.250"
38 #define SEND_ADDRESS_IPV6 "FF02::C"
39 #define SEND_PORT "3702"
41 static const char *publisherId = "urn:uuid:3AE5617D-790F-408A-9374-359A77F924A3";
42 static const char *sequenceId = "urn:uuid:b14de351-72fc-4453-96f9-e58b0c9faf38";
44 static const char testProbeMessage[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
45 "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" "
46 "xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\" "
47 "xmlns:wsd=\"http://schemas.xmlsoap.org/ws/2005/04/discovery\" "
48 "xmlns:grog=\"http://more.tests/\"><soap:Header><wsa:To>urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To>"
49 "<wsa:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:Action>"
50 "<wsa:MessageID>urn:uuid:%s</wsa:MessageID>"
51 "<wsd:AppSequence InstanceId=\"21\" SequenceId=\"urn:uuid:638abee8-124d-4b6a-8b85-8cf2837a2fd2\" MessageNumber=\"14\"></wsd:AppSequence>"
52 "<grog:Perry>ExtraInfo</grog:Perry></soap:Header>"
53 "<soap:Body><wsd:Probe><wsd:Types>grog:Cider</wsd:Types><grog:Lager>MoreInfo</grog:Lager></wsd:Probe></soap:Body></soap:Envelope>";
55 static const WCHAR *uri_more_tests = L"http://more.tests/";
56 static const WCHAR *uri_more_tests_no_slash = L"http://more.tests";
57 static const WCHAR *prefix_grog = L"grog";
58 static const WCHAR *name_cider = L"Cider";
60 static HANDLE probe_event = NULL;
61 static UUID probe_message_id;
63 static IWSDiscoveryPublisher *publisher_instance = NULL;
65 #define MAX_CACHED_MESSAGES 5
66 #define MAX_LISTENING_THREADS 20
68 typedef struct messageStorage {
69 BOOL running;
70 CRITICAL_SECTION criticalSection;
71 char* messages[MAX_CACHED_MESSAGES];
72 int messageCount;
73 HANDLE threadHandles[MAX_LISTENING_THREADS];
74 int numThreadHandles;
75 } messageStorage;
77 static LPWSTR utf8_to_wide(const char *utf8String)
79 int sizeNeeded = 0, utf8StringLength = 0, memLength = 0;
80 LPWSTR newString = NULL;
82 if (utf8String == NULL) return NULL;
83 utf8StringLength = lstrlenA(utf8String);
85 sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, utf8String, utf8StringLength, NULL, 0);
86 if (sizeNeeded <= 0) return NULL;
88 memLength = sizeof(WCHAR) * (sizeNeeded + 1);
89 newString = heap_alloc_zero(memLength);
91 MultiByteToWideChar(CP_UTF8, 0, utf8String, utf8StringLength, newString, sizeNeeded);
92 return newString;
95 static int join_multicast_group(SOCKET s, struct addrinfo *group, struct addrinfo *iface)
97 int level, optname, optlen;
98 struct ipv6_mreq mreqv6;
99 struct ip_mreq mreqv4;
100 char *optval;
102 if (group->ai_family == AF_INET6)
104 level = IPPROTO_IPV6;
105 optname = IPV6_ADD_MEMBERSHIP;
106 optval = (char *)&mreqv6;
107 optlen = sizeof(mreqv6);
109 mreqv6.ipv6mr_multiaddr = ((SOCKADDR_IN6 *)group->ai_addr)->sin6_addr;
110 mreqv6.ipv6mr_interface = ((SOCKADDR_IN6 *)iface->ai_addr)->sin6_scope_id;
112 else
114 level = IPPROTO_IP;
115 optname = IP_ADD_MEMBERSHIP;
116 optval = (char *)&mreqv4;
117 optlen = sizeof(mreqv4);
119 mreqv4.imr_multiaddr.s_addr = ((SOCKADDR_IN *)group->ai_addr)->sin_addr.s_addr;
120 mreqv4.imr_interface.s_addr = ((SOCKADDR_IN *)iface->ai_addr)->sin_addr.s_addr;
123 return setsockopt(s, level, optname, optval, optlen);
126 static int set_send_interface(SOCKET s, struct addrinfo *iface)
128 int level, optname, optlen;
129 char *optval = NULL;
131 if (iface->ai_family == AF_INET6)
133 level = IPPROTO_IPV6;
134 optname = IPV6_MULTICAST_IF;
135 optval = (char *) &((SOCKADDR_IN6 *)iface->ai_addr)->sin6_scope_id;
136 optlen = sizeof(((SOCKADDR_IN6 *)iface->ai_addr)->sin6_scope_id);
138 else
140 level = IPPROTO_IP;
141 optname = IP_MULTICAST_IF;
142 optval = (char *) &((SOCKADDR_IN *)iface->ai_addr)->sin_addr.s_addr;
143 optlen = sizeof(((SOCKADDR_IN *)iface->ai_addr)->sin_addr.s_addr);
146 return setsockopt(s, level, optname, optval, optlen);
149 static struct addrinfo *resolve_address(const char *address, const char *port, int family, int type, int protocol)
151 struct addrinfo hints, *result = NULL;
153 ZeroMemory(&hints, sizeof(hints));
155 hints.ai_flags = AI_PASSIVE;
156 hints.ai_family = family;
157 hints.ai_socktype = type;
158 hints.ai_protocol = protocol;
160 return getaddrinfo(address, port, &hints, &result) == 0 ? result : NULL;
163 typedef struct listenerThreadParams
165 messageStorage *msgStorage;
166 SOCKET listeningSocket;
167 } listenerThreadParams;
169 #define RECEIVE_BUFFER_SIZE 65536
171 static DWORD WINAPI listening_thread(LPVOID lpParam)
173 listenerThreadParams *parameter = (listenerThreadParams *)lpParam;
174 messageStorage *msgStorage = parameter->msgStorage;
175 int bytesReceived;
176 char *buffer;
178 buffer = heap_alloc(RECEIVE_BUFFER_SIZE);
180 while (parameter->msgStorage->running)
182 ZeroMemory(buffer, RECEIVE_BUFFER_SIZE);
183 bytesReceived = recv(parameter->listeningSocket, buffer, RECEIVE_BUFFER_SIZE, 0);
185 if (bytesReceived == SOCKET_ERROR)
187 if (WSAGetLastError() != WSAETIMEDOUT)
188 return 0;
190 else
192 EnterCriticalSection(&msgStorage->criticalSection);
194 if (msgStorage->messageCount < MAX_CACHED_MESSAGES)
196 msgStorage->messages[msgStorage->messageCount] = heap_alloc(bytesReceived);
198 if (msgStorage->messages[msgStorage->messageCount] != NULL)
200 memcpy(msgStorage->messages[msgStorage->messageCount], buffer, bytesReceived);
201 msgStorage->messageCount++;
205 LeaveCriticalSection(&msgStorage->criticalSection);
207 if (msgStorage->messageCount >= MAX_CACHED_MESSAGES)
209 /* Stop all threads */
210 msgStorage->running = FALSE;
211 break;
216 closesocket(parameter->listeningSocket);
218 heap_free(buffer);
219 heap_free(parameter);
221 return 0;
224 static BOOL start_listening_udp_unicast(messageStorage *msgStorage, struct sockaddr_in *address)
226 listenerThreadParams *parameter = NULL;
227 const DWORD receive_timeout = 500;
228 const UINT reuse_addr = 1;
229 HANDLE hThread;
230 SOCKET s = 0;
232 /* Create the socket */
233 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
234 if (s == INVALID_SOCKET) goto cleanup;
236 /* Ensure the socket can be reused */
237 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse_addr, sizeof(reuse_addr)) == SOCKET_ERROR) goto cleanup;
239 /* Bind the socket to the local interface so we can receive data */
240 if (bind(s, (struct sockaddr *) address, sizeof(struct sockaddr_in)) == SOCKET_ERROR) goto cleanup;
242 /* Set a 500ms receive timeout */
243 if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char *) &receive_timeout, sizeof(receive_timeout)) == SOCKET_ERROR)
244 goto cleanup;
246 /* Allocate memory for thread parameters */
247 parameter = heap_alloc(sizeof(listenerThreadParams));
249 parameter->msgStorage = msgStorage;
250 parameter->listeningSocket = s;
252 hThread = CreateThread(NULL, 0, listening_thread, parameter, 0, NULL);
253 if (hThread == NULL) goto cleanup;
255 msgStorage->threadHandles[msgStorage->numThreadHandles] = hThread;
256 msgStorage->numThreadHandles++;
258 return TRUE;
260 cleanup:
261 closesocket(s);
262 heap_free(parameter);
264 return FALSE;
267 static void start_listening(messageStorage *msgStorage, const char *multicastAddress, const char *bindAddress)
269 struct addrinfo *multicastAddr = NULL, *bindAddr = NULL, *interfaceAddr = NULL;
270 listenerThreadParams *parameter = NULL;
271 const DWORD receiveTimeout = 500;
272 const UINT reuseAddr = 1;
273 HANDLE hThread;
274 SOCKET s = 0;
276 /* Resolve the multicast address */
277 multicastAddr = resolve_address(multicastAddress, SEND_PORT, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP);
278 if (multicastAddr == NULL) goto cleanup;
280 /* Resolve the binding address */
281 bindAddr = resolve_address(bindAddress, SEND_PORT, multicastAddr->ai_family, multicastAddr->ai_socktype, multicastAddr->ai_protocol);
282 if (bindAddr == NULL) goto cleanup;
284 /* Resolve the multicast interface */
285 interfaceAddr = resolve_address(bindAddress, "0", multicastAddr->ai_family, multicastAddr->ai_socktype, multicastAddr->ai_protocol);
286 if (interfaceAddr == NULL) goto cleanup;
288 /* Create the socket */
289 s = socket(multicastAddr->ai_family, multicastAddr->ai_socktype, multicastAddr->ai_protocol);
290 if (s == INVALID_SOCKET) goto cleanup;
292 /* Ensure the socket can be reused */
293 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuseAddr, sizeof(reuseAddr)) == SOCKET_ERROR) goto cleanup;
295 /* Bind the socket to the local interface so we can receive data */
296 if (bind(s, bindAddr->ai_addr, bindAddr->ai_addrlen) == SOCKET_ERROR) goto cleanup;
298 /* Join the multicast group */
299 if (join_multicast_group(s, multicastAddr, interfaceAddr) == SOCKET_ERROR) goto cleanup;
301 /* Set the outgoing interface */
302 if (set_send_interface(s, interfaceAddr) == SOCKET_ERROR) goto cleanup;
304 /* For IPv6, ensure the scope ID is zero */
305 if (multicastAddr->ai_family == AF_INET6)
306 ((SOCKADDR_IN6 *)multicastAddr->ai_addr)->sin6_scope_id = 0;
308 /* Set a 500ms receive timeout */
309 if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char *)&receiveTimeout, sizeof(receiveTimeout)) == SOCKET_ERROR) goto cleanup;
311 /* Allocate memory for thread parameters */
312 parameter = heap_alloc(sizeof(listenerThreadParams));
314 parameter->msgStorage = msgStorage;
315 parameter->listeningSocket = s;
317 hThread = CreateThread(NULL, 0, listening_thread, parameter, 0, NULL);
318 if (hThread == NULL) goto cleanup;
320 msgStorage->threadHandles[msgStorage->numThreadHandles] = hThread;
321 msgStorage->numThreadHandles++;
323 goto cleanup_addresses;
325 cleanup:
326 closesocket(s);
327 heap_free(parameter);
329 cleanup_addresses:
330 freeaddrinfo(multicastAddr);
331 freeaddrinfo(bindAddr);
332 freeaddrinfo(interfaceAddr);
335 static BOOL start_listening_on_all_addresses(messageStorage *msgStorage, ULONG family)
337 IP_ADAPTER_ADDRESSES *adapterAddresses = NULL, *adapterAddress;
338 ULONG bufferSize = 0;
339 LPSOCKADDR sockaddr;
340 DWORD addressLength;
341 char address[64];
342 BOOL ret = FALSE;
343 ULONG retVal;
345 retVal = GetAdaptersAddresses(family, 0, NULL, NULL, &bufferSize); /* family should be AF_INET or AF_INET6 */
346 if (retVal != ERROR_BUFFER_OVERFLOW) goto cleanup;
348 /* Get size of buffer for adapters */
349 adapterAddresses = (IP_ADAPTER_ADDRESSES *)heap_alloc(bufferSize);
350 if (adapterAddresses == NULL) goto cleanup;
352 /* Get list of adapters */
353 retVal = GetAdaptersAddresses(family, 0, NULL, adapterAddresses, &bufferSize);
354 if (retVal != ERROR_SUCCESS) goto cleanup;
356 for (adapterAddress = adapterAddresses; adapterAddress != NULL; adapterAddress = adapterAddress->Next)
358 if (msgStorage->numThreadHandles >= MAX_LISTENING_THREADS)
360 ret = TRUE;
361 goto cleanup;
364 if (adapterAddress->FirstUnicastAddress == NULL) continue;
366 sockaddr = adapterAddress->FirstUnicastAddress->Address.lpSockaddr;
367 addressLength = sizeof(address);
368 WSAAddressToStringA(sockaddr, adapterAddress->FirstUnicastAddress->Address.iSockaddrLength, NULL, address, &addressLength);
370 start_listening(msgStorage, adapterAddress->FirstUnicastAddress->Address.lpSockaddr->sa_family == AF_INET ? SEND_ADDRESS_IPV4 : SEND_ADDRESS_IPV6, address);
373 ret = TRUE;
375 cleanup:
376 heap_free(adapterAddresses);
377 return ret;
380 static BOOL send_udp_multicast_of_type(const char *data, int length, ULONG family)
382 IP_ADAPTER_ADDRESSES *adapter_addresses = NULL, *adapter_addr;
383 static const struct in6_addr i_addr_zero;
384 struct addrinfo *multi_address;
385 ULONG bufferSize = 0;
386 LPSOCKADDR sockaddr;
387 BOOL ret = FALSE;
388 const char ttl = 8;
389 ULONG retval;
390 SOCKET s;
392 /* Resolve the multicast address */
393 if (family == AF_INET6)
394 multi_address = resolve_address(SEND_ADDRESS_IPV6, SEND_PORT, AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
395 else
396 multi_address = resolve_address(SEND_ADDRESS_IPV4, SEND_PORT, AF_INET, SOCK_DGRAM, IPPROTO_UDP);
398 if (multi_address == NULL)
399 return FALSE;
401 /* Get size of buffer for adapters */
402 retval = GetAdaptersAddresses(family, 0, NULL, NULL, &bufferSize);
403 if (retval != ERROR_BUFFER_OVERFLOW) goto cleanup;
405 adapter_addresses = (IP_ADAPTER_ADDRESSES *) heap_alloc(bufferSize);
406 if (adapter_addresses == NULL) goto cleanup;
408 /* Get list of adapters */
409 retval = GetAdaptersAddresses(family, 0, NULL, adapter_addresses, &bufferSize);
410 if (retval != ERROR_SUCCESS) goto cleanup;
412 for (adapter_addr = adapter_addresses; adapter_addr != NULL; adapter_addr = adapter_addr->Next)
414 if (adapter_addr->FirstUnicastAddress == NULL) continue;
416 sockaddr = adapter_addr->FirstUnicastAddress->Address.lpSockaddr;
418 /* Create a socket and bind to the adapter address */
419 s = socket(family, SOCK_DGRAM, IPPROTO_UDP);
420 if (s == INVALID_SOCKET) continue;
422 if (bind(s, sockaddr, adapter_addr->FirstUnicastAddress->Address.iSockaddrLength) == SOCKET_ERROR)
424 closesocket(s);
425 continue;
428 /* Set the multicast interface and TTL value */
429 setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char *) &i_addr_zero,
430 (family == AF_INET6) ? sizeof(struct in6_addr) : sizeof(struct in_addr));
431 setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
433 sendto(s, data, length, 0, (SOCKADDR *) multi_address->ai_addr, multi_address->ai_addrlen);
434 closesocket(s);
437 ret = TRUE;
439 cleanup:
440 freeaddrinfo(multi_address);
441 heap_free(adapter_addresses);
442 return ret;
445 typedef struct IWSDiscoveryPublisherNotifyImpl {
446 IWSDiscoveryPublisherNotify IWSDiscoveryPublisherNotify_iface;
447 LONG ref;
448 } IWSDiscoveryPublisherNotifyImpl;
450 static inline IWSDiscoveryPublisherNotifyImpl *impl_from_IWSDiscoveryPublisherNotify(IWSDiscoveryPublisherNotify *iface)
452 return CONTAINING_RECORD(iface, IWSDiscoveryPublisherNotifyImpl, IWSDiscoveryPublisherNotify_iface);
455 static HRESULT WINAPI IWSDiscoveryPublisherNotifyImpl_QueryInterface(IWSDiscoveryPublisherNotify *iface, REFIID riid, void **ppv)
457 IWSDiscoveryPublisherNotifyImpl *This = impl_from_IWSDiscoveryPublisherNotify(iface);
459 if (!ppv)
461 return E_INVALIDARG;
464 *ppv = NULL;
466 if (IsEqualIID(riid, &IID_IUnknown) ||
467 IsEqualIID(riid, &IID_IWSDiscoveryPublisherNotify))
469 *ppv = &This->IWSDiscoveryPublisherNotify_iface;
471 else
473 return E_NOINTERFACE;
476 IUnknown_AddRef((IUnknown*)*ppv);
477 return S_OK;
480 static ULONG WINAPI IWSDiscoveryPublisherNotifyImpl_AddRef(IWSDiscoveryPublisherNotify *iface)
482 IWSDiscoveryPublisherNotifyImpl *This = impl_from_IWSDiscoveryPublisherNotify(iface);
483 ULONG ref = InterlockedIncrement(&This->ref);
485 trace("IWSDiscoveryPublisherNotifyImpl_AddRef called (%p, ref = %d)\n", This, ref);
486 return ref;
489 static ULONG WINAPI IWSDiscoveryPublisherNotifyImpl_Release(IWSDiscoveryPublisherNotify *iface)
491 IWSDiscoveryPublisherNotifyImpl *This = impl_from_IWSDiscoveryPublisherNotify(iface);
492 ULONG ref = InterlockedDecrement(&This->ref);
494 trace("IWSDiscoveryPublisherNotifyImpl_Release called (%p, ref = %d)\n", This, ref);
496 if (ref == 0)
498 HeapFree(GetProcessHeap(), 0, This);
501 return ref;
504 static void verify_wsdxml_name(const char *debug_prefix, WSDXML_NAME *name, LPCWSTR uri, LPCWSTR prefix,
505 LPCWSTR local_name)
507 ok(name != NULL, "%s: name == NULL\n", debug_prefix);
508 if (name == NULL) return;
510 ok(name->LocalName != NULL && lstrcmpW(name->LocalName, local_name) == 0,
511 "%s: Local name = '%s'\n", debug_prefix, wine_dbgstr_w(name->LocalName));
513 ok(name->Space != NULL, "%s: Space == NULL\n", debug_prefix);
514 if (name->Space == NULL) return;
516 ok(name->Space->Uri != NULL && lstrcmpW(name->Space->Uri, uri) == 0,
517 "%s: URI == '%s'\n", debug_prefix, wine_dbgstr_w(name->Space->Uri));
518 ok(name->Space->PreferredPrefix != NULL && lstrcmpW(name->Space->PreferredPrefix, prefix) == 0,
519 "%s: Prefix = '%s'\n", debug_prefix, wine_dbgstr_w(name->Space->PreferredPrefix));
522 static void verify_wsdxml_any_text(const char *debug_prefix, WSDXML_ELEMENT *any, LPCWSTR uri, LPCWSTR prefix,
523 LPCWSTR local_name, LPCWSTR value)
525 WSDXML_TEXT *child;
527 ok(any != NULL, "%s: any == NULL\n", debug_prefix);
528 if (any == NULL) return;
530 child = (WSDXML_TEXT *) any->FirstChild;
532 ok(any->Node.Type == ElementType, "%s: Node type == %d\n", debug_prefix, any->Node.Type);
533 ok(any->Node.Parent == NULL, "%s: Parent == %p\n", debug_prefix, any->Node.Parent);
534 ok(any->Node.Next == NULL, "%s: Next == %p\n", debug_prefix, any->Node.Next);
535 verify_wsdxml_name(debug_prefix, any->Name, uri, prefix, local_name);
537 ok(child != NULL, "%s: First child == NULL\n", debug_prefix);
539 if (child != NULL)
541 ok(child->Node.Type == TextType, "%s: Node type == %d\n", debug_prefix, child->Node.Type);
542 ok(child->Node.Parent == any, "%s: Parent == %p\n", debug_prefix, child->Node.Parent);
543 ok(child->Node.Next == NULL, "%s: Next == %p\n", debug_prefix, child->Node.Next);
545 if (child->Node.Type == TextType)
546 ok(child->Text != NULL && lstrcmpW(child->Text, value) == 0,
547 "%s: Text == '%s'\n", debug_prefix, wine_dbgstr_w(child->Text));
551 static HRESULT WINAPI IWSDiscoveryPublisherNotifyImpl_ProbeHandler(IWSDiscoveryPublisherNotify *This, const WSD_SOAP_MESSAGE *pSoap, IWSDMessageParameters *pMessageParameters)
553 trace("IWSDiscoveryPublisherNotifyImpl_ProbeHandler called (%p, %p, %p)\n", This, pSoap, pMessageParameters);
555 if (probe_event == NULL)
557 /* We may have received an unrelated probe on the network */
558 return S_OK;
561 ok(pSoap != NULL, "pSoap == NULL\n");
562 ok(pMessageParameters != NULL, "pMessageParameters == NULL\n");
564 if (pSoap != NULL)
566 WSD_PROBE *probe_msg = (WSD_PROBE *) pSoap->Body;
567 WSD_APP_SEQUENCE *appseq = (WSD_APP_SEQUENCE *) pSoap->Header.AppSequence;
569 ok(pSoap->Body != NULL, "pSoap->Body == NULL\n");
570 ok(pSoap->Header.To != NULL && lstrcmpW(pSoap->Header.To, L"urn:schemas-xmlsoap-org:ws:2005:04:discovery") == 0,
571 "pSoap->Header.To == '%s'\n", wine_dbgstr_w(pSoap->Header.To));
572 ok(pSoap->Header.Action != NULL && lstrcmpW(pSoap->Header.Action, L"http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe") == 0,
573 "pSoap->Header.Action == '%s'\n", wine_dbgstr_w(pSoap->Header.Action));
575 ok(pSoap->Header.MessageID != NULL, "pSoap->Header.MessageID == NULL\n");
577 /* Ensure the message ID is at least 9 characters long (to skip past the 'urn:uuid:' prefix) */
578 if ((pSoap->Header.MessageID != NULL) && (lstrlenW(pSoap->Header.MessageID) > 9))
580 UUID uuid;
581 RPC_STATUS ret = UuidFromStringW((LPWSTR)pSoap->Header.MessageID + 9, &uuid);
583 trace("Received message with UUID '%s' (expected UUID '%s')\n", wine_dbgstr_guid(&uuid),
584 wine_dbgstr_guid(&probe_message_id));
586 /* Check if we've either received a message without a UUID, or the UUID isn't the one we sent. If so,
587 ignore it and wait for another message. */
588 if ((ret != RPC_S_OK) || (UuidEqual(&uuid, &probe_message_id, &ret) == FALSE)) return S_OK;
591 ok(appseq != NULL, "pSoap->Header.AppSequence == NULL\n");
593 if (appseq != NULL)
595 ok(appseq->InstanceId == 21, "pSoap->Header.AppSequence->InstanceId = %s\n",
596 wine_dbgstr_longlong(appseq->InstanceId));
597 ok(lstrcmpW(appseq->SequenceId, L"urn:uuid:638abee8-124d-4b6a-8b85-8cf2837a2fd2") == 0, "pSoap->Header.AppSequence->SequenceId = '%s'\n",
598 wine_dbgstr_w(appseq->SequenceId));
599 ok(appseq->MessageNumber == 14, "pSoap->Header.AppSequence->MessageNumber = %s\n",
600 wine_dbgstr_longlong(appseq->MessageNumber));
603 verify_wsdxml_any_text("pSoap->Header.AnyHeaders", pSoap->Header.AnyHeaders, uri_more_tests_no_slash,
604 prefix_grog, L"Perry", L"ExtraInfo");
606 if (probe_msg != NULL)
608 IWSDUdpAddress *remote_addr = NULL;
609 HRESULT rc;
611 ok(probe_msg->Types != NULL, "Probe message Types == NULL\n");
613 if (probe_msg->Types != NULL)
615 verify_wsdxml_name("probe_msg->Types->Element", probe_msg->Types->Element, uri_more_tests_no_slash,
616 prefix_grog, name_cider);
617 ok(probe_msg->Types->Next == NULL, "probe_msg->Types->Next == %p\n", probe_msg->Types->Next);
620 ok(probe_msg->Scopes == NULL, "Probe message Scopes != NULL\n");
621 verify_wsdxml_any_text("probe_msg->Any", probe_msg->Any, uri_more_tests_no_slash, prefix_grog, L"Lager", L"MoreInfo");
623 rc = IWSDMessageParameters_GetRemoteAddress(pMessageParameters, (IWSDAddress **) &remote_addr);
624 ok(rc == S_OK, "IWSDMessageParameters_GetRemoteAddress returned %08x\n", rc);
626 if (remote_addr != NULL)
628 messageStorage *msg_storage;
629 char endpoint_reference_string[MAX_PATH], app_sequence_string[MAX_PATH];
630 LPWSTR publisherIdW = NULL, sequenceIdW = NULL;
631 SOCKADDR_STORAGE remote_sock;
632 WSDXML_ELEMENT *header_any_element, *body_any_element, *endpoint_any_element, *ref_param_any_element;
633 WSDXML_NAME header_any_name;
634 WSDXML_NAMESPACE ns;
635 BOOL probe_matches_message_seen = FALSE, endpoint_reference_seen = FALSE, app_sequence_seen = FALSE;
636 BOOL metadata_version_seen = FALSE, wine_ns_seen = FALSE, body_probe_matches_seen = FALSE;
637 BOOL types_seen = FALSE, any_header_seen = FALSE, any_body_seen = FALSE;
638 BOOL message_ok;
639 char *msg;
640 int i;
642 rc = IWSDUdpAddress_GetSockaddr(remote_addr, &remote_sock);
643 ok(rc == S_OK, "IWSDMessageParameters_GetRemoteAddress returned %08x\n", rc);
645 IWSDUdpAddress_Release(remote_addr);
647 msg_storage = heap_alloc_zero(sizeof(messageStorage));
648 if (msg_storage == NULL) goto after_matchprobe_test;
650 msg_storage->running = TRUE;
651 InitializeCriticalSection(&msg_storage->criticalSection);
653 ok(start_listening_udp_unicast(msg_storage, (struct sockaddr_in *) &remote_sock) == TRUE,
654 "Unable to listen on local socket for UDP messages\n");
656 publisherIdW = utf8_to_wide(publisherId);
657 sequenceIdW = utf8_to_wide(sequenceId);
659 /* Create "any" elements for header */
660 ns.Uri = L"http://wine.test/";
661 ns.PreferredPrefix = L"wine";
663 header_any_name.LocalName = (WCHAR *) L"Beer";
664 header_any_name.Space = &ns;
666 rc = WSDXMLBuildAnyForSingleElement(&header_any_name, L"PublishTest", &header_any_element);
667 ok(rc == S_OK, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc);
669 rc = WSDXMLBuildAnyForSingleElement(&header_any_name, L"BodyTest", &body_any_element);
670 ok(rc == S_OK, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc);
672 rc = WSDXMLBuildAnyForSingleElement(&header_any_name, L"EndPTest", &endpoint_any_element);
673 ok(rc == S_OK, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc);
675 rc = WSDXMLBuildAnyForSingleElement(&header_any_name, L"RefPTest", &ref_param_any_element);
676 ok(rc == S_OK, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc);
678 rc = IWSDiscoveryPublisher_MatchProbeEx(publisher_instance, pSoap, pMessageParameters, publisherIdW, 1, 1, 1,
679 sequenceIdW, probe_msg->Types, NULL, NULL, header_any_element, ref_param_any_element, NULL,
680 endpoint_any_element, body_any_element);
681 ok(rc == S_OK, "IWSDiscoveryPublisher_MatchProbeEx failed with %08x\n", rc);
683 WSDFreeLinkedMemory(header_any_element);
684 WSDFreeLinkedMemory(body_any_element);
685 WSDFreeLinkedMemory(endpoint_any_element);
686 WSDFreeLinkedMemory(ref_param_any_element);
688 /* Wait up to 2 seconds for messages to be received */
689 if (WaitForMultipleObjects(msg_storage->numThreadHandles, msg_storage->threadHandles, TRUE, 5000) == WAIT_TIMEOUT)
691 /* Wait up to 1 more second for threads to terminate */
692 msg_storage->running = FALSE;
693 WaitForMultipleObjects(msg_storage->numThreadHandles, msg_storage->threadHandles, TRUE, 1000);
696 for (i = 0; i < msg_storage->numThreadHandles; i++)
698 CloseHandle(msg_storage->threadHandles[i]);
701 DeleteCriticalSection(&msg_storage->criticalSection);
703 /* Verify we've received a message */
704 ok(msg_storage->messageCount >= 1, "No messages received\n");
706 sprintf(endpoint_reference_string, "<wsa:EndpointReference><wsa:Address>%s</wsa:Address>"
707 "<wsa:ReferenceParameters><wine:Beer>RefPTest</wine:Beer></wsa:ReferenceParameters>"
708 "<wine:Beer>EndPTest</wine:Beer></wsa:EndpointReference>", publisherId);
710 sprintf(app_sequence_string, "<wsd:AppSequence InstanceId=\"1\" SequenceId=\"%s\" MessageNumber=\"1\"></wsd:AppSequence>",
711 sequenceId);
713 message_ok = FALSE;
715 /* Check we're received the correct message */
716 for (i = 0; i < msg_storage->messageCount; i++)
718 msg = msg_storage->messages[i];
719 message_ok = FALSE;
721 probe_matches_message_seen = (strstr(msg,
722 "<wsa:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches</wsa:Action>") != NULL);
723 endpoint_reference_seen = (strstr(msg, endpoint_reference_string) != NULL);
724 app_sequence_seen = (strstr(msg, app_sequence_string) != NULL);
725 metadata_version_seen = (strstr(msg, "<wsd:MetadataVersion>1</wsd:MetadataVersion>") != NULL);
726 any_header_seen = (strstr(msg, "<wine:Beer>PublishTest</wine:Beer>") != NULL);
727 wine_ns_seen = (strstr(msg, "xmlns:grog=\"http://more.tests\"") != NULL);
728 body_probe_matches_seen = (strstr(msg, "<soap:Body><wsd:ProbeMatches") != NULL);
729 any_body_seen = (strstr(msg, "<wine:Beer>BodyTest</wine:Beer>") != NULL);
730 types_seen = (strstr(msg, "<wsd:Types>grog:Cider</wsd:Types>") != NULL);
731 message_ok = probe_matches_message_seen && endpoint_reference_seen && app_sequence_seen &&
732 metadata_version_seen && body_probe_matches_seen && types_seen;
734 if (message_ok) break;
737 for (i = 0; i < msg_storage->messageCount; i++)
739 heap_free(msg_storage->messages[i]);
742 ok(probe_matches_message_seen == TRUE, "Probe matches message not received\n");
743 ok(endpoint_reference_seen == TRUE, "EndpointReference not received\n");
744 ok(app_sequence_seen == TRUE, "AppSequence not received\n");
745 ok(metadata_version_seen == TRUE, "MetadataVersion not received\n");
746 ok(message_ok == TRUE, "ProbeMatches message metadata not received\n");
747 ok(any_header_seen == TRUE, "Custom header not received\n");
748 ok(wine_ns_seen == TRUE, "Wine namespace not received\n");
749 ok(body_probe_matches_seen == TRUE, "Body and Probe Matches elements not received\n");
750 ok(any_body_seen == TRUE, "Custom body element not received\n");
751 ok(types_seen == TRUE, "Types not received\n");
753 after_matchprobe_test:
754 heap_free(publisherIdW);
755 heap_free(sequenceIdW);
756 heap_free(msg_storage);
761 SetEvent(probe_event);
762 return S_OK;
765 static HRESULT WINAPI IWSDiscoveryPublisherNotifyImpl_ResolveHandler(IWSDiscoveryPublisherNotify *This, const WSD_SOAP_MESSAGE *pSoap, IWSDMessageParameters *pMessageParameters)
767 trace("IWSDiscoveryPublisherNotifyImpl_ResolveHandler called (%p, %p, %p)\n", This, pSoap, pMessageParameters);
768 return S_OK;
771 static const IWSDiscoveryPublisherNotifyVtbl publisherNotify_vtbl =
773 IWSDiscoveryPublisherNotifyImpl_QueryInterface,
774 IWSDiscoveryPublisherNotifyImpl_AddRef,
775 IWSDiscoveryPublisherNotifyImpl_Release,
776 IWSDiscoveryPublisherNotifyImpl_ProbeHandler,
777 IWSDiscoveryPublisherNotifyImpl_ResolveHandler
780 static BOOL create_discovery_publisher_notify(IWSDiscoveryPublisherNotify **publisherNotify)
782 IWSDiscoveryPublisherNotifyImpl *obj;
784 *publisherNotify = NULL;
786 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
788 if (!obj)
790 trace("Out of memory creating IWSDiscoveryPublisherNotify\n");
791 return FALSE;
794 obj->IWSDiscoveryPublisherNotify_iface.lpVtbl = &publisherNotify_vtbl;
795 obj->ref = 1;
797 *publisherNotify = &obj->IWSDiscoveryPublisherNotify_iface;
799 return TRUE;
802 static void CreateDiscoveryPublisher_tests(void)
804 IWSDiscoveryPublisher *publisher = NULL;
805 IWSDiscoveryPublisher *publisher2;
806 IUnknown *unknown;
807 HRESULT rc;
808 ULONG ref;
810 rc = WSDCreateDiscoveryPublisher(NULL, NULL);
811 ok((rc == E_POINTER) || (rc == E_INVALIDARG), "WSDCreateDiscoveryPublisher(NULL, NULL) failed: %08x\n", rc);
813 rc = WSDCreateDiscoveryPublisher(NULL, &publisher);
814 ok(rc == S_OK, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: %08x\n", rc);
815 ok(publisher != NULL, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: publisher == NULL\n");
817 /* Try to query for objects */
818 rc = IWSDiscoveryPublisher_QueryInterface(publisher, &IID_IUnknown, (LPVOID*)&unknown);
819 ok(rc == S_OK,"IWSDiscoveryPublisher_QueryInterface(IID_IUnknown) failed: %08x\n", rc);
821 if (rc == S_OK)
822 IUnknown_Release(unknown);
824 rc = IWSDiscoveryPublisher_QueryInterface(publisher, &IID_IWSDiscoveryPublisher, (LPVOID*)&publisher2);
825 ok(rc == S_OK,"IWSDiscoveryPublisher_QueryInterface(IID_IWSDiscoveryPublisher) failed: %08x\n", rc);
827 if (rc == S_OK)
828 IWSDiscoveryPublisher_Release(publisher2);
830 ref = IWSDiscoveryPublisher_Release(publisher);
831 ok(ref == 0, "IWSDiscoveryPublisher_Release() has %d references, should have 0\n", ref);
834 static void CreateDiscoveryPublisher_XMLContext_tests(void)
836 IWSDiscoveryPublisher *publisher = NULL;
837 IWSDXMLContext *xmlContext, *returnedContext;
838 HRESULT rc;
839 int ref;
841 /* Test creating an XML context and supplying it to WSDCreateDiscoveryPublisher */
842 rc = WSDXMLCreateContext(&xmlContext);
843 ok(rc == S_OK, "WSDXMLCreateContext failed: %08x\n", rc);
845 rc = WSDCreateDiscoveryPublisher(xmlContext, &publisher);
846 ok(rc == S_OK, "WSDCreateDiscoveryPublisher(xmlContext, &publisher) failed: %08x\n", rc);
847 ok(publisher != NULL, "WSDCreateDiscoveryPublisher(xmlContext, &publisher) failed: publisher == NULL\n");
849 rc = IWSDiscoveryPublisher_GetXMLContext(publisher, NULL);
850 ok(rc == E_INVALIDARG, "GetXMLContext returned unexpected value with NULL argument: %08x\n", rc);
852 rc = IWSDiscoveryPublisher_GetXMLContext(publisher, &returnedContext);
853 ok(rc == S_OK, "GetXMLContext failed: %08x\n", rc);
855 ok(xmlContext == returnedContext, "GetXMLContext returned unexpected value: returnedContext == %p\n", returnedContext);
857 ref = IWSDXMLContext_Release(returnedContext);
858 ok(ref == 2, "IWSDXMLContext_Release() has %d references, should have 2\n", ref);
860 ref = IWSDiscoveryPublisher_Release(publisher);
861 ok(ref == 0, "IWSDiscoveryPublisher_Release() has %d references, should have 0\n", ref);
863 ref = IWSDXMLContext_Release(returnedContext);
864 ok(ref == 0, "IWSDXMLContext_Release() has %d references, should have 0\n", ref);
866 /* Test using a default XML context */
867 publisher = NULL;
868 returnedContext = NULL;
870 rc = WSDCreateDiscoveryPublisher(NULL, &publisher);
871 ok(rc == S_OK, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: %08x\n", rc);
872 ok(publisher != NULL, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: publisher == NULL\n");
874 rc = IWSDiscoveryPublisher_GetXMLContext(publisher, &returnedContext);
875 ok(rc == S_OK, "GetXMLContext failed: %08x\n", rc);
877 ref = IWSDXMLContext_Release(returnedContext);
878 ok(ref == 1, "IWSDXMLContext_Release() has %d references, should have 1\n", ref);
880 ref = IWSDiscoveryPublisher_Release(publisher);
881 ok(ref == 0, "IWSDiscoveryPublisher_Release() has %d references, should have 0\n", ref);
884 static void Publish_tests(void)
886 IWSDiscoveryPublisher *publisher = NULL;
887 IWSDiscoveryPublisherNotify *sink1 = NULL, *sink2 = NULL;
888 IWSDiscoveryPublisherNotifyImpl *sink1Impl = NULL, *sink2Impl = NULL;
889 char endpointReferenceString[MAX_PATH], app_sequence_string[MAX_PATH];
890 LPWSTR publisherIdW = NULL, sequenceIdW = NULL;
891 messageStorage *msgStorage;
892 WSADATA wsaData;
893 BOOL messageOK, hello_message_seen = FALSE, endpoint_reference_seen = FALSE, app_sequence_seen = FALSE;
894 BOOL metadata_version_seen = FALSE, any_header_seen = FALSE, wine_ns_seen = FALSE, body_hello_seen = FALSE;
895 BOOL any_body_seen = FALSE, types_seen = FALSE, xml_namespaces_seen = FALSE, scopes_seen = FALSE;
896 BOOL xaddrs_seen = FALSE;
897 int ret, i;
898 HRESULT rc;
899 ULONG ref;
900 char *msg;
901 WSDXML_ELEMENT *header_any_element, *body_any_element, *endpoint_any_element, *ref_param_any_element;
902 WSDXML_NAME header_any_name, another_name;
903 WSDXML_NAMESPACE ns, ns2;
904 static const WCHAR *uri = L"http://wine.test/";
905 WSD_NAME_LIST types_list;
906 WSD_URI_LIST scopes_list, xaddrs_list;
907 unsigned char *probe_uuid_str;
909 rc = WSDCreateDiscoveryPublisher(NULL, &publisher);
910 ok(rc == S_OK, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: %08x\n", rc);
911 ok(publisher != NULL, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: publisher == NULL\n");
913 publisher_instance = publisher;
915 /* Test SetAddressFamily */
916 rc = IWSDiscoveryPublisher_SetAddressFamily(publisher, 12345);
917 ok(rc == E_INVALIDARG, "IWSDiscoveryPublisher_SetAddressFamily(12345) returned unexpected result: %08x\n", rc);
919 rc = IWSDiscoveryPublisher_SetAddressFamily(publisher, WSDAPI_ADDRESSFAMILY_IPV4);
920 ok(rc == S_OK, "IWSDiscoveryPublisher_SetAddressFamily(WSDAPI_ADDRESSFAMILY_IPV4) failed: %08x\n", rc);
922 /* Try to update the address family after already setting it */
923 rc = IWSDiscoveryPublisher_SetAddressFamily(publisher, WSDAPI_ADDRESSFAMILY_IPV6);
924 ok(rc == STG_E_INVALIDFUNCTION, "IWSDiscoveryPublisher_SetAddressFamily(WSDAPI_ADDRESSFAMILY_IPV6) returned unexpected result: %08x\n", rc);
926 /* Create notification sinks */
927 ok(create_discovery_publisher_notify(&sink1) == TRUE, "create_discovery_publisher_notify failed\n");
928 ok(create_discovery_publisher_notify(&sink2) == TRUE, "create_discovery_publisher_notify failed\n");
930 /* Get underlying implementation so we can check the ref count */
931 sink1Impl = impl_from_IWSDiscoveryPublisherNotify(sink1);
932 sink2Impl = impl_from_IWSDiscoveryPublisherNotify(sink2);
934 /* Attempt to unregister sink before registering it */
935 rc = IWSDiscoveryPublisher_UnRegisterNotificationSink(publisher, sink1);
936 ok(rc == E_FAIL, "IWSDiscoveryPublisher_UnRegisterNotificationSink returned unexpected result: %08x\n", rc);
938 /* Register notification sinks */
939 rc = IWSDiscoveryPublisher_RegisterNotificationSink(publisher, sink1);
940 ok(rc == S_OK, "IWSDiscoveryPublisher_RegisterNotificationSink failed: %08x\n", rc);
941 ok(sink1Impl->ref == 2, "Ref count for sink 1 is not as expected: %d\n", sink1Impl->ref);
943 rc = IWSDiscoveryPublisher_RegisterNotificationSink(publisher, sink2);
944 ok(rc == S_OK, "IWSDiscoveryPublisher_RegisterNotificationSink failed: %08x\n", rc);
945 ok(sink2Impl->ref == 2, "Ref count for sink 2 is not as expected: %d\n", sink2Impl->ref);
947 /* Unregister the first sink */
948 rc = IWSDiscoveryPublisher_UnRegisterNotificationSink(publisher, sink1);
949 ok(rc == S_OK, "IWSDiscoveryPublisher_UnRegisterNotificationSink failed: %08x\n", rc);
950 ok(sink1Impl->ref == 1, "Ref count for sink 1 is not as expected: %d\n", sink1Impl->ref);
952 /* Set up network listener */
953 publisherIdW = utf8_to_wide(publisherId);
954 if (publisherIdW == NULL) goto after_publish_test;
956 sequenceIdW = utf8_to_wide(sequenceId);
957 if (sequenceIdW == NULL) goto after_publish_test;
959 msgStorage = heap_alloc_zero(sizeof(messageStorage));
960 if (msgStorage == NULL) goto after_publish_test;
962 msgStorage->running = TRUE;
963 InitializeCriticalSection(&msgStorage->criticalSection);
965 ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
966 ok(ret == 0, "WSAStartup failed (ret = %d)\n", ret);
968 ret = start_listening_on_all_addresses(msgStorage, AF_INET);
969 ok(ret == TRUE, "Unable to listen on IPv4 addresses (ret == %d)\n", ret);
971 /* Create "any" elements for header */
972 ns.Uri = uri;
973 ns.PreferredPrefix = L"wine";
975 header_any_name.LocalName = (WCHAR *) L"Beer";
976 header_any_name.Space = &ns;
978 rc = WSDXMLBuildAnyForSingleElement(&header_any_name, L"PublishTest", &header_any_element);
979 ok(rc == S_OK, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc);
981 rc = WSDXMLBuildAnyForSingleElement(&header_any_name, L"BodyTest", &body_any_element);
982 ok(rc == S_OK, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc);
984 rc = WSDXMLBuildAnyForSingleElement(&header_any_name, L"EndPTest", &endpoint_any_element);
985 ok(rc == S_OK, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc);
987 rc = WSDXMLBuildAnyForSingleElement(&header_any_name, L"RefPTest", &ref_param_any_element);
988 ok(rc == S_OK, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc);
990 /* Create types list */
991 ns2.Uri = uri_more_tests;
992 ns2.PreferredPrefix = prefix_grog;
994 another_name.LocalName = (WCHAR *) name_cider;
995 another_name.Space = &ns2;
997 types_list.Next = heap_alloc(sizeof(WSD_NAME_LIST));
998 types_list.Element = &another_name;
1000 types_list.Next->Next = NULL;
1001 types_list.Next->Element = &header_any_name;
1003 /* Create scopes and xaddrs lists */
1004 scopes_list.Next = heap_alloc(sizeof(WSD_URI_LIST));
1005 scopes_list.Element = uri;
1007 scopes_list.Next->Next = NULL;
1008 scopes_list.Next->Element = uri_more_tests;
1010 xaddrs_list.Next = heap_alloc(sizeof(WSD_URI_LIST));
1011 xaddrs_list.Element = uri_more_tests;
1013 xaddrs_list.Next->Next = NULL;
1014 xaddrs_list.Next->Element = L"http://third.url/";
1016 /* Publish the service */
1017 rc = IWSDiscoveryPublisher_PublishEx(publisher, publisherIdW, 1, 1, 1, sequenceIdW, &types_list, &scopes_list,
1018 &xaddrs_list, header_any_element, ref_param_any_element, NULL, endpoint_any_element, body_any_element);
1020 WSDFreeLinkedMemory(header_any_element);
1021 WSDFreeLinkedMemory(body_any_element);
1022 WSDFreeLinkedMemory(endpoint_any_element);
1023 WSDFreeLinkedMemory(ref_param_any_element);
1024 heap_free(types_list.Next);
1025 heap_free(scopes_list.Next);
1026 heap_free(xaddrs_list.Next);
1028 ok(rc == S_OK, "Publish failed: %08x\n", rc);
1030 /* Wait up to 2 seconds for messages to be received */
1031 if (WaitForMultipleObjects(msgStorage->numThreadHandles, msgStorage->threadHandles, TRUE, 2000) == WAIT_TIMEOUT)
1033 /* Wait up to 1 more second for threads to terminate */
1034 msgStorage->running = FALSE;
1035 WaitForMultipleObjects(msgStorage->numThreadHandles, msgStorage->threadHandles, TRUE, 1000);
1038 DeleteCriticalSection(&msgStorage->criticalSection);
1040 /* Verify we've received a message */
1041 ok(msgStorage->messageCount >= 1, "No messages received\n");
1043 sprintf(endpointReferenceString, "<wsa:EndpointReference><wsa:Address>%s</wsa:Address><wsa:ReferenceParameters>"
1044 "<wine:Beer>RefPTest</wine:Beer></wsa:ReferenceParameters><wine:Beer>EndPTest</wine:Beer>"
1045 "</wsa:EndpointReference>", publisherId);
1047 sprintf(app_sequence_string, "<wsd:AppSequence InstanceId=\"1\" SequenceId=\"%s\" MessageNumber=\"1\"></wsd:AppSequence>",
1048 sequenceId);
1050 messageOK = FALSE;
1052 /* Check we're received the correct message */
1053 for (i = 0; i < msgStorage->messageCount; i++)
1055 msg = msgStorage->messages[i];
1056 messageOK = FALSE;
1058 hello_message_seen = (strstr(msg, "<wsa:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/Hello</wsa:Action>") != NULL);
1059 endpoint_reference_seen = (strstr(msg, endpointReferenceString) != NULL);
1060 app_sequence_seen = (strstr(msg, app_sequence_string) != NULL);
1061 metadata_version_seen = (strstr(msg, "<wsd:MetadataVersion>1</wsd:MetadataVersion>") != NULL);
1062 any_header_seen = (strstr(msg, "<wine:Beer>PublishTest</wine:Beer>") != NULL);
1063 wine_ns_seen = (strstr(msg, "xmlns:wine=\"http://wine.test/\"") != NULL);
1064 body_hello_seen = (strstr(msg, "<soap:Body><wsd:Hello") != NULL);
1065 any_body_seen = (strstr(msg, "<wine:Beer>BodyTest</wine:Beer>") != NULL);
1066 types_seen = (strstr(msg, "<wsd:Types>grog:Cider wine:Beer</wsd:Types>") != NULL);
1067 scopes_seen = (strstr(msg, "<wsd:Scopes>http://wine.test/ http://more.tests/</wsd:Scopes>") != NULL);
1068 xaddrs_seen = (strstr(msg, "<wsd:XAddrs>http://more.tests/ http://third.url/</wsd:XAddrs>") != NULL);
1069 xml_namespaces_seen = (strstr(msg, "xmlns:wine=\"http://wine.test/\" xmlns:grog=\"http://more.tests/\"") != NULL);
1070 messageOK = hello_message_seen && endpoint_reference_seen && app_sequence_seen && metadata_version_seen &&
1071 any_header_seen && wine_ns_seen && body_hello_seen && any_body_seen && types_seen && xml_namespaces_seen &&
1072 scopes_seen && xaddrs_seen;
1074 if (messageOK) break;
1077 for (i = 0; i < msgStorage->messageCount; i++)
1079 heap_free(msgStorage->messages[i]);
1082 heap_free(msgStorage);
1084 ok(hello_message_seen == TRUE, "Hello message not received\n");
1085 ok(endpoint_reference_seen == TRUE, "EndpointReference not received\n");
1086 ok(app_sequence_seen == TRUE, "AppSequence not received\n");
1087 ok(metadata_version_seen == TRUE, "MetadataVersion not received\n");
1088 ok(messageOK == TRUE, "Hello message metadata not received\n");
1089 ok(any_header_seen == TRUE, "Custom header not received\n");
1090 ok(wine_ns_seen == TRUE, "Wine namespace not received\n");
1091 ok(body_hello_seen == TRUE, "Body and Hello elements not received\n");
1092 ok(any_body_seen == TRUE, "Custom body element not received\n");
1093 ok(types_seen == TRUE, "Types not received\n");
1094 ok(xml_namespaces_seen == TRUE, "XML namespaces not received\n");
1095 ok(scopes_seen == TRUE, "Scopes not received\n");
1096 ok(xaddrs_seen == TRUE, "XAddrs not received\n");
1098 after_publish_test:
1100 heap_free(publisherIdW);
1101 heap_free(sequenceIdW);
1103 /* Test the receiving of a probe message */
1104 probe_event = CreateEventW(NULL, TRUE, FALSE, NULL);
1106 UuidCreate(&probe_message_id);
1107 UuidToStringA(&probe_message_id, &probe_uuid_str);
1109 ok(probe_uuid_str != NULL, "Failed to create UUID for probe message\n");
1111 if (probe_uuid_str != NULL)
1113 char probe_message[sizeof(testProbeMessage) + 50];
1114 sprintf(probe_message, testProbeMessage, probe_uuid_str);
1116 ok(send_udp_multicast_of_type(probe_message, strlen(probe_message), AF_INET) == TRUE, "Sending Probe message failed\n");
1117 ok(WaitForSingleObject(probe_event, 10000) == WAIT_OBJECT_0, "Probe message not received\n");
1119 RpcStringFreeA(&probe_uuid_str);
1122 CloseHandle(probe_event);
1124 ref = IWSDiscoveryPublisher_Release(publisher);
1125 ok(ref == 0, "IWSDiscoveryPublisher_Release() has %d references, should have 0\n", ref);
1127 /* Check that the sinks have been released by the publisher */
1128 ok(sink1Impl->ref == 1, "Ref count for sink 1 is not as expected: %d\n", sink1Impl->ref);
1129 ok(sink2Impl->ref == 1, "Ref count for sink 2 is not as expected: %d\n", sink2Impl->ref);
1131 /* Release the sinks */
1132 IWSDiscoveryPublisherNotify_Release(sink1);
1133 IWSDiscoveryPublisherNotify_Release(sink2);
1135 WSACleanup();
1138 static void UnPublish_tests(void)
1140 IWSDiscoveryPublisher *publisher = NULL;
1141 IWSDiscoveryPublisherNotify *sink1 = NULL;
1142 char endpoint_reference_string[MAX_PATH], app_sequence_string[MAX_PATH];
1143 LPWSTR publisherIdW = NULL, sequenceIdW = NULL;
1144 messageStorage *msg_storage;
1145 WSADATA wsa_data;
1146 BOOL message_ok, hello_message_seen = FALSE, endpoint_reference_seen = FALSE, app_sequence_seen = FALSE;
1147 BOOL wine_ns_seen = FALSE, body_hello_seen = FALSE, any_body_seen = FALSE;
1148 int ret, i;
1149 HRESULT rc;
1150 ULONG ref;
1151 char *msg;
1152 WSDXML_ELEMENT *body_any_element;
1153 WSDXML_NAME body_any_name;
1154 WSDXML_NAMESPACE ns;
1156 rc = WSDCreateDiscoveryPublisher(NULL, &publisher);
1157 ok(rc == S_OK, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: %08x\n", rc);
1158 ok(publisher != NULL, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: publisher == NULL\n");
1160 rc = IWSDiscoveryPublisher_SetAddressFamily(publisher, WSDAPI_ADDRESSFAMILY_IPV4);
1161 ok(rc == S_OK, "IWSDiscoveryPublisher_SetAddressFamily(WSDAPI_ADDRESSFAMILY_IPV4) failed: %08x\n", rc);
1163 /* Create notification sink */
1164 ok(create_discovery_publisher_notify(&sink1) == TRUE, "create_discovery_publisher_notify failed\n");
1165 rc = IWSDiscoveryPublisher_RegisterNotificationSink(publisher, sink1);
1166 ok(rc == S_OK, "IWSDiscoveryPublisher_RegisterNotificationSink failed: %08x\n", rc);
1168 /* Set up network listener */
1169 publisherIdW = utf8_to_wide(publisherId);
1170 if (publisherIdW == NULL) goto after_unpublish_test;
1172 sequenceIdW = utf8_to_wide(sequenceId);
1173 if (sequenceIdW == NULL) goto after_unpublish_test;
1175 msg_storage = heap_alloc_zero(sizeof(messageStorage));
1176 if (msg_storage == NULL) goto after_unpublish_test;
1178 msg_storage->running = TRUE;
1179 InitializeCriticalSection(&msg_storage->criticalSection);
1181 ret = WSAStartup(MAKEWORD(2, 2), &wsa_data);
1182 ok(ret == 0, "WSAStartup failed (ret = %d)\n", ret);
1184 ret = start_listening_on_all_addresses(msg_storage, AF_INET);
1185 ok(ret == TRUE, "Unable to listen on IPv4 addresses (ret == %d)\n", ret);
1187 /* Create "any" elements for header */
1188 ns.Uri = L"http://wine.test/";
1189 ns.PreferredPrefix = L"wine";
1191 body_any_name.LocalName = (WCHAR *) L"Beer";
1192 body_any_name.Space = &ns;
1194 rc = WSDXMLBuildAnyForSingleElement(&body_any_name, L"BodyTest", &body_any_element);
1195 ok(rc == S_OK, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc);
1197 /* Unpublish the service */
1198 rc = IWSDiscoveryPublisher_UnPublish(publisher, publisherIdW, 1, 1, sequenceIdW, body_any_element);
1200 WSDFreeLinkedMemory(body_any_element);
1202 ok(rc == S_OK, "Unpublish failed: %08x\n", rc);
1204 /* Wait up to 2 seconds for messages to be received */
1205 if (WaitForMultipleObjects(msg_storage->numThreadHandles, msg_storage->threadHandles, TRUE, 2000) == WAIT_TIMEOUT)
1207 /* Wait up to 1 more second for threads to terminate */
1208 msg_storage->running = FALSE;
1209 WaitForMultipleObjects(msg_storage->numThreadHandles, msg_storage->threadHandles, TRUE, 1000);
1212 DeleteCriticalSection(&msg_storage->criticalSection);
1214 /* Verify we've received a message */
1215 ok(msg_storage->messageCount >= 1, "No messages received\n");
1217 sprintf(endpoint_reference_string, "<wsa:EndpointReference><wsa:Address>%s</wsa:Address></wsa:EndpointReference>",
1218 publisherId);
1219 sprintf(app_sequence_string, "<wsd:AppSequence InstanceId=\"1\" SequenceId=\"%s\" MessageNumber=\"1\"></wsd:AppSequence>",
1220 sequenceId);
1222 message_ok = FALSE;
1224 /* Check we're received the correct message */
1225 for (i = 0; i < msg_storage->messageCount; i++)
1227 msg = msg_storage->messages[i];
1228 message_ok = FALSE;
1230 hello_message_seen = (strstr(msg, "<wsa:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/Bye</wsa:Action>") != NULL);
1231 endpoint_reference_seen = (strstr(msg, endpoint_reference_string) != NULL);
1232 app_sequence_seen = (strstr(msg, app_sequence_string) != NULL);
1233 wine_ns_seen = (strstr(msg, "xmlns:wine=\"http://wine.test/\"") != NULL);
1234 body_hello_seen = (strstr(msg, "<soap:Body><wsd:Bye") != NULL);
1235 any_body_seen = (strstr(msg, "<wine:Beer>BodyTest</wine:Beer>") != NULL);
1236 message_ok = hello_message_seen && endpoint_reference_seen && app_sequence_seen && wine_ns_seen &&
1237 body_hello_seen && any_body_seen;
1239 if (message_ok) break;
1242 for (i = 0; i < msg_storage->messageCount; i++)
1244 heap_free(msg_storage->messages[i]);
1247 heap_free(msg_storage);
1249 ok(hello_message_seen == TRUE, "Bye message not received\n");
1250 ok(endpoint_reference_seen == TRUE, "EndpointReference not received\n");
1251 ok(app_sequence_seen == TRUE, "AppSequence not received\n");
1252 ok(message_ok == TRUE, "Bye message metadata not received\n");
1253 ok(wine_ns_seen == TRUE, "Wine namespace not received\n");
1254 ok(body_hello_seen == TRUE, "Body and Bye elements not received\n");
1255 ok(any_body_seen == TRUE, "Custom body element not received\n");
1257 after_unpublish_test:
1259 heap_free(publisherIdW);
1260 heap_free(sequenceIdW);
1262 ref = IWSDiscoveryPublisher_Release(publisher);
1263 ok(ref == 0, "IWSDiscoveryPublisher_Release() has %d references, should have 0\n", ref);
1265 /* Release the sinks */
1266 IWSDiscoveryPublisherNotify_Release(sink1);
1268 WSACleanup();
1271 enum firewall_op
1273 APP_ADD,
1274 APP_REMOVE
1277 static BOOL is_process_elevated(void)
1279 HANDLE token;
1280 if (OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &token ))
1282 TOKEN_ELEVATION_TYPE type;
1283 DWORD size;
1284 BOOL ret;
1286 ret = GetTokenInformation( token, TokenElevationType, &type, sizeof(type), &size );
1287 CloseHandle( token );
1288 return (ret && type == TokenElevationTypeFull);
1290 return FALSE;
1293 static BOOL is_firewall_enabled(void)
1295 HRESULT hr, init;
1296 INetFwMgr *mgr = NULL;
1297 INetFwPolicy *policy = NULL;
1298 INetFwProfile *profile = NULL;
1299 VARIANT_BOOL enabled = VARIANT_FALSE;
1301 init = CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
1303 hr = CoCreateInstance( &CLSID_NetFwMgr, NULL, CLSCTX_INPROC_SERVER, &IID_INetFwMgr,
1304 (void **)&mgr );
1305 ok( hr == S_OK, "got %08x\n", hr );
1306 if (hr != S_OK) goto done;
1308 hr = INetFwMgr_get_LocalPolicy( mgr, &policy );
1309 ok( hr == S_OK, "got %08x\n", hr );
1310 if (hr != S_OK) goto done;
1312 hr = INetFwPolicy_get_CurrentProfile( policy, &profile );
1313 if (hr != S_OK) goto done;
1315 hr = INetFwProfile_get_FirewallEnabled( profile, &enabled );
1316 ok( hr == S_OK, "got %08x\n", hr );
1318 done:
1319 if (policy) INetFwPolicy_Release( policy );
1320 if (profile) INetFwProfile_Release( profile );
1321 if (mgr) INetFwMgr_Release( mgr );
1322 if (SUCCEEDED( init )) CoUninitialize();
1323 return (enabled == VARIANT_TRUE);
1326 static HRESULT set_firewall( enum firewall_op op )
1328 HRESULT hr, init;
1329 INetFwMgr *mgr = NULL;
1330 INetFwPolicy *policy = NULL;
1331 INetFwProfile *profile = NULL;
1332 INetFwAuthorizedApplication *app = NULL;
1333 INetFwAuthorizedApplications *apps = NULL;
1334 BSTR name, image = SysAllocStringLen( NULL, MAX_PATH );
1336 if (!GetModuleFileNameW( NULL, image, MAX_PATH ))
1338 SysFreeString( image );
1339 return E_FAIL;
1341 init = CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
1343 hr = CoCreateInstance( &CLSID_NetFwMgr, NULL, CLSCTX_INPROC_SERVER, &IID_INetFwMgr,
1344 (void **)&mgr );
1345 ok( hr == S_OK, "got %08x\n", hr );
1346 if (hr != S_OK) goto done;
1348 hr = INetFwMgr_get_LocalPolicy( mgr, &policy );
1349 ok( hr == S_OK, "got %08x\n", hr );
1350 if (hr != S_OK) goto done;
1352 hr = INetFwPolicy_get_CurrentProfile( policy, &profile );
1353 if (hr != S_OK) goto done;
1355 hr = INetFwProfile_get_AuthorizedApplications( profile, &apps );
1356 ok( hr == S_OK, "got %08x\n", hr );
1357 if (hr != S_OK) goto done;
1359 hr = CoCreateInstance( &CLSID_NetFwAuthorizedApplication, NULL, CLSCTX_INPROC_SERVER,
1360 &IID_INetFwAuthorizedApplication, (void **)&app );
1361 ok( hr == S_OK, "got %08x\n", hr );
1362 if (hr != S_OK) goto done;
1364 hr = INetFwAuthorizedApplication_put_ProcessImageFileName( app, image );
1365 if (hr != S_OK) goto done;
1367 name = SysAllocString( L"wsdapi_test" );
1368 hr = INetFwAuthorizedApplication_put_Name( app, name );
1369 SysFreeString( name );
1370 ok( hr == S_OK, "got %08x\n", hr );
1371 if (hr != S_OK) goto done;
1373 if (op == APP_ADD)
1374 hr = INetFwAuthorizedApplications_Add( apps, app );
1375 else if (op == APP_REMOVE)
1376 hr = INetFwAuthorizedApplications_Remove( apps, image );
1377 else
1378 hr = E_INVALIDARG;
1380 done:
1381 if (app) INetFwAuthorizedApplication_Release( app );
1382 if (apps) INetFwAuthorizedApplications_Release( apps );
1383 if (policy) INetFwPolicy_Release( policy );
1384 if (profile) INetFwProfile_Release( profile );
1385 if (mgr) INetFwMgr_Release( mgr );
1386 if (SUCCEEDED( init )) CoUninitialize();
1387 SysFreeString( image );
1388 return hr;
1391 START_TEST(discovery)
1393 BOOL firewall_enabled = is_firewall_enabled();
1394 HRESULT hr;
1396 if (firewall_enabled)
1398 if (!is_process_elevated())
1400 skip("no privileges, skipping tests to avoid firewall dialog\n");
1401 return;
1403 if ((hr = set_firewall(APP_ADD)) != S_OK)
1405 skip("can't authorize app in firewall %08x\n", hr);
1406 return;
1410 CoInitialize(NULL);
1412 CreateDiscoveryPublisher_tests();
1413 CreateDiscoveryPublisher_XMLContext_tests();
1414 Publish_tests();
1415 UnPublish_tests();
1417 CoUninitialize();
1418 if (firewall_enabled) set_firewall(APP_REMOVE);