2 * Web Services on Devices
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
28 #include "wine/test.h"
29 #include "wine/heap.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 "<grog:Perry>ExtraInfo</grog:Perry></soap:Header>"
52 "<soap:Body><wsd:Probe><wsd:Types>grog:Cider</wsd:Types><grog:Lager>MoreInfo</grog:Lager></wsd:Probe></soap:Body></soap:Envelope>";
54 static const WCHAR discoveryTo
[] = {
56 's','c','h','e','m','a','s','-','x','m','l','s','o','a','p','-','o','r','g',':',
57 'w','s',':','2','0','0','5',':','0','4',':',
58 'd','i','s','c','o','v','e','r','y', 0 };
60 static const WCHAR actionProbe
[] = {
61 'h','t','t','p',':','/','/',
62 's','c','h','e','m','a','s','.','x','m','l','s','o','a','p','.','o','r','g','/',
63 'w','s','/','2','0','0','5','/','0','4','/',
64 'd','i','s','c','o','v','e','r','y','/',
65 'P','r','o','b','e', 0 };
67 static const WCHAR uri_more_tests
[] = { 'h','t','t','p',':','/','/','m','o','r','e','.','t','e','s','t','s','/', 0 };
68 static const WCHAR uri_more_tests_no_slash
[] = { 'h','t','t','p',':','/','/','m','o','r','e','.','t','e','s','t','s', 0 };
69 static const WCHAR prefix_grog
[] = { 'g','r','o','g', 0 };
70 static const WCHAR name_cider
[] = { 'C','i','d','e','r', 0 };
72 static HANDLE probe_event
= NULL
;
73 static UUID probe_message_id
;
75 #define MAX_CACHED_MESSAGES 5
76 #define MAX_LISTENING_THREADS 20
78 typedef struct messageStorage
{
80 CRITICAL_SECTION criticalSection
;
81 char* messages
[MAX_CACHED_MESSAGES
];
83 HANDLE threadHandles
[MAX_LISTENING_THREADS
];
87 static LPWSTR
utf8_to_wide(const char *utf8String
)
89 int sizeNeeded
= 0, utf8StringLength
= 0, memLength
= 0;
90 LPWSTR newString
= NULL
;
92 if (utf8String
== NULL
) return NULL
;
93 utf8StringLength
= lstrlenA(utf8String
);
95 sizeNeeded
= MultiByteToWideChar(CP_UTF8
, 0, utf8String
, utf8StringLength
, NULL
, 0);
96 if (sizeNeeded
<= 0) return NULL
;
98 memLength
= sizeof(WCHAR
) * (sizeNeeded
+ 1);
99 newString
= heap_alloc_zero(memLength
);
101 MultiByteToWideChar(CP_UTF8
, 0, utf8String
, utf8StringLength
, newString
, sizeNeeded
);
105 static int join_multicast_group(SOCKET s
, struct addrinfo
*group
, struct addrinfo
*iface
)
107 int level
, optname
, optlen
;
108 struct ipv6_mreq mreqv6
;
109 struct ip_mreq mreqv4
;
112 if (group
->ai_family
== AF_INET6
)
114 level
= IPPROTO_IPV6
;
115 optname
= IPV6_ADD_MEMBERSHIP
;
116 optval
= (char *)&mreqv6
;
117 optlen
= sizeof(mreqv6
);
119 mreqv6
.ipv6mr_multiaddr
= ((SOCKADDR_IN6
*)group
->ai_addr
)->sin6_addr
;
120 mreqv6
.ipv6mr_interface
= ((SOCKADDR_IN6
*)iface
->ai_addr
)->sin6_scope_id
;
125 optname
= IP_ADD_MEMBERSHIP
;
126 optval
= (char *)&mreqv4
;
127 optlen
= sizeof(mreqv4
);
129 mreqv4
.imr_multiaddr
.s_addr
= ((SOCKADDR_IN
*)group
->ai_addr
)->sin_addr
.s_addr
;
130 mreqv4
.imr_interface
.s_addr
= ((SOCKADDR_IN
*)iface
->ai_addr
)->sin_addr
.s_addr
;
133 return setsockopt(s
, level
, optname
, optval
, optlen
);
136 static int set_send_interface(SOCKET s
, struct addrinfo
*iface
)
138 int level
, optname
, optlen
;
141 if (iface
->ai_family
== AF_INET6
)
143 level
= IPPROTO_IPV6
;
144 optname
= IPV6_MULTICAST_IF
;
145 optval
= (char *) &((SOCKADDR_IN6
*)iface
->ai_addr
)->sin6_scope_id
;
146 optlen
= sizeof(((SOCKADDR_IN6
*)iface
->ai_addr
)->sin6_scope_id
);
151 optname
= IP_MULTICAST_IF
;
152 optval
= (char *) &((SOCKADDR_IN
*)iface
->ai_addr
)->sin_addr
.s_addr
;
153 optlen
= sizeof(((SOCKADDR_IN
*)iface
->ai_addr
)->sin_addr
.s_addr
);
156 return setsockopt(s
, level
, optname
, optval
, optlen
);
159 static struct addrinfo
*resolve_address(const char *address
, const char *port
, int family
, int type
, int protocol
)
161 struct addrinfo hints
, *result
= NULL
;
163 ZeroMemory(&hints
, sizeof(hints
));
165 hints
.ai_flags
= AI_PASSIVE
;
166 hints
.ai_family
= family
;
167 hints
.ai_socktype
= type
;
168 hints
.ai_protocol
= protocol
;
170 return getaddrinfo(address
, port
, &hints
, &result
) == 0 ? result
: NULL
;
173 typedef struct listenerThreadParams
175 messageStorage
*msgStorage
;
176 SOCKET listeningSocket
;
177 } listenerThreadParams
;
179 #define RECEIVE_BUFFER_SIZE 65536
181 static DWORD WINAPI
listening_thread(LPVOID lpParam
)
183 listenerThreadParams
*parameter
= (listenerThreadParams
*)lpParam
;
184 messageStorage
*msgStorage
= parameter
->msgStorage
;
188 buffer
= heap_alloc(RECEIVE_BUFFER_SIZE
);
190 while (parameter
->msgStorage
->running
)
192 ZeroMemory(buffer
, RECEIVE_BUFFER_SIZE
);
193 bytesReceived
= recv(parameter
->listeningSocket
, buffer
, RECEIVE_BUFFER_SIZE
, 0);
195 if (bytesReceived
== SOCKET_ERROR
)
197 if (WSAGetLastError() != WSAETIMEDOUT
)
202 EnterCriticalSection(&msgStorage
->criticalSection
);
204 if (msgStorage
->messageCount
< MAX_CACHED_MESSAGES
)
206 msgStorage
->messages
[msgStorage
->messageCount
] = heap_alloc(bytesReceived
);
208 if (msgStorage
->messages
[msgStorage
->messageCount
] != NULL
)
210 memcpy(msgStorage
->messages
[msgStorage
->messageCount
], buffer
, bytesReceived
);
211 msgStorage
->messageCount
++;
215 LeaveCriticalSection(&msgStorage
->criticalSection
);
217 if (msgStorage
->messageCount
>= MAX_CACHED_MESSAGES
)
219 /* Stop all threads */
220 msgStorage
->running
= FALSE
;
226 closesocket(parameter
->listeningSocket
);
229 heap_free(parameter
);
234 static void start_listening(messageStorage
*msgStorage
, const char *multicastAddress
, const char *bindAddress
)
236 struct addrinfo
*multicastAddr
= NULL
, *bindAddr
= NULL
, *interfaceAddr
= NULL
;
237 listenerThreadParams
*parameter
= NULL
;
238 const DWORD receiveTimeout
= 500;
239 const UINT reuseAddr
= 1;
243 /* Resolve the multicast address */
244 multicastAddr
= resolve_address(multicastAddress
, SEND_PORT
, AF_UNSPEC
, SOCK_DGRAM
, IPPROTO_UDP
);
245 if (multicastAddr
== NULL
) goto cleanup
;
247 /* Resolve the binding address */
248 bindAddr
= resolve_address(bindAddress
, SEND_PORT
, multicastAddr
->ai_family
, multicastAddr
->ai_socktype
, multicastAddr
->ai_protocol
);
249 if (bindAddr
== NULL
) goto cleanup
;
251 /* Resolve the multicast interface */
252 interfaceAddr
= resolve_address(bindAddress
, "0", multicastAddr
->ai_family
, multicastAddr
->ai_socktype
, multicastAddr
->ai_protocol
);
253 if (interfaceAddr
== NULL
) goto cleanup
;
255 /* Create the socket */
256 s
= socket(multicastAddr
->ai_family
, multicastAddr
->ai_socktype
, multicastAddr
->ai_protocol
);
257 if (s
== INVALID_SOCKET
) goto cleanup
;
259 /* Ensure the socket can be reused */
260 if (setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, (const char *)&reuseAddr
, sizeof(reuseAddr
)) == SOCKET_ERROR
) goto cleanup
;
262 /* Bind the socket to the local interface so we can receive data */
263 if (bind(s
, bindAddr
->ai_addr
, bindAddr
->ai_addrlen
) == SOCKET_ERROR
) goto cleanup
;
265 /* Join the multicast group */
266 if (join_multicast_group(s
, multicastAddr
, interfaceAddr
) == SOCKET_ERROR
) goto cleanup
;
268 /* Set the outgoing interface */
269 if (set_send_interface(s
, interfaceAddr
) == SOCKET_ERROR
) goto cleanup
;
271 /* For IPv6, ensure the scope ID is zero */
272 if (multicastAddr
->ai_family
== AF_INET6
)
273 ((SOCKADDR_IN6
*)multicastAddr
->ai_addr
)->sin6_scope_id
= 0;
275 /* Set a 500ms receive timeout */
276 if (setsockopt(s
, SOL_SOCKET
, SO_RCVTIMEO
, (const char *)&receiveTimeout
, sizeof(receiveTimeout
)) == SOCKET_ERROR
) goto cleanup
;
278 /* Allocate memory for thread parameters */
279 parameter
= heap_alloc(sizeof(listenerThreadParams
));
281 parameter
->msgStorage
= msgStorage
;
282 parameter
->listeningSocket
= s
;
284 hThread
= CreateThread(NULL
, 0, listening_thread
, parameter
, 0, NULL
);
285 if (hThread
== NULL
) goto cleanup
;
287 msgStorage
->threadHandles
[msgStorage
->numThreadHandles
] = hThread
;
288 msgStorage
->numThreadHandles
++;
290 goto cleanup_addresses
;
294 heap_free(parameter
);
297 freeaddrinfo(multicastAddr
);
298 freeaddrinfo(bindAddr
);
299 freeaddrinfo(interfaceAddr
);
302 static BOOL
start_listening_on_all_addresses(messageStorage
*msgStorage
, ULONG family
)
304 IP_ADAPTER_ADDRESSES
*adapterAddresses
= NULL
, *adapterAddress
;
305 ULONG bufferSize
= 0;
312 retVal
= GetAdaptersAddresses(family
, 0, NULL
, NULL
, &bufferSize
); /* family should be AF_INET or AF_INET6 */
313 if (retVal
!= ERROR_BUFFER_OVERFLOW
) goto cleanup
;
315 /* Get size of buffer for adapters */
316 adapterAddresses
= (IP_ADAPTER_ADDRESSES
*)heap_alloc(bufferSize
);
317 if (adapterAddresses
== NULL
) goto cleanup
;
319 /* Get list of adapters */
320 retVal
= GetAdaptersAddresses(family
, 0, NULL
, adapterAddresses
, &bufferSize
);
321 if (retVal
!= ERROR_SUCCESS
) goto cleanup
;
323 for (adapterAddress
= adapterAddresses
; adapterAddress
!= NULL
; adapterAddress
= adapterAddress
->Next
)
325 if (msgStorage
->numThreadHandles
>= MAX_LISTENING_THREADS
)
331 if (adapterAddress
->FirstUnicastAddress
== NULL
) continue;
333 sockaddr
= adapterAddress
->FirstUnicastAddress
->Address
.lpSockaddr
;
334 addressLength
= sizeof(address
);
335 WSAAddressToStringA(sockaddr
, adapterAddress
->FirstUnicastAddress
->Address
.iSockaddrLength
, NULL
, address
, &addressLength
);
337 start_listening(msgStorage
, adapterAddress
->FirstUnicastAddress
->Address
.lpSockaddr
->sa_family
== AF_INET
? SEND_ADDRESS_IPV4
: SEND_ADDRESS_IPV6
, address
);
343 heap_free(adapterAddresses
);
347 static BOOL
send_udp_multicast_of_type(const char *data
, int length
, ULONG family
)
349 IP_ADAPTER_ADDRESSES
*adapter_addresses
= NULL
, *adapter_addr
;
350 static const struct in6_addr i_addr_zero
;
351 struct addrinfo
*multi_address
;
352 ULONG bufferSize
= 0;
359 /* Resolve the multicast address */
360 if (family
== AF_INET6
)
361 multi_address
= resolve_address(SEND_ADDRESS_IPV6
, SEND_PORT
, AF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
);
363 multi_address
= resolve_address(SEND_ADDRESS_IPV4
, SEND_PORT
, AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
365 if (multi_address
== NULL
)
368 /* Get size of buffer for adapters */
369 retval
= GetAdaptersAddresses(family
, 0, NULL
, NULL
, &bufferSize
);
370 if (retval
!= ERROR_BUFFER_OVERFLOW
) goto cleanup
;
372 adapter_addresses
= (IP_ADAPTER_ADDRESSES
*) heap_alloc(bufferSize
);
373 if (adapter_addresses
== NULL
) goto cleanup
;
375 /* Get list of adapters */
376 retval
= GetAdaptersAddresses(family
, 0, NULL
, adapter_addresses
, &bufferSize
);
377 if (retval
!= ERROR_SUCCESS
) goto cleanup
;
379 for (adapter_addr
= adapter_addresses
; adapter_addr
!= NULL
; adapter_addr
= adapter_addr
->Next
)
381 if (adapter_addr
->FirstUnicastAddress
== NULL
) continue;
383 sockaddr
= adapter_addr
->FirstUnicastAddress
->Address
.lpSockaddr
;
385 /* Create a socket and bind to the adapter address */
386 s
= socket(family
, SOCK_DGRAM
, IPPROTO_UDP
);
387 if (s
== INVALID_SOCKET
) continue;
389 if (bind(s
, sockaddr
, adapter_addr
->FirstUnicastAddress
->Address
.iSockaddrLength
) == SOCKET_ERROR
)
395 /* Set the multicast interface and TTL value */
396 setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &i_addr_zero
,
397 (family
== AF_INET6
) ? sizeof(struct in6_addr
) : sizeof(struct in_addr
));
398 setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
, sizeof(ttl
));
400 sendto(s
, data
, length
, 0, (SOCKADDR
*) multi_address
->ai_addr
, multi_address
->ai_addrlen
);
407 freeaddrinfo(multi_address
);
408 heap_free(adapter_addresses
);
412 typedef struct IWSDiscoveryPublisherNotifyImpl
{
413 IWSDiscoveryPublisherNotify IWSDiscoveryPublisherNotify_iface
;
415 } IWSDiscoveryPublisherNotifyImpl
;
417 static inline IWSDiscoveryPublisherNotifyImpl
*impl_from_IWSDiscoveryPublisherNotify(IWSDiscoveryPublisherNotify
*iface
)
419 return CONTAINING_RECORD(iface
, IWSDiscoveryPublisherNotifyImpl
, IWSDiscoveryPublisherNotify_iface
);
422 static HRESULT WINAPI
IWSDiscoveryPublisherNotifyImpl_QueryInterface(IWSDiscoveryPublisherNotify
*iface
, REFIID riid
, void **ppv
)
424 IWSDiscoveryPublisherNotifyImpl
*This
= impl_from_IWSDiscoveryPublisherNotify(iface
);
433 if (IsEqualIID(riid
, &IID_IUnknown
) ||
434 IsEqualIID(riid
, &IID_IWSDiscoveryPublisherNotify
))
436 *ppv
= &This
->IWSDiscoveryPublisherNotify_iface
;
440 return E_NOINTERFACE
;
443 IUnknown_AddRef((IUnknown
*)*ppv
);
447 static ULONG WINAPI
IWSDiscoveryPublisherNotifyImpl_AddRef(IWSDiscoveryPublisherNotify
*iface
)
449 IWSDiscoveryPublisherNotifyImpl
*This
= impl_from_IWSDiscoveryPublisherNotify(iface
);
450 ULONG ref
= InterlockedIncrement(&This
->ref
);
452 trace("IWSDiscoveryPublisherNotifyImpl_AddRef called (%p, ref = %d)\n", This
, ref
);
456 static ULONG WINAPI
IWSDiscoveryPublisherNotifyImpl_Release(IWSDiscoveryPublisherNotify
*iface
)
458 IWSDiscoveryPublisherNotifyImpl
*This
= impl_from_IWSDiscoveryPublisherNotify(iface
);
459 ULONG ref
= InterlockedDecrement(&This
->ref
);
461 trace("IWSDiscoveryPublisherNotifyImpl_Release called (%p, ref = %d)\n", This
, ref
);
465 HeapFree(GetProcessHeap(), 0, This
);
471 static void verify_wsdxml_name(const char *debug_prefix
, WSDXML_NAME
*name
, LPCWSTR uri
, LPCWSTR prefix
,
474 ok(name
!= NULL
, "%s: name == NULL\n", debug_prefix
);
475 if (name
== NULL
) return;
477 ok(name
->LocalName
!= NULL
&& lstrcmpW(name
->LocalName
, local_name
) == 0,
478 "%s: Local name = '%s'\n", debug_prefix
, wine_dbgstr_w(name
->LocalName
));
480 ok(name
->Space
!= NULL
, "%s: Space == NULL\n", debug_prefix
);
481 if (name
->Space
== NULL
) return;
483 ok(name
->Space
->Uri
!= NULL
&& lstrcmpW(name
->Space
->Uri
, uri
) == 0,
484 "%s: URI == '%s'\n", debug_prefix
, wine_dbgstr_w(name
->Space
->Uri
));
485 ok(name
->Space
->PreferredPrefix
!= NULL
&& lstrcmpW(name
->Space
->PreferredPrefix
, prefix
) == 0,
486 "%s: Prefix = '%s'\n", debug_prefix
, wine_dbgstr_w(name
->Space
->PreferredPrefix
));
489 static void verify_wsdxml_any_text(const char *debug_prefix
, WSDXML_ELEMENT
*any
, LPCWSTR uri
, LPCWSTR prefix
,
490 LPCWSTR local_name
, LPCWSTR value
)
494 ok(any
!= NULL
, "%s: any == NULL\n", debug_prefix
);
495 if (any
== NULL
) return;
497 child
= (WSDXML_TEXT
*) any
->FirstChild
;
499 ok(any
->Node
.Type
== ElementType
, "%s: Node type == %d\n", debug_prefix
, any
->Node
.Type
);
500 ok(any
->Node
.Parent
== NULL
, "%s: Parent == %p\n", debug_prefix
, any
->Node
.Parent
);
501 ok(any
->Node
.Next
== NULL
, "%s: Next == %p\n", debug_prefix
, any
->Node
.Next
);
502 verify_wsdxml_name(debug_prefix
, any
->Name
, uri
, prefix
, local_name
);
504 ok(child
!= NULL
, "%s: First child == NULL\n", debug_prefix
);
508 ok(child
->Node
.Type
== TextType
, "%s: Node type == %d\n", debug_prefix
, child
->Node
.Type
);
509 ok(child
->Node
.Parent
== any
, "%s: Parent == %p\n", debug_prefix
, child
->Node
.Parent
);
510 ok(child
->Node
.Next
== NULL
, "%s: Next == %p\n", debug_prefix
, child
->Node
.Next
);
512 if (child
->Node
.Type
== TextType
)
513 ok(child
->Text
!= NULL
&& lstrcmpW(child
->Text
, value
) == 0,
514 "%s: Text == '%s'\n", debug_prefix
, wine_dbgstr_w(child
->Text
));
518 static HRESULT WINAPI
IWSDiscoveryPublisherNotifyImpl_ProbeHandler(IWSDiscoveryPublisherNotify
*This
, const WSD_SOAP_MESSAGE
*pSoap
, IWSDMessageParameters
*pMessageParameters
)
520 trace("IWSDiscoveryPublisherNotifyImpl_ProbeHandler called (%p, %p, %p)\n", This
, pSoap
, pMessageParameters
);
522 if (probe_event
== NULL
)
524 /* We may have received an unrelated probe on the network */
528 ok(pSoap
!= NULL
, "pSoap == NULL\n");
529 ok(pMessageParameters
!= NULL
, "pMessageParameters == NULL\n");
533 static const WCHAR perry
[] = {'P','e','r','r','y',0};
534 static const WCHAR extra_info
[] = {'E','x','t','r','a','I','n','f','o',0};
535 WSD_PROBE
*probe_msg
= (WSD_PROBE
*) pSoap
->Body
;
537 ok(pSoap
->Body
!= NULL
, "pSoap->Body == NULL\n");
538 ok(pSoap
->Header
.To
!= NULL
&& lstrcmpW(pSoap
->Header
.To
, discoveryTo
) == 0,
539 "pSoap->Header.To == '%s'\n", wine_dbgstr_w(pSoap
->Header
.To
));
540 ok(pSoap
->Header
.Action
!= NULL
&& lstrcmpW(pSoap
->Header
.Action
, actionProbe
) == 0,
541 "pSoap->Header.Action == '%s'\n", wine_dbgstr_w(pSoap
->Header
.Action
));
543 ok(pSoap
->Header
.MessageID
!= NULL
, "pSoap->Header.MessageID == NULL\n");
545 /* Ensure the message ID is at least 9 characters long (to skip past the 'urn:uuid:' prefix) */
546 if ((pSoap
->Header
.MessageID
!= NULL
) && (lstrlenW(pSoap
->Header
.MessageID
) > 9))
549 RPC_STATUS ret
= UuidFromStringW((LPWSTR
)pSoap
->Header
.MessageID
+ 9, &uuid
);
551 trace("Received message with UUID '%s' (expected UUID '%s')\n", wine_dbgstr_guid(&uuid
),
552 wine_dbgstr_guid(&probe_message_id
));
554 /* Check if we've either received a message without a UUID, or the UUID isn't the one we sent. If so,
555 ignore it and wait for another message. */
556 if ((ret
!= RPC_S_OK
) || (UuidEqual(&uuid
, &probe_message_id
, &ret
) == FALSE
)) return S_OK
;
559 verify_wsdxml_any_text("pSoap->Header.AnyHeaders", pSoap
->Header
.AnyHeaders
, uri_more_tests_no_slash
,
560 prefix_grog
, perry
, extra_info
);
562 if (probe_msg
!= NULL
)
564 static const WCHAR lager
[] = {'L','a','g','e','r',0};
565 static const WCHAR more_info
[] = {'M','o','r','e','I','n','f','o',0};
567 todo_wine
ok(probe_msg
->Types
!= NULL
, "Probe message Types == NULL\n");
569 if (probe_msg
->Types
!= NULL
)
571 verify_wsdxml_name("probe_msg->Types->Element", probe_msg
->Types
->Element
, uri_more_tests_no_slash
,
572 prefix_grog
, name_cider
);
573 ok(probe_msg
->Types
->Next
== NULL
, "probe_msg->Types->Next == %p\n", probe_msg
->Types
->Next
);
576 ok(probe_msg
->Scopes
== NULL
, "Probe message Scopes != NULL\n");
577 verify_wsdxml_any_text("probe_msg->Any", probe_msg
->Any
, uri_more_tests_no_slash
, prefix_grog
, lager
, more_info
);
581 SetEvent(probe_event
);
585 static HRESULT WINAPI
IWSDiscoveryPublisherNotifyImpl_ResolveHandler(IWSDiscoveryPublisherNotify
*This
, const WSD_SOAP_MESSAGE
*pSoap
, IWSDMessageParameters
*pMessageParameters
)
587 trace("IWSDiscoveryPublisherNotifyImpl_ResolveHandler called (%p, %p, %p)\n", This
, pSoap
, pMessageParameters
);
591 static const IWSDiscoveryPublisherNotifyVtbl publisherNotify_vtbl
=
593 IWSDiscoveryPublisherNotifyImpl_QueryInterface
,
594 IWSDiscoveryPublisherNotifyImpl_AddRef
,
595 IWSDiscoveryPublisherNotifyImpl_Release
,
596 IWSDiscoveryPublisherNotifyImpl_ProbeHandler
,
597 IWSDiscoveryPublisherNotifyImpl_ResolveHandler
600 static BOOL
create_discovery_publisher_notify(IWSDiscoveryPublisherNotify
**publisherNotify
)
602 IWSDiscoveryPublisherNotifyImpl
*obj
;
604 *publisherNotify
= NULL
;
606 obj
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*obj
));
610 trace("Out of memory creating IWSDiscoveryPublisherNotify\n");
614 obj
->IWSDiscoveryPublisherNotify_iface
.lpVtbl
= &publisherNotify_vtbl
;
617 *publisherNotify
= &obj
->IWSDiscoveryPublisherNotify_iface
;
622 static void CreateDiscoveryPublisher_tests(void)
624 IWSDiscoveryPublisher
*publisher
= NULL
;
625 IWSDiscoveryPublisher
*publisher2
;
630 rc
= WSDCreateDiscoveryPublisher(NULL
, NULL
);
631 ok((rc
== E_POINTER
) || (rc
== E_INVALIDARG
), "WSDCreateDiscoveryPublisher(NULL, NULL) failed: %08x\n", rc
);
633 rc
= WSDCreateDiscoveryPublisher(NULL
, &publisher
);
634 ok(rc
== S_OK
, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: %08x\n", rc
);
635 ok(publisher
!= NULL
, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: publisher == NULL\n");
637 /* Try to query for objects */
638 rc
= IWSDiscoveryPublisher_QueryInterface(publisher
, &IID_IUnknown
, (LPVOID
*)&unknown
);
639 ok(rc
== S_OK
,"IWSDiscoveryPublisher_QueryInterface(IID_IUnknown) failed: %08x\n", rc
);
642 IUnknown_Release(unknown
);
644 rc
= IWSDiscoveryPublisher_QueryInterface(publisher
, &IID_IWSDiscoveryPublisher
, (LPVOID
*)&publisher2
);
645 ok(rc
== S_OK
,"IWSDiscoveryPublisher_QueryInterface(IID_IWSDiscoveryPublisher) failed: %08x\n", rc
);
648 IWSDiscoveryPublisher_Release(publisher2
);
650 ref
= IWSDiscoveryPublisher_Release(publisher
);
651 ok(ref
== 0, "IWSDiscoveryPublisher_Release() has %d references, should have 0\n", ref
);
654 static void CreateDiscoveryPublisher_XMLContext_tests(void)
656 IWSDiscoveryPublisher
*publisher
= NULL
;
657 IWSDXMLContext
*xmlContext
, *returnedContext
;
661 /* Test creating an XML context and supplying it to WSDCreateDiscoveryPublisher */
662 rc
= WSDXMLCreateContext(&xmlContext
);
663 ok(rc
== S_OK
, "WSDXMLCreateContext failed: %08x\n", rc
);
665 rc
= WSDCreateDiscoveryPublisher(xmlContext
, &publisher
);
666 ok(rc
== S_OK
, "WSDCreateDiscoveryPublisher(xmlContext, &publisher) failed: %08x\n", rc
);
667 ok(publisher
!= NULL
, "WSDCreateDiscoveryPublisher(xmlContext, &publisher) failed: publisher == NULL\n");
669 rc
= IWSDiscoveryPublisher_GetXMLContext(publisher
, NULL
);
670 ok(rc
== E_INVALIDARG
, "GetXMLContext returned unexpected value with NULL argument: %08x\n", rc
);
672 rc
= IWSDiscoveryPublisher_GetXMLContext(publisher
, &returnedContext
);
673 ok(rc
== S_OK
, "GetXMLContext failed: %08x\n", rc
);
675 ok(xmlContext
== returnedContext
, "GetXMLContext returned unexpected value: returnedContext == %p\n", returnedContext
);
677 ref
= IWSDXMLContext_Release(returnedContext
);
678 ok(ref
== 2, "IWSDXMLContext_Release() has %d references, should have 2\n", ref
);
680 ref
= IWSDiscoveryPublisher_Release(publisher
);
681 ok(ref
== 0, "IWSDiscoveryPublisher_Release() has %d references, should have 0\n", ref
);
683 ref
= IWSDXMLContext_Release(returnedContext
);
684 ok(ref
== 0, "IWSDXMLContext_Release() has %d references, should have 0\n", ref
);
686 /* Test using a default XML context */
688 returnedContext
= NULL
;
690 rc
= WSDCreateDiscoveryPublisher(NULL
, &publisher
);
691 ok(rc
== S_OK
, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: %08x\n", rc
);
692 ok(publisher
!= NULL
, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: publisher == NULL\n");
694 rc
= IWSDiscoveryPublisher_GetXMLContext(publisher
, &returnedContext
);
695 ok(rc
== S_OK
, "GetXMLContext failed: %08x\n", rc
);
697 ref
= IWSDXMLContext_Release(returnedContext
);
698 ok(ref
== 1, "IWSDXMLContext_Release() has %d references, should have 1\n", ref
);
700 ref
= IWSDiscoveryPublisher_Release(publisher
);
701 ok(ref
== 0, "IWSDiscoveryPublisher_Release() has %d references, should have 0\n", ref
);
704 static void Publish_tests(void)
706 IWSDiscoveryPublisher
*publisher
= NULL
;
707 IWSDiscoveryPublisherNotify
*sink1
= NULL
, *sink2
= NULL
;
708 IWSDiscoveryPublisherNotifyImpl
*sink1Impl
= NULL
, *sink2Impl
= NULL
;
709 char endpointReferenceString
[MAX_PATH
], app_sequence_string
[MAX_PATH
];
710 LPWSTR publisherIdW
= NULL
, sequenceIdW
= NULL
;
711 messageStorage
*msgStorage
;
713 BOOL messageOK
, hello_message_seen
= FALSE
, endpoint_reference_seen
= FALSE
, app_sequence_seen
= FALSE
;
714 BOOL metadata_version_seen
= FALSE
, any_header_seen
= FALSE
, wine_ns_seen
= FALSE
, body_hello_seen
= FALSE
;
715 BOOL any_body_seen
= FALSE
, types_seen
= FALSE
, xml_namespaces_seen
= FALSE
, scopes_seen
= FALSE
;
716 BOOL xaddrs_seen
= FALSE
;
721 WSDXML_ELEMENT
*header_any_element
, *body_any_element
, *endpoint_any_element
, *ref_param_any_element
;
722 WSDXML_NAME header_any_name
, another_name
;
723 WSDXML_NAMESPACE ns
, ns2
;
724 WCHAR header_any_name_text
[] = {'B','e','e','r',0};
725 static const WCHAR header_any_text
[] = {'P','u','b','l','i','s','h','T','e','s','t',0};
726 static const WCHAR body_any_text
[] = {'B','o','d','y','T','e','s','t',0};
727 static const WCHAR endpoint_any_text
[] = {'E','n','d','P','T','e','s','t',0};
728 static const WCHAR ref_param_any_text
[] = {'R','e','f','P','T','e','s','t',0};
729 static const WCHAR uri
[] = {'h','t','t','p',':','/','/','w','i','n','e','.','t','e','s','t','/',0};
730 static const WCHAR prefix
[] = {'w','i','n','e',0};
731 static const WCHAR uri3
[] = {'h','t','t','p',':','/','/','t','h','i','r','d','.','u','r','l','/',0};
732 WSD_NAME_LIST types_list
;
733 WSD_URI_LIST scopes_list
, xaddrs_list
;
734 unsigned char *probe_uuid_str
;
736 rc
= WSDCreateDiscoveryPublisher(NULL
, &publisher
);
737 ok(rc
== S_OK
, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: %08x\n", rc
);
738 ok(publisher
!= NULL
, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: publisher == NULL\n");
740 /* Test SetAddressFamily */
741 rc
= IWSDiscoveryPublisher_SetAddressFamily(publisher
, 12345);
742 ok(rc
== E_INVALIDARG
, "IWSDiscoveryPublisher_SetAddressFamily(12345) returned unexpected result: %08x\n", rc
);
744 rc
= IWSDiscoveryPublisher_SetAddressFamily(publisher
, WSDAPI_ADDRESSFAMILY_IPV4
);
745 ok(rc
== S_OK
, "IWSDiscoveryPublisher_SetAddressFamily(WSDAPI_ADDRESSFAMILY_IPV4) failed: %08x\n", rc
);
747 /* Try to update the address family after already setting it */
748 rc
= IWSDiscoveryPublisher_SetAddressFamily(publisher
, WSDAPI_ADDRESSFAMILY_IPV6
);
749 ok(rc
== STG_E_INVALIDFUNCTION
, "IWSDiscoveryPublisher_SetAddressFamily(WSDAPI_ADDRESSFAMILY_IPV6) returned unexpected result: %08x\n", rc
);
751 /* Create notification sinks */
752 ok(create_discovery_publisher_notify(&sink1
) == TRUE
, "create_discovery_publisher_notify failed\n");
753 ok(create_discovery_publisher_notify(&sink2
) == TRUE
, "create_discovery_publisher_notify failed\n");
755 /* Get underlying implementation so we can check the ref count */
756 sink1Impl
= impl_from_IWSDiscoveryPublisherNotify(sink1
);
757 sink2Impl
= impl_from_IWSDiscoveryPublisherNotify(sink2
);
759 /* Attempt to unregister sink before registering it */
760 rc
= IWSDiscoveryPublisher_UnRegisterNotificationSink(publisher
, sink1
);
761 ok(rc
== E_FAIL
, "IWSDiscoveryPublisher_UnRegisterNotificationSink returned unexpected result: %08x\n", rc
);
763 /* Register notification sinks */
764 rc
= IWSDiscoveryPublisher_RegisterNotificationSink(publisher
, sink1
);
765 ok(rc
== S_OK
, "IWSDiscoveryPublisher_RegisterNotificationSink failed: %08x\n", rc
);
766 ok(sink1Impl
->ref
== 2, "Ref count for sink 1 is not as expected: %d\n", sink1Impl
->ref
);
768 rc
= IWSDiscoveryPublisher_RegisterNotificationSink(publisher
, sink2
);
769 ok(rc
== S_OK
, "IWSDiscoveryPublisher_RegisterNotificationSink failed: %08x\n", rc
);
770 ok(sink2Impl
->ref
== 2, "Ref count for sink 2 is not as expected: %d\n", sink2Impl
->ref
);
772 /* Unregister the first sink */
773 rc
= IWSDiscoveryPublisher_UnRegisterNotificationSink(publisher
, sink1
);
774 ok(rc
== S_OK
, "IWSDiscoveryPublisher_UnRegisterNotificationSink failed: %08x\n", rc
);
775 ok(sink1Impl
->ref
== 1, "Ref count for sink 1 is not as expected: %d\n", sink1Impl
->ref
);
777 /* Set up network listener */
778 publisherIdW
= utf8_to_wide(publisherId
);
779 if (publisherIdW
== NULL
) goto after_publish_test
;
781 sequenceIdW
= utf8_to_wide(sequenceId
);
782 if (sequenceIdW
== NULL
) goto after_publish_test
;
784 msgStorage
= heap_alloc_zero(sizeof(messageStorage
));
785 if (msgStorage
== NULL
) goto after_publish_test
;
787 msgStorage
->running
= TRUE
;
788 InitializeCriticalSection(&msgStorage
->criticalSection
);
790 ret
= WSAStartup(MAKEWORD(2, 2), &wsaData
);
791 ok(ret
== 0, "WSAStartup failed (ret = %d)\n", ret
);
793 ret
= start_listening_on_all_addresses(msgStorage
, AF_INET
);
794 ok(ret
== TRUE
, "Unable to listen on IPv4 addresses (ret == %d)\n", ret
);
796 /* Create "any" elements for header */
798 ns
.PreferredPrefix
= prefix
;
800 header_any_name
.LocalName
= header_any_name_text
;
801 header_any_name
.Space
= &ns
;
803 rc
= WSDXMLBuildAnyForSingleElement(&header_any_name
, header_any_text
, &header_any_element
);
804 ok(rc
== S_OK
, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc
);
806 rc
= WSDXMLBuildAnyForSingleElement(&header_any_name
, body_any_text
, &body_any_element
);
807 ok(rc
== S_OK
, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc
);
809 rc
= WSDXMLBuildAnyForSingleElement(&header_any_name
, endpoint_any_text
, &endpoint_any_element
);
810 ok(rc
== S_OK
, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc
);
812 rc
= WSDXMLBuildAnyForSingleElement(&header_any_name
, ref_param_any_text
, &ref_param_any_element
);
813 ok(rc
== S_OK
, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc
);
815 /* Create types list */
816 ns2
.Uri
= uri_more_tests
;
817 ns2
.PreferredPrefix
= prefix_grog
;
819 another_name
.LocalName
= (WCHAR
*) name_cider
;
820 another_name
.Space
= &ns2
;
822 types_list
.Next
= malloc(sizeof(WSD_NAME_LIST
));
823 types_list
.Element
= &another_name
;
825 types_list
.Next
->Next
= NULL
;
826 types_list
.Next
->Element
= &header_any_name
;
828 /* Create scopes and xaddrs lists */
829 scopes_list
.Next
= malloc(sizeof(WSD_URI_LIST
));
830 scopes_list
.Element
= uri
;
832 scopes_list
.Next
->Next
= NULL
;
833 scopes_list
.Next
->Element
= uri_more_tests
;
835 xaddrs_list
.Next
= malloc(sizeof(WSD_URI_LIST
));
836 xaddrs_list
.Element
= uri_more_tests
;
838 xaddrs_list
.Next
->Next
= NULL
;
839 xaddrs_list
.Next
->Element
= uri3
;
841 /* Publish the service */
842 rc
= IWSDiscoveryPublisher_PublishEx(publisher
, publisherIdW
, 1, 1, 1, sequenceIdW
, &types_list
, &scopes_list
,
843 &xaddrs_list
, header_any_element
, ref_param_any_element
, NULL
, endpoint_any_element
, body_any_element
);
845 WSDFreeLinkedMemory(header_any_element
);
846 WSDFreeLinkedMemory(body_any_element
);
847 WSDFreeLinkedMemory(endpoint_any_element
);
848 WSDFreeLinkedMemory(ref_param_any_element
);
849 free(types_list
.Next
);
850 free(scopes_list
.Next
);
851 free(xaddrs_list
.Next
);
853 ok(rc
== S_OK
, "Publish failed: %08x\n", rc
);
855 /* Wait up to 2 seconds for messages to be received */
856 if (WaitForMultipleObjects(msgStorage
->numThreadHandles
, msgStorage
->threadHandles
, TRUE
, 2000) == WAIT_TIMEOUT
)
858 /* Wait up to 1 more second for threads to terminate */
859 msgStorage
->running
= FALSE
;
860 WaitForMultipleObjects(msgStorage
->numThreadHandles
, msgStorage
->threadHandles
, TRUE
, 1000);
863 DeleteCriticalSection(&msgStorage
->criticalSection
);
865 /* Verify we've received a message */
866 ok(msgStorage
->messageCount
>= 1, "No messages received\n");
868 sprintf(endpointReferenceString
, "<wsa:EndpointReference><wsa:Address>%s</wsa:Address><wsa:ReferenceParameters>"
869 "<wine:Beer>RefPTest</wine:Beer></wsa:ReferenceParameters><wine:Beer>EndPTest</wine:Beer>"
870 "</wsa:EndpointReference>", publisherId
);
872 sprintf(app_sequence_string
, "<wsd:AppSequence InstanceId=\"1\" SequenceId=\"%s\" MessageNumber=\"1\"></wsd:AppSequence>",
877 /* Check we're received the correct message */
878 for (i
= 0; i
< msgStorage
->messageCount
; i
++)
880 msg
= msgStorage
->messages
[i
];
883 hello_message_seen
= (strstr(msg
, "<wsa:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/Hello</wsa:Action>") != NULL
);
884 endpoint_reference_seen
= (strstr(msg
, endpointReferenceString
) != NULL
);
885 app_sequence_seen
= (strstr(msg
, app_sequence_string
) != NULL
);
886 metadata_version_seen
= (strstr(msg
, "<wsd:MetadataVersion>1</wsd:MetadataVersion>") != NULL
);
887 any_header_seen
= (strstr(msg
, "<wine:Beer>PublishTest</wine:Beer>") != NULL
);
888 wine_ns_seen
= (strstr(msg
, "xmlns:wine=\"http://wine.test/\"") != NULL
);
889 body_hello_seen
= (strstr(msg
, "<soap:Body><wsd:Hello") != NULL
);
890 any_body_seen
= (strstr(msg
, "<wine:Beer>BodyTest</wine:Beer>") != NULL
);
891 types_seen
= (strstr(msg
, "<wsd:Types>grog:Cider wine:Beer</wsd:Types>") != NULL
);
892 scopes_seen
= (strstr(msg
, "<wsd:Scopes>http://wine.test/ http://more.tests/</wsd:Scopes>") != NULL
);
893 xaddrs_seen
= (strstr(msg
, "<wsd:XAddrs>http://more.tests/ http://third.url/</wsd:XAddrs>") != NULL
);
894 xml_namespaces_seen
= (strstr(msg
, "xmlns:wine=\"http://wine.test/\" xmlns:grog=\"http://more.tests/\"") != NULL
);
895 messageOK
= hello_message_seen
&& endpoint_reference_seen
&& app_sequence_seen
&& metadata_version_seen
&&
896 any_header_seen
&& wine_ns_seen
&& body_hello_seen
&& any_body_seen
&& types_seen
&& xml_namespaces_seen
&&
897 scopes_seen
&& xaddrs_seen
;
899 if (messageOK
) break;
902 for (i
= 0; i
< msgStorage
->messageCount
; i
++)
904 heap_free(msgStorage
->messages
[i
]);
907 heap_free(msgStorage
);
909 ok(hello_message_seen
== TRUE
, "Hello message not received\n");
910 ok(endpoint_reference_seen
== TRUE
, "EndpointReference not received\n");
911 ok(app_sequence_seen
== TRUE
, "AppSequence not received\n");
912 ok(metadata_version_seen
== TRUE
, "MetadataVersion not received\n");
913 ok(messageOK
== TRUE
, "Hello message metadata not received\n");
914 ok(any_header_seen
== TRUE
, "Custom header not received\n");
915 ok(wine_ns_seen
== TRUE
, "Wine namespace not received\n");
916 ok(body_hello_seen
== TRUE
, "Body and Hello elements not received\n");
917 ok(any_body_seen
== TRUE
, "Custom body element not received\n");
918 ok(types_seen
== TRUE
, "Types not received\n");
919 ok(xml_namespaces_seen
== TRUE
, "XML namespaces not received\n");
920 ok(scopes_seen
== TRUE
, "Scopes not received\n");
921 ok(xaddrs_seen
== TRUE
, "XAddrs not received\n");
925 heap_free(publisherIdW
);
926 heap_free(sequenceIdW
);
928 /* Test the receiving of a probe message */
929 probe_event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
931 UuidCreate(&probe_message_id
);
932 UuidToStringA(&probe_message_id
, &probe_uuid_str
);
934 ok(probe_uuid_str
!= NULL
, "Failed to create UUID for probe message\n");
936 if (probe_uuid_str
!= NULL
)
938 char probe_message
[sizeof(testProbeMessage
) + 50];
939 sprintf(probe_message
, testProbeMessage
, probe_uuid_str
);
941 ok(send_udp_multicast_of_type(probe_message
, strlen(probe_message
), AF_INET
) == TRUE
, "Sending Probe message failed\n");
942 ok(WaitForSingleObject(probe_event
, 2000) == WAIT_OBJECT_0
, "Probe message not received\n");
944 RpcStringFreeA(&probe_uuid_str
);
947 CloseHandle(probe_event
);
949 ref
= IWSDiscoveryPublisher_Release(publisher
);
950 ok(ref
== 0, "IWSDiscoveryPublisher_Release() has %d references, should have 0\n", ref
);
952 /* Check that the sinks have been released by the publisher */
953 ok(sink1Impl
->ref
== 1, "Ref count for sink 1 is not as expected: %d\n", sink1Impl
->ref
);
954 ok(sink2Impl
->ref
== 1, "Ref count for sink 2 is not as expected: %d\n", sink2Impl
->ref
);
956 /* Release the sinks */
957 IWSDiscoveryPublisherNotify_Release(sink1
);
958 IWSDiscoveryPublisherNotify_Release(sink2
);
963 static void UnPublish_tests(void)
965 IWSDiscoveryPublisher
*publisher
= NULL
;
966 IWSDiscoveryPublisherNotify
*sink1
= NULL
;
967 char endpoint_reference_string
[MAX_PATH
], app_sequence_string
[MAX_PATH
];
968 LPWSTR publisherIdW
= NULL
, sequenceIdW
= NULL
;
969 messageStorage
*msg_storage
;
971 BOOL message_ok
, hello_message_seen
= FALSE
, endpoint_reference_seen
= FALSE
, app_sequence_seen
= FALSE
;
972 BOOL wine_ns_seen
= FALSE
, body_hello_seen
= FALSE
, any_body_seen
= FALSE
;
977 WSDXML_ELEMENT
*body_any_element
;
978 WSDXML_NAME body_any_name
;
980 WCHAR body_any_name_text
[] = {'B','e','e','r',0};
981 static const WCHAR body_any_text
[] = {'B','o','d','y','T','e','s','t',0};
982 static const WCHAR uri
[] = {'h','t','t','p',':','/','/','w','i','n','e','.','t','e','s','t','/',0};
983 static const WCHAR prefix
[] = {'w','i','n','e',0};
985 rc
= WSDCreateDiscoveryPublisher(NULL
, &publisher
);
986 ok(rc
== S_OK
, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: %08x\n", rc
);
987 ok(publisher
!= NULL
, "WSDCreateDiscoveryPublisher(NULL, &publisher) failed: publisher == NULL\n");
989 rc
= IWSDiscoveryPublisher_SetAddressFamily(publisher
, WSDAPI_ADDRESSFAMILY_IPV4
);
990 ok(rc
== S_OK
, "IWSDiscoveryPublisher_SetAddressFamily(WSDAPI_ADDRESSFAMILY_IPV4) failed: %08x\n", rc
);
992 /* Create notification sink */
993 ok(create_discovery_publisher_notify(&sink1
) == TRUE
, "create_discovery_publisher_notify failed\n");
994 rc
= IWSDiscoveryPublisher_RegisterNotificationSink(publisher
, sink1
);
995 ok(rc
== S_OK
, "IWSDiscoveryPublisher_RegisterNotificationSink failed: %08x\n", rc
);
997 /* Set up network listener */
998 publisherIdW
= utf8_to_wide(publisherId
);
999 if (publisherIdW
== NULL
) goto after_unpublish_test
;
1001 sequenceIdW
= utf8_to_wide(sequenceId
);
1002 if (sequenceIdW
== NULL
) goto after_unpublish_test
;
1004 msg_storage
= heap_alloc_zero(sizeof(messageStorage
));
1005 if (msg_storage
== NULL
) goto after_unpublish_test
;
1007 msg_storage
->running
= TRUE
;
1008 InitializeCriticalSection(&msg_storage
->criticalSection
);
1010 ret
= WSAStartup(MAKEWORD(2, 2), &wsa_data
);
1011 ok(ret
== 0, "WSAStartup failed (ret = %d)\n", ret
);
1013 ret
= start_listening_on_all_addresses(msg_storage
, AF_INET
);
1014 ok(ret
== TRUE
, "Unable to listen on IPv4 addresses (ret == %d)\n", ret
);
1016 /* Create "any" elements for header */
1018 ns
.PreferredPrefix
= prefix
;
1020 body_any_name
.LocalName
= body_any_name_text
;
1021 body_any_name
.Space
= &ns
;
1023 rc
= WSDXMLBuildAnyForSingleElement(&body_any_name
, body_any_text
, &body_any_element
);
1024 ok(rc
== S_OK
, "WSDXMLBuildAnyForSingleElement failed with %08x\n", rc
);
1026 /* Unpublish the service */
1027 rc
= IWSDiscoveryPublisher_UnPublish(publisher
, publisherIdW
, 1, 1, sequenceIdW
, body_any_element
);
1029 WSDFreeLinkedMemory(body_any_element
);
1031 ok(rc
== S_OK
, "Unpublish failed: %08x\n", rc
);
1033 /* Wait up to 2 seconds for messages to be received */
1034 if (WaitForMultipleObjects(msg_storage
->numThreadHandles
, msg_storage
->threadHandles
, TRUE
, 2000) == WAIT_TIMEOUT
)
1036 /* Wait up to 1 more second for threads to terminate */
1037 msg_storage
->running
= FALSE
;
1038 WaitForMultipleObjects(msg_storage
->numThreadHandles
, msg_storage
->threadHandles
, TRUE
, 1000);
1041 DeleteCriticalSection(&msg_storage
->criticalSection
);
1043 /* Verify we've received a message */
1044 ok(msg_storage
->messageCount
>= 1, "No messages received\n");
1046 sprintf(endpoint_reference_string
, "<wsa:EndpointReference><wsa:Address>%s</wsa:Address></wsa:EndpointReference>",
1048 sprintf(app_sequence_string
, "<wsd:AppSequence InstanceId=\"1\" SequenceId=\"%s\" MessageNumber=\"1\"></wsd:AppSequence>",
1053 /* Check we're received the correct message */
1054 for (i
= 0; i
< msg_storage
->messageCount
; i
++)
1056 msg
= msg_storage
->messages
[i
];
1059 hello_message_seen
= (strstr(msg
, "<wsa:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/Bye</wsa:Action>") != NULL
);
1060 endpoint_reference_seen
= (strstr(msg
, endpoint_reference_string
) != NULL
);
1061 app_sequence_seen
= (strstr(msg
, app_sequence_string
) != NULL
);
1062 wine_ns_seen
= (strstr(msg
, "xmlns:wine=\"http://wine.test/\"") != NULL
);
1063 body_hello_seen
= (strstr(msg
, "<soap:Body><wsd:Bye") != NULL
);
1064 any_body_seen
= (strstr(msg
, "<wine:Beer>BodyTest</wine:Beer>") != NULL
);
1065 message_ok
= hello_message_seen
&& endpoint_reference_seen
&& app_sequence_seen
&& wine_ns_seen
&&
1066 body_hello_seen
&& any_body_seen
;
1068 if (message_ok
) break;
1071 for (i
= 0; i
< msg_storage
->messageCount
; i
++)
1073 heap_free(msg_storage
->messages
[i
]);
1076 heap_free(msg_storage
);
1078 ok(hello_message_seen
== TRUE
, "Bye message not received\n");
1079 ok(endpoint_reference_seen
== TRUE
, "EndpointReference not received\n");
1080 ok(app_sequence_seen
== TRUE
, "AppSequence not received\n");
1081 ok(message_ok
== TRUE
, "Bye message metadata not received\n");
1082 ok(wine_ns_seen
== TRUE
, "Wine namespace not received\n");
1083 ok(body_hello_seen
== TRUE
, "Body and Bye elements not received\n");
1084 ok(any_body_seen
== TRUE
, "Custom body element not received\n");
1086 after_unpublish_test
:
1088 heap_free(publisherIdW
);
1089 heap_free(sequenceIdW
);
1091 ref
= IWSDiscoveryPublisher_Release(publisher
);
1092 ok(ref
== 0, "IWSDiscoveryPublisher_Release() has %d references, should have 0\n", ref
);
1094 /* Release the sinks */
1095 IWSDiscoveryPublisherNotify_Release(sink1
);
1106 static BOOL
is_process_elevated(void)
1109 if (OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY
, &token
))
1111 TOKEN_ELEVATION_TYPE type
;
1115 ret
= GetTokenInformation( token
, TokenElevationType
, &type
, sizeof(type
), &size
);
1116 CloseHandle( token
);
1117 return (ret
&& type
== TokenElevationTypeFull
);
1122 static BOOL
is_firewall_enabled(void)
1125 INetFwMgr
*mgr
= NULL
;
1126 INetFwPolicy
*policy
= NULL
;
1127 INetFwProfile
*profile
= NULL
;
1128 VARIANT_BOOL enabled
= VARIANT_FALSE
;
1130 init
= CoInitializeEx( 0, COINIT_APARTMENTTHREADED
);
1132 hr
= CoCreateInstance( &CLSID_NetFwMgr
, NULL
, CLSCTX_INPROC_SERVER
, &IID_INetFwMgr
,
1134 ok( hr
== S_OK
, "got %08x\n", hr
);
1135 if (hr
!= S_OK
) goto done
;
1137 hr
= INetFwMgr_get_LocalPolicy( mgr
, &policy
);
1138 ok( hr
== S_OK
, "got %08x\n", hr
);
1139 if (hr
!= S_OK
) goto done
;
1141 hr
= INetFwPolicy_get_CurrentProfile( policy
, &profile
);
1142 if (hr
!= S_OK
) goto done
;
1144 hr
= INetFwProfile_get_FirewallEnabled( profile
, &enabled
);
1145 ok( hr
== S_OK
, "got %08x\n", hr
);
1148 if (policy
) INetFwPolicy_Release( policy
);
1149 if (profile
) INetFwProfile_Release( profile
);
1150 if (mgr
) INetFwMgr_Release( mgr
);
1151 if (SUCCEEDED( init
)) CoUninitialize();
1152 return (enabled
== VARIANT_TRUE
);
1155 static HRESULT
set_firewall( enum firewall_op op
)
1157 static const WCHAR testW
[] = {'w','s','d','a','p','i','_','t','e','s','t',0};
1159 INetFwMgr
*mgr
= NULL
;
1160 INetFwPolicy
*policy
= NULL
;
1161 INetFwProfile
*profile
= NULL
;
1162 INetFwAuthorizedApplication
*app
= NULL
;
1163 INetFwAuthorizedApplications
*apps
= NULL
;
1164 BSTR name
, image
= SysAllocStringLen( NULL
, MAX_PATH
);
1166 if (!GetModuleFileNameW( NULL
, image
, MAX_PATH
))
1168 SysFreeString( image
);
1171 init
= CoInitializeEx( 0, COINIT_APARTMENTTHREADED
);
1173 hr
= CoCreateInstance( &CLSID_NetFwMgr
, NULL
, CLSCTX_INPROC_SERVER
, &IID_INetFwMgr
,
1175 ok( hr
== S_OK
, "got %08x\n", hr
);
1176 if (hr
!= S_OK
) goto done
;
1178 hr
= INetFwMgr_get_LocalPolicy( mgr
, &policy
);
1179 ok( hr
== S_OK
, "got %08x\n", hr
);
1180 if (hr
!= S_OK
) goto done
;
1182 hr
= INetFwPolicy_get_CurrentProfile( policy
, &profile
);
1183 if (hr
!= S_OK
) goto done
;
1185 hr
= INetFwProfile_get_AuthorizedApplications( profile
, &apps
);
1186 ok( hr
== S_OK
, "got %08x\n", hr
);
1187 if (hr
!= S_OK
) goto done
;
1189 hr
= CoCreateInstance( &CLSID_NetFwAuthorizedApplication
, NULL
, CLSCTX_INPROC_SERVER
,
1190 &IID_INetFwAuthorizedApplication
, (void **)&app
);
1191 ok( hr
== S_OK
, "got %08x\n", hr
);
1192 if (hr
!= S_OK
) goto done
;
1194 hr
= INetFwAuthorizedApplication_put_ProcessImageFileName( app
, image
);
1195 if (hr
!= S_OK
) goto done
;
1197 name
= SysAllocString( testW
);
1198 hr
= INetFwAuthorizedApplication_put_Name( app
, name
);
1199 SysFreeString( name
);
1200 ok( hr
== S_OK
, "got %08x\n", hr
);
1201 if (hr
!= S_OK
) goto done
;
1204 hr
= INetFwAuthorizedApplications_Add( apps
, app
);
1205 else if (op
== APP_REMOVE
)
1206 hr
= INetFwAuthorizedApplications_Remove( apps
, image
);
1211 if (app
) INetFwAuthorizedApplication_Release( app
);
1212 if (apps
) INetFwAuthorizedApplications_Release( apps
);
1213 if (policy
) INetFwPolicy_Release( policy
);
1214 if (profile
) INetFwProfile_Release( profile
);
1215 if (mgr
) INetFwMgr_Release( mgr
);
1216 if (SUCCEEDED( init
)) CoUninitialize();
1217 SysFreeString( image
);
1221 START_TEST(discovery
)
1223 BOOL firewall_enabled
= is_firewall_enabled();
1226 if (firewall_enabled
)
1228 if (!is_process_elevated())
1230 skip("no privileges, skipping tests to avoid firewall dialog\n");
1233 if ((hr
= set_firewall(APP_ADD
)) != S_OK
)
1235 skip("can't authorize app in firewall %08x\n", hr
);
1242 CreateDiscoveryPublisher_tests();
1243 CreateDiscoveryPublisher_XMLContext_tests();
1248 if (firewall_enabled
) set_firewall(APP_REMOVE
);