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 "<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
{
70 CRITICAL_SECTION criticalSection
;
71 char* messages
[MAX_CACHED_MESSAGES
];
73 HANDLE threadHandles
[MAX_LISTENING_THREADS
];
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
);
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
;
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
;
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
;
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
);
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
;
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
)
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
;
216 closesocket(parameter
->listeningSocket
);
219 heap_free(parameter
);
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;
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
)
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
++;
262 heap_free(parameter
);
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;
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
;
327 heap_free(parameter
);
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;
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
)
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
);
376 heap_free(adapterAddresses
);
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;
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
);
396 multi_address
= resolve_address(SEND_ADDRESS_IPV4
, SEND_PORT
, AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
398 if (multi_address
== NULL
)
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
)
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
);
440 freeaddrinfo(multi_address
);
441 heap_free(adapter_addresses
);
445 typedef struct IWSDiscoveryPublisherNotifyImpl
{
446 IWSDiscoveryPublisherNotify IWSDiscoveryPublisherNotify_iface
;
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
);
466 if (IsEqualIID(riid
, &IID_IUnknown
) ||
467 IsEqualIID(riid
, &IID_IWSDiscoveryPublisherNotify
))
469 *ppv
= &This
->IWSDiscoveryPublisherNotify_iface
;
473 return E_NOINTERFACE
;
476 IUnknown_AddRef((IUnknown
*)*ppv
);
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
);
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
);
498 HeapFree(GetProcessHeap(), 0, This
);
504 static void verify_wsdxml_name(const char *debug_prefix
, WSDXML_NAME
*name
, LPCWSTR uri
, LPCWSTR prefix
,
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
)
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
);
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 */
561 ok(pSoap
!= NULL
, "pSoap == NULL\n");
562 ok(pMessageParameters
!= NULL
, "pMessageParameters == NULL\n");
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))
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");
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
;
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
;
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
;
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>",
715 /* Check we're received the correct message */
716 for (i
= 0; i
< msg_storage
->messageCount
; i
++)
718 msg
= msg_storage
->messages
[i
];
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
);
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
);
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
));
790 trace("Out of memory creating IWSDiscoveryPublisherNotify\n");
794 obj
->IWSDiscoveryPublisherNotify_iface
.lpVtbl
= &publisherNotify_vtbl
;
797 *publisherNotify
= &obj
->IWSDiscoveryPublisherNotify_iface
;
802 static void CreateDiscoveryPublisher_tests(void)
804 IWSDiscoveryPublisher
*publisher
= NULL
;
805 IWSDiscoveryPublisher
*publisher2
;
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
);
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
);
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
;
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 */
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
;
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
;
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 */
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>",
1052 /* Check we're received the correct message */
1053 for (i
= 0; i
< msgStorage
->messageCount
; i
++)
1055 msg
= msgStorage
->messages
[i
];
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");
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
);
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
;
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
;
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>",
1219 sprintf(app_sequence_string
, "<wsd:AppSequence InstanceId=\"1\" SequenceId=\"%s\" MessageNumber=\"1\"></wsd:AppSequence>",
1224 /* Check we're received the correct message */
1225 for (i
= 0; i
< msg_storage
->messageCount
; i
++)
1227 msg
= msg_storage
->messages
[i
];
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
);
1277 static BOOL
is_process_elevated(void)
1280 if (OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY
, &token
))
1282 TOKEN_ELEVATION_TYPE type
;
1286 ret
= GetTokenInformation( token
, TokenElevationType
, &type
, sizeof(type
), &size
);
1287 CloseHandle( token
);
1288 return (ret
&& type
== TokenElevationTypeFull
);
1293 static BOOL
is_firewall_enabled(void)
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
,
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
);
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
)
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
);
1341 init
= CoInitializeEx( 0, COINIT_APARTMENTTHREADED
);
1343 hr
= CoCreateInstance( &CLSID_NetFwMgr
, NULL
, CLSCTX_INPROC_SERVER
, &IID_INetFwMgr
,
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
;
1374 hr
= INetFwAuthorizedApplications_Add( apps
, app
);
1375 else if (op
== APP_REMOVE
)
1376 hr
= INetFwAuthorizedApplications_Remove( apps
, image
);
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
);
1391 START_TEST(discovery
)
1393 BOOL firewall_enabled
= is_firewall_enabled();
1396 if (firewall_enabled
)
1398 if (!is_process_elevated())
1400 skip("no privileges, skipping tests to avoid firewall dialog\n");
1403 if ((hr
= set_firewall(APP_ADD
)) != S_OK
)
1405 skip("can't authorize app in firewall %08x\n", hr
);
1412 CreateDiscoveryPublisher_tests();
1413 CreateDiscoveryPublisher_XMLContext_tests();
1418 if (firewall_enabled
) set_firewall(APP_REMOVE
);