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 sequenceIdString
[] = { 'S','e','q','u','e','n','c','e','I','d', 0 };
75 static const WCHAR emptyString
[] = { 0 };
76 static const WCHAR bodyString
[] = { 'B','o','d','y', 0 };
77 static const WCHAR helloString
[] = { 'H','e','l','l','o', 0 };
78 static const WCHAR endpointReferenceString
[] = { 'E','n','d','p','o','i','n','t','R','e','f','e','r','e','n','c','e', 0 };
79 static const WCHAR addressString
[] = { 'A','d','d','r','e','s','s', 0 };
80 static const WCHAR typesString
[] = { 'T','y','p','e','s', 0 };
81 static const WCHAR scopesString
[] = { 'S','c','o','p','e','s', 0 };
82 static const WCHAR xAddrsString
[] = { 'X','A','d','d','r','s', 0 };
84 struct discovered_namespace
91 static char *wide_to_utf8(LPCWSTR wide_string
, int *length
)
93 char *new_string
= NULL
;
95 if (wide_string
== NULL
)
98 *length
= WideCharToMultiByte(CP_UTF8
, 0, wide_string
, -1, NULL
, 0, NULL
, NULL
);
103 new_string
= heap_alloc(*length
);
104 WideCharToMultiByte(CP_UTF8
, 0, wide_string
, -1, new_string
, *length
, NULL
, NULL
);
109 static WS_XML_STRING
*populate_xml_string(LPCWSTR str
)
111 WS_XML_STRING
*xml
= heap_alloc_zero(sizeof(WS_XML_STRING
));
117 xml
->bytes
= (BYTE
*)wide_to_utf8(str
, &utf8Length
);
119 if (xml
->bytes
== NULL
)
125 xml
->dictionary
= NULL
;
127 xml
->length
= (xml
->bytes
== NULL
) ? 0 : (utf8Length
- 1);
132 static inline void free_xml_string(WS_XML_STRING
*value
)
137 heap_free(value
->bytes
);
142 static HRESULT
write_xml_attribute(WSDXML_ATTRIBUTE
*attribute
, WS_XML_WRITER
*writer
)
144 WS_XML_STRING
*local_name
= NULL
, *element_ns
= NULL
, *ns_prefix
= NULL
;
145 WS_XML_UTF16_TEXT utf16_text
;
146 HRESULT ret
= E_OUTOFMEMORY
;
149 if (attribute
== NULL
)
152 /* Start the attribute */
153 local_name
= populate_xml_string(attribute
->Name
->LocalName
);
154 if (local_name
== NULL
) goto cleanup
;
156 if (attribute
->Name
->Space
== NULL
)
158 element_ns
= populate_xml_string(emptyString
);
159 if (element_ns
== NULL
) goto cleanup
;
165 element_ns
= populate_xml_string(attribute
->Name
->Space
->Uri
);
166 if (element_ns
== NULL
) goto cleanup
;
168 ns_prefix
= populate_xml_string(attribute
->Name
->Space
->PreferredPrefix
);
169 if (ns_prefix
== NULL
) goto cleanup
;
172 ret
= WsWriteStartAttribute(writer
, ns_prefix
, local_name
, element_ns
, FALSE
, NULL
);
173 if (FAILED(ret
)) goto cleanup
;
175 text_len
= lstrlenW(attribute
->Value
);
177 utf16_text
.text
.textType
= WS_XML_TEXT_TYPE_UTF16
;
178 utf16_text
.bytes
= (BYTE
*)attribute
->Value
;
179 utf16_text
.byteCount
= min(WSD_MAX_TEXT_LENGTH
, text_len
) * sizeof(WCHAR
);
181 ret
= WsWriteText(writer
, (WS_XML_TEXT
*)&utf16_text
, NULL
);
182 if (FAILED(ret
)) goto cleanup
;
184 ret
= WsWriteEndAttribute(writer
, NULL
);
185 if (FAILED(ret
)) goto cleanup
;
188 free_xml_string(local_name
);
189 free_xml_string(element_ns
);
190 free_xml_string(ns_prefix
);
195 static HRESULT
write_xml_element(WSDXML_ELEMENT
*element
, WS_XML_WRITER
*writer
)
197 WS_XML_STRING
*local_name
= NULL
, *element_ns
= NULL
, *ns_prefix
= NULL
;
198 WSDXML_ATTRIBUTE
*current_attribute
;
199 WS_XML_UTF16_TEXT utf16_text
;
200 WSDXML_NODE
*current_child
;
201 WSDXML_TEXT
*node_as_text
;
203 HRESULT ret
= E_OUTOFMEMORY
;
208 /* Start the element */
209 local_name
= populate_xml_string(element
->Name
->LocalName
);
210 if (local_name
== NULL
) goto cleanup
;
212 element_ns
= populate_xml_string(element
->Name
->Space
->Uri
);
213 if (element_ns
== NULL
) goto cleanup
;
215 ns_prefix
= populate_xml_string(element
->Name
->Space
->PreferredPrefix
);
216 if (ns_prefix
== NULL
) goto cleanup
;
218 ret
= WsWriteStartElement(writer
, ns_prefix
, local_name
, element_ns
, NULL
);
219 if (FAILED(ret
)) goto cleanup
;
221 /* Write attributes */
222 current_attribute
= element
->FirstAttribute
;
224 while (current_attribute
!= NULL
)
226 ret
= write_xml_attribute(current_attribute
, writer
);
227 if (FAILED(ret
)) goto cleanup
;
228 current_attribute
= current_attribute
->Next
;
231 /* Write child elements */
232 current_child
= element
->FirstChild
;
234 while (current_child
!= NULL
)
236 if (current_child
->Type
== ElementType
)
238 ret
= write_xml_element((WSDXML_ELEMENT
*)current_child
, writer
);
239 if (FAILED(ret
)) goto cleanup
;
241 else if (current_child
->Type
== TextType
)
243 node_as_text
= (WSDXML_TEXT
*)current_child
;
244 text_len
= lstrlenW(node_as_text
->Text
);
246 utf16_text
.text
.textType
= WS_XML_TEXT_TYPE_UTF16
;
247 utf16_text
.byteCount
= min(WSD_MAX_TEXT_LENGTH
, text_len
) * sizeof(WCHAR
);
248 utf16_text
.bytes
= (BYTE
*)node_as_text
->Text
;
250 ret
= WsWriteText(writer
, (WS_XML_TEXT
*)&utf16_text
, NULL
);
251 if (FAILED(ret
)) goto cleanup
;
254 current_child
= current_child
->Next
;
257 /* End the element */
258 ret
= WsWriteEndElement(writer
, NULL
);
261 free_xml_string(local_name
);
262 free_xml_string(element_ns
);
263 free_xml_string(ns_prefix
);
268 static HRESULT
add_child_element(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
,
269 LPCWSTR name
, LPCWSTR text
, WSDXML_ELEMENT
**out
)
271 WSDXML_ELEMENT
*element_obj
;
272 WSDXML_NAME
*name_obj
;
275 ret
= IWSDXMLContext_AddNameToNamespace(xml_context
, ns_uri
, name
, &name_obj
);
276 if (FAILED(ret
)) return ret
;
278 ret
= WSDXMLBuildAnyForSingleElement(name_obj
, text
, &element_obj
);
279 WSDFreeLinkedMemory(name_obj
);
281 if (FAILED(ret
)) return ret
;
283 /* Add the element as a child - this will link the element's memory allocation to the parent's */
284 ret
= WSDXMLAddChild(parent
, element_obj
);
288 WSDFreeLinkedMemory(element_obj
);
292 if (out
!= NULL
) *out
= element_obj
;
296 HRESULT
register_namespaces(IWSDXMLContext
*xml_context
)
300 ret
= IWSDXMLContext_AddNamespace(xml_context
, addressingNsUri
, addressingPrefix
, NULL
);
301 if (FAILED(ret
)) return ret
;
303 ret
= IWSDXMLContext_AddNamespace(xml_context
, discoveryNsUri
, discoveryPrefix
, NULL
);
304 if (FAILED(ret
)) return ret
;
306 return IWSDXMLContext_AddNamespace(xml_context
, envelopeNsUri
, envelopePrefix
, NULL
);
309 static BOOL
create_guid(LPWSTR buffer
)
311 const WCHAR formatString
[] = { 'u','r','n',':','u','u','i','d',':','%','s', 0 };
313 WCHAR
* uuidString
= NULL
;
316 if (UuidCreate(&uuid
) != RPC_S_OK
)
319 UuidToStringW(&uuid
, (RPC_WSTR
*)&uuidString
);
321 if (uuidString
== NULL
)
324 wsprintfW(buffer
, formatString
, uuidString
);
325 RpcStringFreeW((RPC_WSTR
*)&uuidString
);
330 static void populate_soap_header(WSD_SOAP_HEADER
*header
, LPCWSTR to
, LPCWSTR action
, LPCWSTR message_id
,
331 WSD_APP_SEQUENCE
*sequence
, const WSDXML_ELEMENT
*any_headers
)
333 ZeroMemory(header
, sizeof(WSD_SOAP_HEADER
));
336 header
->Action
= action
;
337 header
->MessageID
= message_id
;
338 header
->AppSequence
= sequence
;
339 header
->AnyHeaders
= (WSDXML_ELEMENT
*)any_headers
;
341 /* TODO: Implement RelatesTo, ReplyTo, From, FaultTo */
344 #define MAX_ULONGLONG_STRING_SIZE 25
346 static LPWSTR
ulonglong_to_string(void *parent
, ULONGLONG value
)
348 WCHAR formatString
[] = { '%','I','6','4','u', 0 };
351 ret
= WSDAllocateLinkedMemory(parent
, MAX_ULONGLONG_STRING_SIZE
* sizeof(WCHAR
));
356 wsprintfW(ret
, formatString
, value
);
360 static WSDXML_ATTRIBUTE
*add_attribute(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
, LPCWSTR name
)
362 WSDXML_ATTRIBUTE
*attribute
, *cur_attrib
;
363 WSDXML_NAME
*name_obj
= NULL
;
367 name_obj
= WSDAllocateLinkedMemory(NULL
, sizeof(WSDXML_NAME
));
368 name_obj
->LocalName
= duplicate_string(name_obj
, name
);
369 name_obj
->Space
= NULL
;
373 if (FAILED(IWSDXMLContext_AddNameToNamespace(xml_context
, ns_uri
, name
, &name_obj
)))
377 attribute
= WSDAllocateLinkedMemory(parent
, sizeof(WSDXML_ATTRIBUTE
));
379 if (attribute
== NULL
)
381 WSDFreeLinkedMemory(name_obj
);
385 attribute
->Element
= parent
;
386 attribute
->Name
= name_obj
;
387 attribute
->Next
= NULL
;
388 attribute
->Value
= NULL
;
390 if (name_obj
!= NULL
)
391 WSDAttachLinkedMemory(attribute
, name_obj
);
393 if (parent
->FirstAttribute
== NULL
)
395 /* Make this the first attribute of the parent */
396 parent
->FirstAttribute
= attribute
;
400 /* Find the last attribute and add this as the next one */
401 cur_attrib
= parent
->FirstAttribute
;
403 while (cur_attrib
->Next
!= NULL
)
405 cur_attrib
= cur_attrib
->Next
;
408 cur_attrib
->Next
= attribute
;
414 static void remove_attribute(WSDXML_ELEMENT
*parent
, WSDXML_ATTRIBUTE
*attribute
)
416 WSDXML_ATTRIBUTE
*cur_attrib
;
418 /* Find the last attribute and add this as the next one */
419 cur_attrib
= parent
->FirstAttribute
;
421 if (cur_attrib
== attribute
)
422 parent
->FirstAttribute
= cur_attrib
->Next
;
425 while (cur_attrib
!= NULL
)
427 /* Is our attribute the next attribute? */
428 if (cur_attrib
->Next
== attribute
)
430 /* Remove it from the list */
431 cur_attrib
->Next
= attribute
->Next
;
435 cur_attrib
= cur_attrib
->Next
;
439 WSDFreeLinkedMemory(attribute
);
442 static HRESULT
add_ulonglong_attribute(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
, LPCWSTR name
,
445 WSDXML_ATTRIBUTE
*attribute
= add_attribute(xml_context
, parent
, ns_uri
, name
);
447 if (attribute
== NULL
)
450 attribute
->Value
= ulonglong_to_string(attribute
, value
);
452 if (attribute
->Value
== NULL
)
454 remove_attribute(parent
, attribute
);
461 static HRESULT
add_string_attribute(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
, LPCWSTR name
,
464 WSDXML_ATTRIBUTE
*attribute
= add_attribute(xml_context
, parent
, ns_uri
, name
);
466 if (attribute
== NULL
)
469 attribute
->Value
= duplicate_string(attribute
, value
);
471 if (attribute
->Value
== NULL
)
473 remove_attribute(parent
, attribute
);
480 static BOOL
add_discovered_namespace(struct list
*namespaces
, WSDXML_NAMESPACE
*discovered_ns
)
482 struct discovered_namespace
*ns
;
484 LIST_FOR_EACH_ENTRY(ns
, namespaces
, struct discovered_namespace
, entry
)
486 if (lstrcmpW(ns
->uri
, discovered_ns
->Uri
) == 0)
487 return TRUE
; /* Already added */
490 ns
= WSDAllocateLinkedMemory(namespaces
, sizeof(struct discovered_namespace
));
495 ns
->prefix
= duplicate_string(ns
, discovered_ns
->PreferredPrefix
);
496 ns
->uri
= duplicate_string(ns
, discovered_ns
->Uri
);
498 if ((ns
->prefix
== NULL
) || (ns
->uri
== NULL
))
501 list_add_tail(namespaces
, &ns
->entry
);
505 static HRESULT
build_types_list(LPWSTR buffer
, size_t buffer_size
, const WSD_NAME_LIST
*list
, struct list
*namespaces
)
507 WCHAR format_string
[] = { '%', 's', ':', '%', 's', 0 };
508 LPWSTR current_buf_pos
= buffer
;
509 size_t memory_needed
= 0;
510 const WSD_NAME_LIST
*cur
= list
;
514 /* Calculate space needed, including NULL character, colon and potential trailing space */
515 memory_needed
= sizeof(WCHAR
) * (lstrlenW(cur
->Element
->LocalName
) +
516 lstrlenW(cur
->Element
->Space
->PreferredPrefix
) + 3);
518 if (current_buf_pos
+ memory_needed
> buffer
+ buffer_size
)
522 *current_buf_pos
++ = ' ';
524 current_buf_pos
+= wsprintfW(current_buf_pos
, format_string
, cur
->Element
->Space
->PreferredPrefix
,
525 cur
->Element
->LocalName
);
527 /* Record the namespace in the discovered namespaces list */
528 if (!add_discovered_namespace(namespaces
, cur
->Element
->Space
))
532 } while (cur
!= NULL
);
537 static HRESULT
build_uri_list(LPWSTR buffer
, size_t buffer_size
, const WSD_URI_LIST
*list
)
539 size_t memory_needed
= 0, string_len
= 0;
540 const WSD_URI_LIST
*cur
= list
;
541 LPWSTR cur_buf_pos
= buffer
;
545 /* Calculate space needed, including trailing space */
546 string_len
= lstrlenW(cur
->Element
);
547 memory_needed
= (string_len
+ 1) * sizeof(WCHAR
);
549 if (cur_buf_pos
+ memory_needed
> buffer
+ buffer_size
)
553 *cur_buf_pos
++ = ' ';
555 memcpy(cur_buf_pos
, cur
->Element
, memory_needed
);
556 cur_buf_pos
+= string_len
;
559 } while (cur
!= NULL
);
564 static HRESULT
duplicate_element(WSDXML_ELEMENT
*parent
, const WSDXML_ELEMENT
*node
, struct list
*namespaces
)
566 WSDXML_ATTRIBUTE
*cur_attribute
, *new_attribute
, *last_attribute
= NULL
;
567 WSDXML_ELEMENT
*new_element
;
568 WSDXML_TEXT
*text_node
;
569 WSDXML_NODE
*cur_node
;
572 /* First record the namespace in the discovered namespaces list */
573 if (!add_discovered_namespace(namespaces
, node
->Name
->Space
))
576 ret
= WSDXMLBuildAnyForSingleElement(node
->Name
, NULL
, &new_element
);
577 if (FAILED(ret
)) return ret
;
579 /* Duplicate the nodes */
580 cur_node
= node
->FirstChild
;
582 while (cur_node
!= NULL
)
584 if (cur_node
->Type
== ElementType
)
586 ret
= duplicate_element(new_element
, (WSDXML_ELEMENT
*)cur_node
, namespaces
);
587 if (FAILED(ret
)) goto cleanup
;
589 else if (cur_node
->Type
== TextType
)
591 text_node
= WSDAllocateLinkedMemory(new_element
, sizeof(WSDXML_TEXT
));
592 if (text_node
== NULL
) goto failed
;
594 text_node
->Node
.Parent
= NULL
;
595 text_node
->Node
.Next
= NULL
;
596 text_node
->Node
.Type
= TextType
;
597 text_node
->Text
= duplicate_string(text_node
, ((WSDXML_TEXT
*)cur_node
)->Text
);
599 if (text_node
->Text
== NULL
) goto failed
;
601 ret
= WSDXMLAddChild(new_element
, (WSDXML_ELEMENT
*)text_node
);
602 if (FAILED(ret
)) goto cleanup
;
605 cur_node
= cur_node
->Next
;
608 /* Duplicate the attributes */
609 cur_attribute
= node
->FirstAttribute
;
611 while (cur_attribute
!= NULL
)
613 if ((cur_attribute
->Name
->Space
!= NULL
) && (!add_discovered_namespace(namespaces
, cur_attribute
->Name
->Space
)))
616 new_attribute
= WSDAllocateLinkedMemory(new_element
, sizeof(WSDXML_ATTRIBUTE
));
617 if (new_attribute
== NULL
) goto failed
;
619 new_attribute
->Element
= new_element
;
620 new_attribute
->Name
= duplicate_name(new_attribute
, cur_attribute
->Name
);
621 new_attribute
->Value
= duplicate_string(new_attribute
, cur_attribute
->Value
);
622 new_attribute
->Next
= NULL
;
624 if ((new_attribute
->Name
== NULL
) || (new_attribute
->Value
== NULL
)) goto failed
;
626 if (last_attribute
== NULL
)
627 new_element
->FirstAttribute
= new_attribute
;
629 last_attribute
->Next
= new_attribute
;
631 last_attribute
= new_attribute
;
632 cur_attribute
= cur_attribute
->Next
;
635 ret
= WSDXMLAddChild(parent
, new_element
);
636 if (FAILED(ret
)) goto cleanup
;
644 WSDXMLCleanupElement(new_element
);
648 static HRESULT
create_soap_header_xml_elements(IWSDXMLContext
*xml_context
, WSD_SOAP_HEADER
*header
,
649 struct list
*discovered_namespaces
, WSDXML_ELEMENT
**out_element
)
651 WSDXML_ELEMENT
*header_element
= NULL
, *app_sequence_element
= NULL
, *temp_element
;
652 WSDXML_NAME
*header_name
= NULL
;
656 ret
= IWSDXMLContext_AddNameToNamespace(xml_context
, envelopeNsUri
, headerString
, &header_name
);
657 if (FAILED(ret
)) goto cleanup
;
659 ret
= WSDXMLBuildAnyForSingleElement(header_name
, NULL
, &header_element
);
660 if (FAILED(ret
)) goto cleanup
;
662 WSDFreeLinkedMemory(header_name
);
665 ret
= add_child_element(xml_context
, header_element
, addressingNsUri
, actionString
, header
->Action
, &temp_element
);
666 if (FAILED(ret
)) goto cleanup
;
669 ret
= add_child_element(xml_context
, header_element
, addressingNsUri
, messageIdString
, header
->MessageID
, &temp_element
);
670 if (FAILED(ret
)) goto cleanup
;
673 ret
= add_child_element(xml_context
, header_element
, addressingNsUri
, toString
, header
->To
, &temp_element
);
674 if (FAILED(ret
)) goto cleanup
;
677 if (header
->RelatesTo
.MessageID
!= NULL
)
679 ret
= add_child_element(xml_context
, header_element
, addressingNsUri
, relatesToString
,
680 header
->RelatesTo
.MessageID
, &temp_element
);
681 if (FAILED(ret
)) goto cleanup
;
684 /* <d:AppSequence> */
685 ret
= add_child_element(xml_context
, header_element
, discoveryNsUri
, appSequenceString
, emptyString
, &app_sequence_element
);
686 if (FAILED(ret
)) goto cleanup
;
688 /* InstanceId attribute */
689 ret
= add_ulonglong_attribute(xml_context
, app_sequence_element
, NULL
, instanceIdString
, min(UINT_MAX
,
690 header
->AppSequence
->InstanceId
));
691 if (FAILED(ret
)) goto cleanup
;
693 /* SequenceID attribute */
694 if (header
->AppSequence
->SequenceId
!= NULL
)
696 ret
= add_string_attribute(xml_context
, app_sequence_element
, NULL
, sequenceIdString
, header
->AppSequence
->SequenceId
);
697 if (FAILED(ret
)) goto cleanup
;
700 /* MessageNumber attribute */
701 ret
= add_ulonglong_attribute(xml_context
, app_sequence_element
, NULL
, messageNumberString
, min(UINT_MAX
,
702 header
->AppSequence
->MessageNumber
));
703 if (FAILED(ret
)) goto cleanup
;
705 /* </d:AppSequence> */
707 /* Write any headers */
708 if (header
->AnyHeaders
!= NULL
)
710 ret
= duplicate_element(header_element
, header
->AnyHeaders
, discovered_namespaces
);
711 if (FAILED(ret
)) goto cleanup
;
716 *out_element
= header_element
;
720 if (header_name
!= NULL
) WSDFreeLinkedMemory(header_name
);
721 WSDXMLCleanupElement(header_element
);
726 static HRESULT
create_soap_envelope(IWSDXMLContext
*xml_context
, WSD_SOAP_HEADER
*header
, WSDXML_ELEMENT
*body_element
,
727 WS_HEAP
**heap
, char **output_xml
, ULONG
*xml_length
, struct list
*discovered_namespaces
)
729 WS_XML_STRING
*actual_envelope_prefix
= NULL
, *envelope_uri_xmlstr
= NULL
, *tmp_prefix
= NULL
, *tmp_uri
= NULL
;
730 WSDXML_NAMESPACE
*addressing_ns
= NULL
, *discovery_ns
= NULL
, *envelope_ns
= NULL
;
731 WSDXML_ELEMENT
*header_element
= NULL
;
732 struct discovered_namespace
*ns
;
733 WS_XML_BUFFER
*buffer
= NULL
;
734 WS_XML_WRITER
*writer
= NULL
;
735 WS_XML_STRING envelope
;
736 HRESULT ret
= E_OUTOFMEMORY
;
737 static BYTE envelopeString
[] = "Envelope";
739 /* Create the necessary XML prefixes */
740 if (FAILED(IWSDXMLContext_AddNamespace(xml_context
, addressingNsUri
, addressingPrefix
, &addressing_ns
))) goto cleanup
;
741 if (!add_discovered_namespace(discovered_namespaces
, addressing_ns
)) goto cleanup
;
743 if (FAILED(IWSDXMLContext_AddNamespace(xml_context
, discoveryNsUri
, discoveryPrefix
, &discovery_ns
))) goto cleanup
;
744 if (!add_discovered_namespace(discovered_namespaces
, discovery_ns
)) goto cleanup
;
746 if (FAILED(IWSDXMLContext_AddNamespace(xml_context
, envelopeNsUri
, envelopePrefix
, &envelope_ns
))) goto cleanup
;
747 if (!add_discovered_namespace(discovered_namespaces
, envelope_ns
)) goto cleanup
;
749 envelope
.bytes
= envelopeString
;
750 envelope
.length
= sizeof(envelopeString
) - 1;
751 envelope
.dictionary
= NULL
;
754 actual_envelope_prefix
= populate_xml_string(envelope_ns
->PreferredPrefix
);
755 envelope_uri_xmlstr
= populate_xml_string(envelope_ns
->Uri
);
757 if ((actual_envelope_prefix
== NULL
) || (envelope_uri_xmlstr
== NULL
)) goto cleanup
;
759 /* Now try to create the appropriate WebServices buffers, etc */
760 ret
= WsCreateHeap(16384, 4096, NULL
, 0, heap
, NULL
);
761 if (FAILED(ret
)) goto cleanup
;
763 ret
= WsCreateXmlBuffer(*heap
, NULL
, 0, &buffer
, NULL
);
764 if (FAILED(ret
)) goto cleanup
;
766 ret
= WsCreateWriter(NULL
, 0, &writer
, NULL
);
767 if (FAILED(ret
)) goto cleanup
;
769 ret
= WsSetOutputToBuffer(writer
, buffer
, NULL
, 0, NULL
);
770 if (FAILED(ret
)) goto cleanup
;
772 /* Create the header XML elements */
773 ret
= create_soap_header_xml_elements(xml_context
, header
, discovered_namespaces
, &header_element
);
774 if (FAILED(ret
)) goto cleanup
;
777 ret
= WsWriteStartElement(writer
, actual_envelope_prefix
, &envelope
, envelope_uri_xmlstr
, NULL
);
778 if (FAILED(ret
)) goto cleanup
;
780 LIST_FOR_EACH_ENTRY(ns
, discovered_namespaces
, struct discovered_namespace
, entry
)
782 tmp_prefix
= populate_xml_string(ns
->prefix
);
783 tmp_uri
= populate_xml_string(ns
->uri
);
785 if ((tmp_prefix
== NULL
) || (tmp_uri
== NULL
)) goto cleanup
;
787 ret
= WsWriteXmlnsAttribute(writer
, tmp_prefix
, tmp_uri
, FALSE
, NULL
);
788 if (FAILED(ret
)) goto cleanup
;
790 free_xml_string(tmp_prefix
);
791 free_xml_string(tmp_uri
);
797 /* Write the header */
798 ret
= write_xml_element(header_element
, writer
);
799 if (FAILED(ret
)) goto cleanup
;
802 ret
= write_xml_element(body_element
, writer
);
803 if (FAILED(ret
)) goto cleanup
;
805 ret
= WsWriteEndElement(writer
, NULL
);
806 if (FAILED(ret
)) goto cleanup
;
810 /* Generate the bytes of the document */
811 ret
= WsWriteXmlBufferToBytes(writer
, buffer
, NULL
, NULL
, 0, *heap
, (void**)output_xml
, xml_length
, NULL
);
812 if (FAILED(ret
)) goto cleanup
;
815 WSDFreeLinkedMemory(addressing_ns
);
816 WSDFreeLinkedMemory(discovery_ns
);
817 WSDFreeLinkedMemory(envelope_ns
);
819 WSDXMLCleanupElement(header_element
);
821 free_xml_string(actual_envelope_prefix
);
822 free_xml_string(envelope_uri_xmlstr
);
825 WsFreeWriter(writer
);
827 /* Don't free the heap unless the operation has failed */
828 if ((FAILED(ret
)) && (*heap
!= NULL
))
837 static HRESULT
write_and_send_message(IWSDiscoveryPublisherImpl
*impl
, WSD_SOAP_HEADER
*header
, WSDXML_ELEMENT
*body_element
,
838 struct list
*discovered_namespaces
, IWSDUdpAddress
*remote_address
, int max_initial_delay
)
840 static const char xml_header
[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
841 ULONG xml_length
= 0, xml_header_len
= sizeof(xml_header
) - 1;
842 WS_HEAP
*heap
= NULL
;
847 ret
= create_soap_envelope(impl
->xmlContext
, header
, body_element
, &heap
, &xml
, &xml_length
, discovered_namespaces
);
848 if (ret
!= S_OK
) return ret
;
850 /* Prefix the XML header */
851 full_xml
= heap_alloc(xml_length
+ xml_header_len
+ 1);
853 if (full_xml
== NULL
)
856 return E_OUTOFMEMORY
;
859 memcpy(full_xml
, xml_header
, xml_header_len
);
860 memcpy(full_xml
+ xml_header_len
, xml
, xml_length
);
861 full_xml
[xml_length
+ xml_header_len
] = 0;
863 if (remote_address
== NULL
)
865 /* Send the message via UDP multicast */
866 ret
= send_udp_multicast(impl
, full_xml
, xml_length
+ xml_header_len
+ 1, max_initial_delay
) ? S_OK
: E_FAIL
;
870 /* TODO: Send the message via UDP unicast */
871 FIXME("TODO: Send the message via UDP unicast\n");
880 HRESULT
send_hello_message(IWSDiscoveryPublisherImpl
*impl
, LPCWSTR id
, ULONGLONG metadata_ver
, ULONGLONG instance_id
,
881 ULONGLONG msg_num
, LPCWSTR session_id
, const WSD_NAME_LIST
*types_list
, const WSD_URI_LIST
*scopes_list
,
882 const WSD_URI_LIST
*xaddrs_list
, const WSDXML_ELEMENT
*hdr_any
, const WSDXML_ELEMENT
*ref_param_any
,
883 const WSDXML_ELEMENT
*endpoint_ref_any
, const WSDXML_ELEMENT
*any
)
885 WSDXML_ELEMENT
*body_element
= NULL
, *hello_element
, *endpoint_reference_element
;
886 struct list
*discoveredNamespaces
= NULL
;
887 WSDXML_NAME
*body_name
= NULL
;
888 WSD_SOAP_HEADER soapHeader
;
889 WSD_APP_SEQUENCE sequence
;
890 WCHAR message_id
[64];
891 HRESULT ret
= E_OUTOFMEMORY
;
894 sequence
.InstanceId
= instance_id
;
895 sequence
.MessageNumber
= msg_num
;
896 sequence
.SequenceId
= session_id
;
898 if (!create_guid(message_id
)) goto failed
;
900 discoveredNamespaces
= WSDAllocateLinkedMemory(NULL
, sizeof(struct list
));
901 if (!discoveredNamespaces
) goto failed
;
903 list_init(discoveredNamespaces
);
905 populate_soap_header(&soapHeader
, discoveryTo
, actionHello
, message_id
, &sequence
, hdr_any
);
907 ret
= IWSDXMLContext_AddNameToNamespace(impl
->xmlContext
, envelopeNsUri
, bodyString
, &body_name
);
908 if (FAILED(ret
)) goto cleanup
;
910 /* <soap:Body>, <wsd:Hello> */
911 ret
= WSDXMLBuildAnyForSingleElement(body_name
, NULL
, &body_element
);
912 if (FAILED(ret
)) goto cleanup
;
914 ret
= add_child_element(impl
->xmlContext
, body_element
, discoveryNsUri
, helloString
, NULL
, &hello_element
);
915 if (FAILED(ret
)) goto cleanup
;
917 /* <wsa:EndpointReference>, <wsa:Address> */
918 ret
= add_child_element(impl
->xmlContext
, hello_element
, addressingNsUri
, endpointReferenceString
, NULL
,
919 &endpoint_reference_element
);
920 if (FAILED(ret
)) goto cleanup
;
922 ret
= add_child_element(impl
->xmlContext
, endpoint_reference_element
, addressingNsUri
, addressString
, id
, NULL
);
923 if (FAILED(ret
)) goto cleanup
;
925 /* Write any endpoint reference headers */
926 if (endpoint_ref_any
!= NULL
)
928 ret
= duplicate_element(endpoint_reference_element
, endpoint_ref_any
, discoveredNamespaces
);
929 if (FAILED(ret
)) goto cleanup
;
933 if (types_list
!= NULL
)
935 buffer
= WSDAllocateLinkedMemory(hello_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
936 if (buffer
== NULL
) goto failed
;
938 ret
= build_types_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), types_list
, discoveredNamespaces
);
939 if (FAILED(ret
)) goto cleanup
;
941 ret
= add_child_element(impl
->xmlContext
, hello_element
, discoveryNsUri
, typesString
, buffer
, NULL
);
942 if (FAILED(ret
)) goto cleanup
;
946 if (scopes_list
!= NULL
)
948 buffer
= WSDAllocateLinkedMemory(hello_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
949 if (buffer
== NULL
) goto failed
;
951 ret
= build_uri_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), scopes_list
);
952 if (FAILED(ret
)) goto cleanup
;
954 ret
= add_child_element(impl
->xmlContext
, hello_element
, discoveryNsUri
, scopesString
, buffer
, NULL
);
955 if (FAILED(ret
)) goto cleanup
;
959 if (xaddrs_list
!= NULL
)
961 buffer
= WSDAllocateLinkedMemory(hello_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
962 if (buffer
== NULL
) goto failed
;
964 ret
= build_uri_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), xaddrs_list
);
965 if (FAILED(ret
)) goto cleanup
;
967 ret
= add_child_element(impl
->xmlContext
, hello_element
, discoveryNsUri
, xAddrsString
, buffer
, NULL
);
968 if (FAILED(ret
)) goto cleanup
;
971 /* Write any body elements */
974 ret
= duplicate_element(hello_element
, any
, discoveredNamespaces
);
975 if (FAILED(ret
)) goto cleanup
;
978 /* Write and send the message */
979 ret
= write_and_send_message(impl
, &soapHeader
, body_element
, discoveredNamespaces
, NULL
, APP_MAX_DELAY
);
986 WSDFreeLinkedMemory(body_name
);
987 WSDFreeLinkedMemory(body_element
);
988 WSDFreeLinkedMemory(discoveredNamespaces
);