2 * Web Services on Devices
4 * Copyright 2017-2018 Owen Rudge for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wsdapi_internal.h"
27 #include "wine/debug.h"
28 #include "wine/heap.h"
29 #include "webservices.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(wsdapi
);
33 #define APP_MAX_DELAY 500
35 static const WCHAR discoveryTo
[] = {
37 's','c','h','e','m','a','s','-','x','m','l','s','o','a','p','-','o','r','g',':',
38 'w','s',':','2','0','0','5',':','0','4',':',
39 'd','i','s','c','o','v','e','r','y', 0 };
41 static const WCHAR actionHello
[] = {
42 'h','t','t','p',':','/','/',
43 's','c','h','e','m','a','s','.','x','m','l','s','o','a','p','.','o','r','g','/',
44 'w','s','/','2','0','0','5','/','0','4','/',
45 'd','i','s','c','o','v','e','r','y','/',
46 'H','e','l','l','o', 0 };
48 static const WCHAR addressingNsUri
[] = {
49 'h','t','t','p',':','/','/',
50 's','c','h','e','m','a','s','.','x','m','l','s','o','a','p','.','o','r','g','/',
51 'w','s','/','2','0','0','4','/','0','8','/','a','d','d','r','e','s','s','i','n','g', 0 };
53 static const WCHAR discoveryNsUri
[] = {
54 'h','t','t','p',':','/','/',
55 's','c','h','e','m','a','s','.','x','m','l','s','o','a','p','.','o','r','g','/',
56 'w','s','/','2','0','0','5','/','0','4','/','d','i','s','c','o','v','e','r','y', 0 };
58 static const WCHAR envelopeNsUri
[] = {
59 'h','t','t','p',':','/','/',
60 'w','w','w','.','w','3','.','o','r','g','/',
61 '2','0','0','3','/','0','5','/','s','o','a','p','-','e','n','v','e','l','o','p','e', 0 };
63 static const WCHAR addressingPrefix
[] = { 'w','s','a', 0 };
64 static const WCHAR discoveryPrefix
[] = { 'w','s','d', 0 };
65 static const WCHAR envelopePrefix
[] = { 's','o','a','p', 0 };
66 static const WCHAR headerString
[] = { 'H','e','a','d','e','r', 0 };
67 static const WCHAR actionString
[] = { 'A','c','t','i','o','n', 0 };
68 static const WCHAR messageIdString
[] = { 'M','e','s','s','a','g','e','I','D', 0 };
69 static const WCHAR toString
[] = { 'T','o', 0 };
70 static const WCHAR relatesToString
[] = { 'R','e','l','a','t','e','s','T','o', 0 };
71 static const WCHAR appSequenceString
[] = { 'A','p','p','S','e','q','u','e','n','c','e', 0 };
72 static const WCHAR instanceIdString
[] = { 'I','n','s','t','a','n','c','e','I','d', 0 };
73 static const WCHAR messageNumberString
[] = { 'M','e','s','s','a','g','e','N','u','m','b','e','r', 0 };
74 static const WCHAR emptyString
[] = { 0 };
76 struct discovered_namespace
83 static char *wide_to_utf8(LPCWSTR wide_string
, int *length
)
85 char *new_string
= NULL
;
87 if (wide_string
== NULL
)
90 *length
= WideCharToMultiByte(CP_UTF8
, 0, wide_string
, -1, NULL
, 0, NULL
, NULL
);
95 new_string
= heap_alloc(*length
);
96 WideCharToMultiByte(CP_UTF8
, 0, wide_string
, -1, new_string
, *length
, NULL
, NULL
);
101 static WS_XML_STRING
*populate_xml_string(LPCWSTR str
)
103 WS_XML_STRING
*xml
= heap_alloc_zero(sizeof(WS_XML_STRING
));
109 xml
->bytes
= (BYTE
*)wide_to_utf8(str
, &utf8Length
);
111 if (xml
->bytes
== NULL
)
117 xml
->dictionary
= NULL
;
119 xml
->length
= (xml
->bytes
== NULL
) ? 0 : (utf8Length
- 1);
124 static inline void free_xml_string(WS_XML_STRING
*value
)
129 if (value
->bytes
!= NULL
)
130 heap_free(value
->bytes
);
135 static HRESULT
write_xml_attribute(WSDXML_ATTRIBUTE
*attribute
, WS_XML_WRITER
*writer
)
137 WS_XML_STRING
*local_name
= NULL
, *element_ns
= NULL
, *ns_prefix
= NULL
;
138 WS_XML_UTF16_TEXT utf16_text
;
139 HRESULT ret
= E_OUTOFMEMORY
;
142 if (attribute
== NULL
)
145 /* Start the attribute */
146 local_name
= populate_xml_string(attribute
->Name
->LocalName
);
147 if (local_name
== NULL
) goto cleanup
;
149 if (attribute
->Name
->Space
== NULL
)
151 element_ns
= populate_xml_string(emptyString
);
152 if (element_ns
== NULL
) goto cleanup
;
158 element_ns
= populate_xml_string(attribute
->Name
->Space
->Uri
);
159 if (element_ns
== NULL
) goto cleanup
;
161 ns_prefix
= populate_xml_string(attribute
->Name
->Space
->PreferredPrefix
);
162 if (ns_prefix
== NULL
) goto cleanup
;
165 ret
= WsWriteStartAttribute(writer
, ns_prefix
, local_name
, element_ns
, FALSE
, NULL
);
166 if (FAILED(ret
)) goto cleanup
;
168 text_len
= lstrlenW(attribute
->Value
);
170 utf16_text
.text
.textType
= WS_XML_TEXT_TYPE_UTF16
;
171 utf16_text
.bytes
= (BYTE
*)attribute
->Value
;
172 utf16_text
.byteCount
= min(WSD_MAX_TEXT_LENGTH
, text_len
) * sizeof(WCHAR
);
174 ret
= WsWriteText(writer
, (WS_XML_TEXT
*)&utf16_text
, NULL
);
175 if (FAILED(ret
)) goto cleanup
;
177 ret
= WsWriteEndAttribute(writer
, NULL
);
178 if (FAILED(ret
)) goto cleanup
;
181 free_xml_string(local_name
);
182 free_xml_string(element_ns
);
183 free_xml_string(ns_prefix
);
188 static HRESULT
write_xml_element(WSDXML_ELEMENT
*element
, WS_XML_WRITER
*writer
)
190 WS_XML_STRING
*local_name
= NULL
, *element_ns
= NULL
, *ns_prefix
= NULL
;
191 WSDXML_ATTRIBUTE
*current_attribute
;
192 WS_XML_UTF16_TEXT utf16_text
;
193 WSDXML_NODE
*current_child
;
194 WSDXML_TEXT
*node_as_text
;
196 HRESULT ret
= E_OUTOFMEMORY
;
201 /* Start the element */
202 local_name
= populate_xml_string(element
->Name
->LocalName
);
203 if (local_name
== NULL
) goto cleanup
;
205 element_ns
= populate_xml_string(element
->Name
->Space
->Uri
);
206 if (element_ns
== NULL
) goto cleanup
;
208 ns_prefix
= populate_xml_string(element
->Name
->Space
->PreferredPrefix
);
209 if (ns_prefix
== NULL
) goto cleanup
;
211 ret
= WsWriteStartElement(writer
, ns_prefix
, local_name
, element_ns
, NULL
);
212 if (FAILED(ret
)) goto cleanup
;
214 /* Write attributes */
215 current_attribute
= element
->FirstAttribute
;
217 while (current_attribute
!= NULL
)
219 ret
= write_xml_attribute(current_attribute
, writer
);
220 if (FAILED(ret
)) goto cleanup
;
221 current_attribute
= current_attribute
->Next
;
224 /* Write child elements */
225 current_child
= element
->FirstChild
;
227 while (current_child
!= NULL
)
229 if (current_child
->Type
== ElementType
)
231 ret
= write_xml_element((WSDXML_ELEMENT
*)current_child
, writer
);
232 if (FAILED(ret
)) goto cleanup
;
234 else if (current_child
->Type
== TextType
)
236 node_as_text
= (WSDXML_TEXT
*)current_child
;
237 text_len
= lstrlenW(node_as_text
->Text
);
239 utf16_text
.text
.textType
= WS_XML_TEXT_TYPE_UTF16
;
240 utf16_text
.byteCount
= min(WSD_MAX_TEXT_LENGTH
, text_len
) * sizeof(WCHAR
);
241 utf16_text
.bytes
= (BYTE
*)node_as_text
->Text
;
243 ret
= WsWriteText(writer
, (WS_XML_TEXT
*)&utf16_text
, NULL
);
244 if (FAILED(ret
)) goto cleanup
;
247 current_child
= current_child
->Next
;
250 /* End the element */
251 ret
= WsWriteEndElement(writer
, NULL
);
254 free_xml_string(local_name
);
255 free_xml_string(element_ns
);
256 free_xml_string(ns_prefix
);
261 static WSDXML_ELEMENT
*add_child_element(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
,
262 LPCWSTR name
, LPCWSTR text
)
264 WSDXML_ELEMENT
*element_obj
;
265 WSDXML_NAME
*name_obj
;
267 if (FAILED(IWSDXMLContext_AddNameToNamespace(xml_context
, ns_uri
, name
, &name_obj
)))
270 if (FAILED(WSDXMLBuildAnyForSingleElement(name_obj
, text
, &element_obj
)))
272 WSDFreeLinkedMemory(name_obj
);
276 WSDFreeLinkedMemory(name_obj
);
278 /* Add the element as a child - this will link the element's memory allocation to the parent's */
279 if (FAILED(WSDXMLAddChild(parent
, element_obj
)))
281 WSDFreeLinkedMemory(element_obj
);
288 static BOOL
create_guid(LPWSTR buffer
)
290 const WCHAR formatString
[] = { 'u','r','n',':','u','u','i','d',':','%','s', 0 };
292 WCHAR
* uuidString
= NULL
;
295 if (UuidCreate(&uuid
) != RPC_S_OK
)
298 UuidToStringW(&uuid
, (RPC_WSTR
*)&uuidString
);
300 if (uuidString
== NULL
)
303 wsprintfW(buffer
, formatString
, uuidString
);
304 RpcStringFreeW((RPC_WSTR
*)&uuidString
);
309 static void populate_soap_header(WSD_SOAP_HEADER
*header
, LPCWSTR to
, LPCWSTR action
, LPCWSTR message_id
,
310 WSD_APP_SEQUENCE
*sequence
, const WSDXML_ELEMENT
*any_headers
)
312 ZeroMemory(header
, sizeof(WSD_SOAP_HEADER
));
315 header
->Action
= action
;
316 header
->MessageID
= message_id
;
317 header
->AppSequence
= sequence
;
318 header
->AnyHeaders
= (WSDXML_ELEMENT
*)any_headers
;
320 /* TODO: Implement RelatesTo, ReplyTo, From, FaultTo */
323 #define MAX_ULONGLONG_STRING_SIZE 25
325 static LPWSTR
ulonglong_to_string(void *parent
, ULONGLONG value
)
327 WCHAR formatString
[] = { '%','I','6','4','u', 0 };
330 ret
= WSDAllocateLinkedMemory(parent
, MAX_ULONGLONG_STRING_SIZE
* sizeof(WCHAR
));
335 wsprintfW(ret
, formatString
, value
);
339 static WSDXML_ATTRIBUTE
*add_attribute(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
, LPCWSTR name
)
341 WSDXML_ATTRIBUTE
*attribute
, *cur_attrib
;
342 WSDXML_NAME
*name_obj
= NULL
;
346 name_obj
= WSDAllocateLinkedMemory(NULL
, sizeof(WSDXML_NAME
));
347 name_obj
->LocalName
= duplicate_string(name_obj
, name
);
348 name_obj
->Space
= NULL
;
352 if (FAILED(IWSDXMLContext_AddNameToNamespace(xml_context
, ns_uri
, name
, &name_obj
)))
356 attribute
= WSDAllocateLinkedMemory(parent
, sizeof(WSDXML_ATTRIBUTE
));
358 if (attribute
== NULL
)
360 WSDFreeLinkedMemory(name_obj
);
364 attribute
->Element
= parent
;
365 attribute
->Name
= name_obj
;
366 attribute
->Next
= NULL
;
367 attribute
->Value
= NULL
;
369 if (name_obj
!= NULL
)
370 WSDAttachLinkedMemory(attribute
, name_obj
);
372 if (parent
->FirstAttribute
== NULL
)
374 /* Make this the first attribute of the parent */
375 parent
->FirstAttribute
= attribute
;
379 /* Find the last attribute and add this as the next one */
380 cur_attrib
= parent
->FirstAttribute
;
382 while (cur_attrib
->Next
!= NULL
)
384 cur_attrib
= cur_attrib
->Next
;
387 cur_attrib
->Next
= attribute
;
393 static void remove_attribute(WSDXML_ELEMENT
*parent
, WSDXML_ATTRIBUTE
*attribute
)
395 WSDXML_ATTRIBUTE
*cur_attrib
;
397 /* Find the last attribute and add this as the next one */
398 cur_attrib
= parent
->FirstAttribute
;
400 if (cur_attrib
== attribute
)
401 parent
->FirstAttribute
= cur_attrib
->Next
;
404 while (cur_attrib
!= NULL
)
406 /* Is our attribute the next attribute? */
407 if (cur_attrib
->Next
== attribute
)
409 /* Remove it from the list */
410 cur_attrib
->Next
= attribute
->Next
;
414 cur_attrib
= cur_attrib
->Next
;
418 WSDFreeLinkedMemory(attribute
);
421 static BOOL
add_ulonglong_attribute(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
, LPCWSTR name
,
424 WSDXML_ATTRIBUTE
*attribute
= add_attribute(xml_context
, parent
, ns_uri
, name
);
426 if (attribute
== NULL
)
429 attribute
->Value
= ulonglong_to_string(attribute
, value
);
431 if (attribute
->Value
== NULL
)
433 remove_attribute(parent
, attribute
);
440 static BOOL
add_discovered_namespace(struct list
*namespaces
, WSDXML_NAMESPACE
*discovered_ns
)
442 struct discovered_namespace
*ns
;
444 LIST_FOR_EACH_ENTRY(ns
, namespaces
, struct discovered_namespace
, entry
)
446 if (lstrcmpW(ns
->uri
, discovered_ns
->Uri
) == 0)
447 return TRUE
; /* Already added */
450 ns
= WSDAllocateLinkedMemory(namespaces
, sizeof(struct discovered_namespace
));
455 ns
->prefix
= duplicate_string(ns
, discovered_ns
->PreferredPrefix
);
456 ns
->uri
= duplicate_string(ns
, discovered_ns
->Uri
);
458 if ((ns
->prefix
== NULL
) || (ns
->uri
== NULL
))
461 list_add_tail(namespaces
, &ns
->entry
);
465 static WSDXML_ELEMENT
*create_soap_header_xml_elements(IWSDXMLContext
*xml_context
, WSD_SOAP_HEADER
*header
)
467 WSDXML_ELEMENT
*header_element
= NULL
, *app_sequence_element
= NULL
;
468 WSDXML_NAME
*header_name
= NULL
;
471 if (FAILED(IWSDXMLContext_AddNameToNamespace(xml_context
, envelopeNsUri
, headerString
, &header_name
))) goto cleanup
;
472 if (FAILED(WSDXMLBuildAnyForSingleElement(header_name
, NULL
, &header_element
))) goto cleanup
;
473 WSDFreeLinkedMemory(header_name
);
476 if (add_child_element(xml_context
, header_element
, addressingNsUri
, actionString
, header
->Action
) == NULL
)
480 if (add_child_element(xml_context
, header_element
, addressingNsUri
, messageIdString
, header
->MessageID
) == NULL
)
484 if (add_child_element(xml_context
, header_element
, addressingNsUri
, toString
, header
->To
) == NULL
)
488 if (header
->RelatesTo
.MessageID
!= NULL
)
490 if (add_child_element(xml_context
, header_element
, addressingNsUri
, relatesToString
,
491 header
->RelatesTo
.MessageID
) == NULL
) goto cleanup
;
494 /* <d:AppSequence> */
495 app_sequence_element
= add_child_element(xml_context
, header_element
, discoveryNsUri
, appSequenceString
, emptyString
);
496 if (app_sequence_element
== NULL
) goto cleanup
;
498 /* InstanceId attribute */
499 if (!add_ulonglong_attribute(xml_context
, app_sequence_element
, NULL
, instanceIdString
, min(UINT_MAX
,
500 header
->AppSequence
->InstanceId
))) goto cleanup
;
502 /* MessageNumber attribute */
503 if (!add_ulonglong_attribute(xml_context
, app_sequence_element
, NULL
, messageNumberString
, min(UINT_MAX
,
504 header
->AppSequence
->MessageNumber
))) goto cleanup
;
506 /* TODO: SequenceID attribute */
508 /* </d:AppSequence> */
510 /* TODO: Write any headers */
514 return header_element
;
517 if (header_name
!= NULL
) WSDFreeLinkedMemory(header_name
);
518 WSDXMLCleanupElement(header_element
);
523 static HRESULT
create_soap_envelope(IWSDXMLContext
*xml_context
, WSD_SOAP_HEADER
*header
, WSDXML_ELEMENT
*body_element
,
524 WS_HEAP
**heap
, char **output_xml
, ULONG
*xml_length
, struct list
*discovered_namespaces
)
526 WS_XML_STRING
*actual_envelope_prefix
= NULL
, *envelope_uri_xmlstr
= NULL
, *tmp_prefix
= NULL
, *tmp_uri
= NULL
;
527 WSDXML_NAMESPACE
*addressing_ns
= NULL
, *discovery_ns
= NULL
, *envelope_ns
= NULL
;
528 WSDXML_ELEMENT
*header_element
= NULL
;
529 struct discovered_namespace
*ns
;
530 WS_XML_BUFFER
*buffer
= NULL
;
531 WS_XML_WRITER
*writer
= NULL
;
532 WS_XML_STRING envelope
;
533 HRESULT ret
= E_OUTOFMEMORY
;
534 static BYTE envelopeString
[] = "Envelope";
536 /* Create the necessary XML prefixes */
537 if (FAILED(IWSDXMLContext_AddNamespace(xml_context
, addressingNsUri
, addressingPrefix
, &addressing_ns
))) goto cleanup
;
538 if (!add_discovered_namespace(discovered_namespaces
, addressing_ns
)) goto cleanup
;
540 if (FAILED(IWSDXMLContext_AddNamespace(xml_context
, discoveryNsUri
, discoveryPrefix
, &discovery_ns
))) goto cleanup
;
541 if (!add_discovered_namespace(discovered_namespaces
, discovery_ns
)) goto cleanup
;
543 if (FAILED(IWSDXMLContext_AddNamespace(xml_context
, envelopeNsUri
, envelopePrefix
, &envelope_ns
))) goto cleanup
;
544 if (!add_discovered_namespace(discovered_namespaces
, envelope_ns
)) goto cleanup
;
546 envelope
.bytes
= envelopeString
;
547 envelope
.length
= sizeof(envelopeString
) - 1;
548 envelope
.dictionary
= NULL
;
551 actual_envelope_prefix
= populate_xml_string(envelope_ns
->PreferredPrefix
);
552 envelope_uri_xmlstr
= populate_xml_string(envelope_ns
->Uri
);
554 if ((actual_envelope_prefix
== NULL
) || (envelope_uri_xmlstr
== NULL
)) goto cleanup
;
556 /* Now try to create the appropriate WebServices buffers, etc */
557 ret
= WsCreateHeap(16384, 4096, NULL
, 0, heap
, NULL
);
558 if (FAILED(ret
)) goto cleanup
;
560 ret
= WsCreateXmlBuffer(*heap
, NULL
, 0, &buffer
, NULL
);
561 if (FAILED(ret
)) goto cleanup
;
563 ret
= WsCreateWriter(NULL
, 0, &writer
, NULL
);
564 if (FAILED(ret
)) goto cleanup
;
566 ret
= WsSetOutputToBuffer(writer
, buffer
, NULL
, 0, NULL
);
567 if (FAILED(ret
)) goto cleanup
;
569 /* Create the header XML elements */
570 header_element
= create_soap_header_xml_elements(xml_context
, header
);
571 if (header_element
== NULL
) goto cleanup
;
574 ret
= WsWriteStartElement(writer
, actual_envelope_prefix
, &envelope
, envelope_uri_xmlstr
, NULL
);
575 if (FAILED(ret
)) goto cleanup
;
577 LIST_FOR_EACH_ENTRY(ns
, discovered_namespaces
, struct discovered_namespace
, entry
)
579 tmp_prefix
= populate_xml_string(ns
->prefix
);
580 tmp_uri
= populate_xml_string(ns
->uri
);
582 if ((tmp_prefix
== NULL
) || (tmp_uri
== NULL
)) goto cleanup
;
584 ret
= WsWriteXmlnsAttribute(writer
, tmp_prefix
, tmp_uri
, FALSE
, NULL
);
585 if (FAILED(ret
)) goto cleanup
;
587 free_xml_string(tmp_prefix
);
588 free_xml_string(tmp_uri
);
594 /* Write the header */
595 ret
= write_xml_element(header_element
, writer
);
596 if (FAILED(ret
)) goto cleanup
;
598 ret
= WsWriteEndElement(writer
, NULL
);
599 if (FAILED(ret
)) goto cleanup
;
603 /* Generate the bytes of the document */
604 ret
= WsWriteXmlBufferToBytes(writer
, buffer
, NULL
, NULL
, 0, *heap
, (void**)output_xml
, xml_length
, NULL
);
605 if (FAILED(ret
)) goto cleanup
;
608 WSDFreeLinkedMemory(addressing_ns
);
609 WSDFreeLinkedMemory(discovery_ns
);
610 WSDFreeLinkedMemory(envelope_ns
);
612 WSDXMLCleanupElement(header_element
);
614 free_xml_string(actual_envelope_prefix
);
615 free_xml_string(envelope_uri_xmlstr
);
618 WsFreeWriter(writer
);
620 /* Don't free the heap unless the operation has failed */
621 if ((FAILED(ret
)) && (*heap
!= NULL
))
630 static HRESULT
write_and_send_message(IWSDiscoveryPublisherImpl
*impl
, WSD_SOAP_HEADER
*header
, WSDXML_ELEMENT
*body_element
,
631 struct list
*discovered_namespaces
, IWSDUdpAddress
*remote_address
, int max_initial_delay
)
633 static const char xml_header
[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
634 ULONG xml_length
= 0, xml_header_len
= sizeof(xml_header
) - 1;
635 WS_HEAP
*heap
= NULL
;
640 ret
= create_soap_envelope(impl
->xmlContext
, header
, NULL
, &heap
, &xml
, &xml_length
, discovered_namespaces
);
641 if (ret
!= S_OK
) return ret
;
643 /* Prefix the XML header */
644 full_xml
= heap_alloc(xml_length
+ xml_header_len
+ 1);
646 if (full_xml
== NULL
)
649 return E_OUTOFMEMORY
;
652 memcpy(full_xml
, xml_header
, xml_header_len
);
653 memcpy(full_xml
+ xml_header_len
, xml
, xml_length
);
654 full_xml
[xml_length
+ xml_header_len
] = 0;
656 if (remote_address
== NULL
)
658 /* Send the message via UDP multicast */
659 ret
= send_udp_multicast(impl
, full_xml
, xml_length
+ xml_header_len
+ 1, max_initial_delay
) ? S_OK
: E_FAIL
;
663 /* TODO: Send the message via UDP unicast */
664 FIXME("TODO: Send the message via UDP unicast\n");
673 HRESULT
send_hello_message(IWSDiscoveryPublisherImpl
*impl
, LPCWSTR id
, ULONGLONG metadata_ver
, ULONGLONG instance_id
,
674 ULONGLONG msg_num
, LPCWSTR session_id
, const WSD_NAME_LIST
*types_list
, const WSD_URI_LIST
*scopes_list
,
675 const WSD_URI_LIST
*xaddrs_list
, const WSDXML_ELEMENT
*hdr_any
, const WSDXML_ELEMENT
*ref_param_any
,
676 const WSDXML_ELEMENT
*endpoint_ref_any
, const WSDXML_ELEMENT
*any
)
678 struct list
*discoveredNamespaces
= NULL
;
679 WSD_SOAP_HEADER soapHeader
;
680 WSD_APP_SEQUENCE sequence
;
681 WCHAR message_id
[64];
682 HRESULT ret
= E_OUTOFMEMORY
;
684 sequence
.InstanceId
= instance_id
;
685 sequence
.MessageNumber
= msg_num
;
686 sequence
.SequenceId
= session_id
;
688 if (!create_guid(message_id
)) goto cleanup
;
690 discoveredNamespaces
= WSDAllocateLinkedMemory(NULL
, sizeof(struct list
));
691 if (!discoveredNamespaces
) goto cleanup
;
693 list_init(discoveredNamespaces
);
695 populate_soap_header(&soapHeader
, discoveryTo
, actionHello
, message_id
, &sequence
, hdr_any
);
697 /* TODO: Populate message body */
699 /* Write and send the message */
700 ret
= write_and_send_message(impl
, &soapHeader
, NULL
, discoveredNamespaces
, NULL
, APP_MAX_DELAY
);
703 WSDFreeLinkedMemory(discoveredNamespaces
);