ia64/xen-unstable

view tools/libxen/src/xen_common.c @ 12635:fe15bf5a58ad

Allow the C bindings to be more permissive when a structure is missing some
entries. Complaining is just slowing development down when the server and
clients get out of sync.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Tue Nov 28 16:22:22 2006 +0000 (2006-11-28)
parents 62376b480034
children 38ad5643aafe
line source
1 /*
2 * Copyright (c) 2006 XenSource, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
19 #include <assert.h>
20 #include <stdarg.h>
21 #include <stddef.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
26 #include <libxml/parser.h>
27 #include <libxml/tree.h>
28 #include <libxml/xmlsave.h>
29 #include <libxml/xmlstring.h>
30 #include <libxml/xpath.h>
32 #include "xen_common.h"
33 #include "xen_internal.h"
34 #include "xen_int_float_map.h"
35 #include "xen_string_string_map.h"
38 /*
39 * Whether to ignore missing structure entries. This is not something we
40 * want to do, once the API has stabilised, as it indicates that the server is
41 * broken, but at the moment, complaining is just slowing development down.
42 */
43 #define PERMISSIVE 1
46 static xmlXPathCompExprPtr responsePath = NULL;
47 static xmlXPathCompExprPtr faultPath = NULL;
50 typedef struct
51 {
52 size_t size;
53 void *contents[];
54 } arbitrary_map;
57 typedef struct
58 {
59 void *handle;
60 } arbitrary_record;
63 typedef struct
64 {
65 bool is_record;
66 union
67 {
68 char *handle;
69 arbitrary_record *record;
70 } u;
71 } arbitrary_record_opt;
74 static char *
75 make_body(const char *, abstract_value [], int);
77 static void
78 parse_result(xen_session *, const char *, const abstract_type *, void *);
80 static void
81 add_value(xmlNode *, const char *, const char *);
82 static void
83 add_param(xmlNode *, const char *, const char *);
85 static xmlNode *
86 add_param_struct(xmlNode *);
87 static xmlNode *
88 add_struct_array(xmlNode *, const char *);
89 static void
90 add_struct_member(xmlNode *, const char *, const char *, const char *);
91 static void
92 add_unnamed_value(xmlNode *, const char *, const char *, const char *);
94 static void
95 add_struct_value(const struct abstract_type *, void *,
96 void (*)(xmlNode *, const char *, const char *,
97 const char *),
98 const char *, xmlNode *);
100 static void
101 call_raw(xen_session *, const char *, abstract_value [], int,
102 const abstract_type *, void *);
104 static void
105 parse_structmap_value(xen_session *, xmlNode *, const abstract_type *,
106 void *);
108 static size_t size_of_member(const abstract_type *);
111 void
112 xen_init(void)
113 {
114 responsePath =
115 xmlXPathCompile(
116 BAD_CAST(
117 "/methodResponse/params/param/value/struct/member/value"));
118 faultPath =
119 xmlXPathCompile(
120 BAD_CAST("/methodResponse/fault/value/struct/member/value"));
121 }
124 void
125 xen_fini(void)
126 {
127 xmlXPathFreeCompExpr(responsePath);
128 xmlXPathFreeCompExpr(faultPath);
129 responsePath = NULL;
130 faultPath = NULL;
131 }
134 xen_session *
135 xen_session_login_with_password(xen_call_func call_func, void *handle,
136 const char *uname, const char *pwd)
137 {
138 abstract_value params[] =
139 {
140 { .type = &abstract_type_string,
141 .u.string_val = uname },
142 { .type = &abstract_type_string,
143 .u.string_val = pwd }
144 };
146 xen_session *session = malloc(sizeof(xen_session));
147 session->call_func = call_func;
148 session->handle = handle;
149 session->session_id = NULL;
150 session->ok = true;
151 session->error_description = NULL;
152 session->error_description_count = 0;
154 call_raw(session, "session.login_with_password", params, 2,
155 &abstract_type_string, &session->session_id);
157 return session;
158 }
161 void
162 xen_session_logout(xen_session *session)
163 {
164 abstract_value params[] =
165 {
166 };
167 xen_call_(session, "session.logout", params, 0, NULL, NULL);
169 if (session->error_description != NULL)
170 {
171 for (int i = 0; i < session->error_description_count; i++)
172 {
173 free(session->error_description[i]);
174 }
175 free(session->error_description);
176 }
178 free((char *)session->session_id);
179 free(session);
180 }
183 int
184 xen_session_get_this_host(xen_session *session, xen_host *result)
185 {
186 abstract_value params[] =
187 {
188 };
190 xen_call_(session, "session.get_this_host", params, 0,
191 &abstract_type_string, result);
192 return session->ok;
193 }
196 #define X "%02x"
197 #define UUID_FORMAT X X X X "-" X X "-" X X "-" X X "-" X X X X X X
200 bool
201 xen_uuid_string_to_bytes(char *uuid, char **bytes)
202 {
203 unsigned int buf[16];
205 *bytes = NULL;
207 if (strlen(uuid) != 36)
208 return false;
210 if (16 != sscanf(uuid, UUID_FORMAT,
211 buf + 0, buf + 1, buf + 2, buf + 3,
212 buf + 4, buf + 5,
213 buf + 6, buf + 7,
214 buf + 8, buf + 9,
215 buf + 10, buf + 11, buf + 12, buf + 13, buf + 14,
216 buf + 15))
217 {
218 return false;
219 }
221 *bytes = malloc(16);
222 if (*bytes == NULL)
223 return false;
225 for (int i = 0; i < 16; i++) {
226 (*bytes)[i] = (char)buf[i];
227 }
229 return true;
230 }
233 bool
234 xen_uuid_bytes_to_string(char *bytes, char **uuid)
235 {
236 *uuid = malloc(37);
237 if (*uuid == NULL)
238 return false;
240 sprintf(*uuid, UUID_FORMAT,
241 bytes[0], bytes[1], bytes[2], bytes[3],
242 bytes[4], bytes[5],
243 bytes[6], bytes[7],
244 bytes[8], bytes[9],
245 bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]);
247 return true;
248 }
251 #undef UUID_FORMAT
252 #undef X
255 void
256 xen_uuid_free(char *uuid)
257 {
258 free(uuid);
259 }
262 void
263 xen_uuid_bytes_free(char *bytes)
264 {
265 free(bytes);
266 }
269 /**
270 * @param value A pointer to the correct location as per the given
271 * result_type. Will be populated if the call succeeds. In that case, and if
272 * value is a char **, the char * itself must be freed by the caller.
273 */
274 void
275 xen_call_(xen_session *s, const char *method_name,
276 abstract_value params[], int param_count,
277 const abstract_type *result_type, void *value)
278 {
279 if (!s->ok)
280 {
281 return;
282 }
284 abstract_value *full_params =
285 malloc(sizeof(abstract_value) * (param_count + 1));
287 full_params[0].type = &abstract_type_string;
288 full_params[0].u.string_val = s->session_id;
290 memcpy(full_params + 1, params, param_count * sizeof(abstract_value));
292 call_raw(s, method_name, full_params, param_count + 1, result_type,
293 value);
295 free(full_params);
296 }
299 static bool
300 bufferAdd(const void *data, size_t len, void *buffer)
301 {
302 return 0 == xmlBufferAdd((xmlBufferPtr)buffer, data, len);
303 }
306 static void
307 call_raw(xen_session *s, const char *method_name,
308 abstract_value params[], int param_count,
309 const abstract_type *result_type, void *value)
310 {
311 xmlBufferPtr buffer = xmlBufferCreate();
312 char *body = make_body(method_name, params, param_count);
313 int error_code =
314 s->call_func(body, strlen(body), s->handle, buffer, &bufferAdd);
315 free(body);
316 if (error_code)
317 {
318 char **strings = malloc(2 * sizeof(char *));
320 strings[0] = xen_strdup_("TRANSPORT_FAULT");
321 strings[1] = malloc(20);
322 snprintf(strings[1], 20, "%d", error_code);
324 s->ok = false;
325 s->error_description = strings;
326 s->error_description_count = 2;
327 }
328 else
329 {
330 parse_result(s, (char *)xmlBufferContent(buffer), result_type, value);
331 }
332 xmlBufferFree(buffer);
333 }
336 static void server_error(xen_session *session, const char *error_string)
337 {
338 if (!session->ok)
339 {
340 /* Don't wipe out the earlier error message with this one. */
341 return;
342 }
344 char **strings = malloc(2 * sizeof(char *));
346 strings[0] = xen_strdup_("SERVER_FAULT");
347 strings[1] = xen_strdup_(error_string);
349 session->ok = false;
350 session->error_description = strings;
351 session->error_description_count = 2;
352 }
355 static void server_error_2(xen_session *session, const char *error_string,
356 const char *param)
357 {
358 if (!session->ok)
359 {
360 /* Don't wipe out the earlier error message with this one. */
361 return;
362 }
364 char **strings = malloc(3 * sizeof(char *));
366 strings[0] = xen_strdup_("SERVER_FAULT_2");
367 strings[1] = xen_strdup_(error_string);
368 strings[2] = xen_strdup_(param);
370 session->ok = false;
371 session->error_description = strings;
372 session->error_description_count = 3;
373 }
376 static bool is_container_node(xmlNode *n, char *type)
377 {
378 return
379 n->type == XML_ELEMENT_NODE &&
380 0 == strcmp((char *)n->name, type) &&
381 n->children != NULL &&
382 n->children == n->last &&
383 n->children->type == XML_ELEMENT_NODE;
384 }
387 /**
388 * @return The contents of the given value, or NULL if this is not a node with
389 * the given type. If not NULL, the result must be freed with xmlFree().
390 */
391 static xmlChar *string_from_value(xmlNode *n, char *type)
392 {
393 return
394 is_container_node(n, "value") &&
395 0 == strcmp((char *)n->children->name, type) ?
396 (n->children->children == NULL ?
397 xmlStrdup(BAD_CAST("")) :
398 xmlNodeGetContent(n->children->children)) :
399 NULL;
400 }
403 /**
404 * Find the name node that is a child of the given one, and return its
405 * contents, or NULL if this has no such node. If not NULL, the result must
406 * be freed with xmlFree().
407 */
408 static xmlChar *string_from_name(xmlNode *n)
409 {
410 xmlNode *cur = n->children;
412 while (cur != NULL)
413 {
414 if (0 == strcmp((char *)cur->name, "name"))
415 {
416 return xmlNodeGetContent(cur);
417 }
418 cur = cur->next;
419 }
421 return NULL;
422 }
425 static int count_children(xmlNode *n, const char *name)
426 {
427 int result = 0;
428 xmlNode *cur = n->children;
430 while (cur != NULL)
431 {
432 if (0 == strcmp((char *)cur->name, name))
433 {
434 result++;
435 }
436 cur = cur->next;
437 }
439 return result;
440 }
443 static void destring(xen_session *s, xmlChar *name, const abstract_type *type,
444 void *value)
445 {
446 switch (type->typename)
447 {
448 case STRING:
449 *((char **)value) = xen_strdup_((const char *)name);
450 break;
452 case INT:
453 *((int64_t *)value) = atoll((const char *)name);
454 break;
456 case FLOAT:
457 *((double *)value) = atof((const char *)name);
458 break;
460 default:
461 server_error(s, "Invalid Map key type");
462 }
463 }
466 /**
467 * result_type : STRING => value : char **, the char * is yours.
468 * result_type : ENUM => value : int *
469 * result_type : INT => value : int64_t *
470 * result_type : FLOAT => value : double *
471 * result_type : BOOL => value : bool *
472 * result_type : SET => value : arbitrary_set **, the set is yours.
473 * result_type : MAP => value : arbitrary_map **, the map is yours.
474 * result_type : OPT => value : arbitrary_record_opt **,
475 * the record is yours, the handle is filled.
476 * result_type : STRUCT => value : void **, the void * is yours.
477 */
478 static void parse_into(xen_session *s, xmlNode *value_node,
479 const abstract_type *result_type, void *value,
480 int slot)
481 {
482 if (result_type == NULL)
483 {
484 xmlChar *string = string_from_value(value_node, "string");
485 if (string == NULL || strcmp((char *)string, ""))
486 {
487 server_error(s,
488 "Expected Void from the server, but didn't get it");
489 }
490 else
491 {
492 free(string);
493 }
495 return;
496 }
498 switch (result_type->typename)
499 {
500 case STRING:
501 {
502 xmlChar *string = string_from_value(value_node, "string");
503 if (string == NULL)
504 {
505 server_error(
506 s, "Expected a String from the server, but didn't get one");
507 }
508 else
509 {
510 ((char **)value)[slot] = xen_strdup_((const char *)string);
511 free(string);
512 }
513 }
514 break;
516 case ENUM:
517 {
518 xmlChar *string = string_from_value(value_node, "string");
519 if (string == NULL)
520 {
521 server_error(
522 s, "Expected an Enum from the server, but didn't get one");
523 }
524 else
525 {
526 ((int *)value)[slot] =
527 result_type->enum_demarshaller(s, (const char *)string);
528 free(string);
529 }
530 }
531 break;
533 case INT:
534 {
535 xmlChar *string = string_from_value(value_node, "string");
536 if (string == NULL)
537 {
538 server_error(
539 s, "Expected an Int from the server, but didn't get one");
540 }
541 else
542 {
543 ((int64_t *)value)[slot] = (int64_t)atoll((char *)string);
544 free(string);
545 }
546 }
547 break;
549 case FLOAT:
550 {
551 xmlChar *string = string_from_value(value_node, "double");
552 if (string == NULL)
553 {
554 server_error(
555 s, "Expected a Float from the server, but didn't get one");
556 }
557 else
558 {
559 ((double *)value)[slot] = atof((char *)string);
560 free(string);
561 }
562 }
563 break;
565 case BOOL:
566 {
567 xmlChar *string = string_from_value(value_node, "boolean");
568 if (string == NULL)
569 {
570 server_error(
571 s, "Expected a Bool from the server, but didn't get one");
572 }
573 else
574 {
575 ((bool *)value)[slot] = (0 == strcmp((char *)string, "1"));
576 free(string);
577 }
578 }
579 break;
581 case SET:
582 {
583 if (!is_container_node(value_node, "value") ||
584 !is_container_node(value_node->children, "array"))
585 {
586 server_error(s,
587 "Expected Set from the server, but didn't get it");
588 }
589 else
590 {
591 xmlNode *data_node = value_node->children->children;
592 int n = count_children(data_node, "value");
594 const abstract_type *member_type = result_type->child;
595 size_t member_size = size_of_member(member_type);
597 arbitrary_set *set =
598 calloc(1, sizeof(arbitrary_set) + member_size * n);
599 set->size = n;
600 int i = 0;
601 xmlNode *cur = data_node->children;
603 while (cur != NULL)
604 {
605 if (0 == strcmp((char *)cur->name, "value"))
606 {
607 parse_into(s, cur, member_type, set->contents, i);
608 i++;
609 }
610 cur = cur->next;
611 }
613 ((arbitrary_set **)value)[slot] = set;
614 }
615 }
616 break;
618 case MAP:
619 {
620 if (!is_container_node(value_node, "value") ||
621 value_node->children->type != XML_ELEMENT_NODE ||
622 0 != strcmp((char *)value_node->children->name, "struct") ||
623 value_node->children->children == NULL)
624 {
625 server_error(s,
626 "Expected Map from the server, but didn't get it");
627 }
628 else
629 {
630 xmlNode *struct_node = value_node->children;
631 int n = count_children(struct_node, "member");
633 size_t struct_size = result_type->struct_size;
635 const struct struct_member *key_member = result_type->members;
636 const struct struct_member *val_member = result_type->members + 1;
638 arbitrary_map *map =
639 calloc(1, sizeof(arbitrary_map) + struct_size * n);
640 map->size = n;
641 int i = 0;
642 xmlNode *cur = struct_node->children;
644 while (cur != NULL)
645 {
646 if (0 == strcmp((char *)cur->name, "member"))
647 {
648 if (cur->children == NULL || cur->last == cur->children)
649 {
650 server_error(s, "Malformed Map");
651 free(map);
652 return;
653 }
655 xmlChar *name = string_from_name(cur);
656 if (name == NULL)
657 {
658 server_error(s, "Malformed Map");
659 free(map);
660 return;
661 }
663 destring(s, name, key_member->type,
664 ((void *)(map + 1)) +
665 (i * struct_size) +
666 key_member->offset);
667 xmlFree(name);
668 if (!s->ok)
669 {
670 free(map);
671 return;
672 }
674 parse_structmap_value(s, cur, val_member->type,
675 ((void *)(map + 1)) +
676 (i * struct_size) +
677 val_member->offset);
678 if (!s->ok)
679 {
680 free(map);
681 return;
682 }
683 i++;
684 }
685 cur = cur->next;
686 }
688 ((arbitrary_map **)value)[slot] = map;
689 }
690 }
691 break;
693 case STRUCT:
694 {
695 if (!is_container_node(value_node, "value") ||
696 value_node->children->type != XML_ELEMENT_NODE ||
697 0 != strcmp((char *)value_node->children->name, "struct") ||
698 value_node->children->children == NULL)
699 {
700 server_error(s,
701 "Expected Map from the server, but didn't get it");
702 }
703 else
704 {
705 xmlNode *struct_node = value_node->children;
707 void *result = calloc(1, result_type->struct_size);
708 xmlNode *cur = struct_node->children;
710 size_t member_count = result_type->member_count;
712 const struct_member **checklist =
713 malloc(sizeof(const struct_member *) * member_count);
714 int seen_count = 0;
716 while (cur != NULL)
717 {
718 if (0 == strcmp((char *)cur->name, "member"))
719 {
720 if (cur->children == NULL || cur->last == cur->children)
721 {
722 server_error(s, "Malformed Struct");
723 free(result);
724 free(checklist);
725 return;
726 }
728 xmlChar *name = string_from_name(cur);
729 if (name == NULL)
730 {
731 server_error(s, "Malformed Struct");
732 free(result);
733 free(checklist);
734 return;
735 }
737 for (size_t i = 0; i < member_count; i++)
738 {
739 const struct_member *mem = result_type->members + i;
741 if (0 == strcmp((char *)name, mem->key))
742 {
743 parse_structmap_value(s, cur, mem->type,
744 result + mem->offset);
745 checklist[seen_count] = mem;
746 seen_count++;
747 break;
748 }
749 }
751 /* Note that we're skipping unknown fields implicitly.
752 This means that we'll be forward compatible with
753 new servers. */
755 xmlFree(name);
757 if (!s->ok)
758 {
759 free(result);
760 free(checklist);
761 return;
762 }
763 }
764 cur = cur->next;
765 }
767 #if !PERMISSIVE
768 /* Check that we've filled all fields. */
769 for (size_t i = 0; i < member_count; i++)
770 {
771 const struct_member *mem = result_type->members + i;
772 int j;
774 for (j = 0; j < seen_count; j++)
775 {
776 if (checklist[j] == mem)
777 {
778 break;
779 }
780 }
782 if (j == seen_count)
783 {
784 server_error_2(s,
785 "Struct did not contain expected field",
786 mem->key);
787 free(result);
788 free(checklist);
789 return;
790 }
791 }
792 #endif
794 free(checklist);
795 ((void **)value)[slot] = result;
796 }
797 }
798 break;
800 case REF:
801 {
802 arbitrary_record_opt *record_opt =
803 calloc(1, sizeof(arbitrary_record_opt));
805 record_opt->is_record = false;
806 parse_into(s, value_node, &abstract_type_string,
807 &(record_opt->u.handle), 0);
809 ((arbitrary_record_opt **)value)[slot] = record_opt;
810 }
811 break;
813 default:
814 assert(false);
815 }
816 }
819 static size_t size_of_member(const abstract_type *type)
820 {
821 switch (type->typename)
822 {
823 case STRING:
824 return sizeof(char *);
826 /*
827 case INT:
828 return sizeof(int64_t);
830 case FLOAT:
831 return sizeof(double);
833 case BOOL:
834 return sizeof(bool);
835 */
836 case ENUM:
837 return sizeof(int);
839 case REF:
840 return sizeof(arbitrary_record_opt *);
842 default:
843 assert(false);
844 }
845 }
848 static void parse_structmap_value(xen_session *s, xmlNode *n,
849 const abstract_type *type, void *value)
850 {
851 xmlNode *cur = n->children;
853 while (cur != NULL)
854 {
855 if (0 == strcmp((char *)cur->name, "value"))
856 {
857 parse_into(s, cur, type, value, 0);
858 return;
859 }
860 cur = cur->next;
861 }
863 server_error(s, "Missing value in Map/Struct");
864 }
867 static void parse_fault(xen_session *session, xmlXPathContextPtr xpathCtx)
868 {
869 xmlXPathObjectPtr xpathObj = xmlXPathCompiledEval(faultPath, xpathCtx);
870 if (xpathObj == NULL)
871 {
872 server_error(session, "Method response is neither result nor fault");
873 return;
874 }
876 if (xpathObj->type != XPATH_NODESET ||
877 xpathObj->nodesetval->nodeNr != 2)
878 {
879 xmlXPathFreeObject(xpathObj);
880 server_error(session, "Method response is neither result nor fault");
881 return;
882 }
884 xmlNode *fault_node0 = xpathObj->nodesetval->nodeTab[0];
885 xmlNode *fault_node1 = xpathObj->nodesetval->nodeTab[1];
887 xmlChar *fault_code_str = string_from_value(fault_node0, "int");
888 if (fault_code_str == NULL)
889 {
890 fault_code_str = string_from_value(fault_node0, "i4");
891 }
892 if (fault_code_str == NULL)
893 {
894 xmlXPathFreeObject(xpathObj);
895 server_error(session, "Fault code is malformed");
896 return;
897 }
899 xmlChar *fault_string_str = string_from_value(fault_node1, "string");
900 if (fault_string_str == NULL)
901 {
902 xmlFree(fault_code_str);
903 xmlXPathFreeObject(xpathObj);
904 server_error(session, "Fault string is malformed");
905 return;
906 }
908 char **strings = malloc(3 * sizeof(char *));
910 strings[0] = xen_strdup_("FAULT");
911 strings[1] = xen_strdup_((char *)fault_code_str);
912 strings[2] = xen_strdup_((char *)fault_string_str);
914 session->ok = false;
915 session->error_description = strings;
916 session->error_description_count = 3;
918 xmlFree(fault_code_str);
919 xmlFree(fault_string_str);
920 xmlXPathFreeObject(xpathObj);
921 }
924 static void parse_failure(xen_session *session, xmlNode *node)
925 {
926 abstract_type error_description_type =
927 { .typename = SET,
928 .child = &abstract_type_string };
929 arbitrary_set *error_descriptions;
931 parse_into(session, node, &error_description_type, &error_descriptions,
932 0);
934 if (session->ok)
935 {
936 session->ok = false;
938 char **c = (char **)error_descriptions->contents;
939 int n = error_descriptions->size;
941 char **strings = malloc(3 * sizeof(char *));
942 for (int i = 0; i < n; i++)
943 {
944 strings[i] = xen_strdup_(c[i]);
945 }
947 session->error_description_count = n;
948 session->error_description = strings;
949 }
951 free(error_descriptions);
952 }
955 /**
956 * Parameters as for xen_call_() above.
957 */
958 static void parse_result(xen_session *session, const char *result,
959 const abstract_type *result_type, void *value)
960 {
961 xmlDocPtr doc =
962 xmlReadMemory(result, strlen(result), "", NULL, XML_PARSE_NONET);
964 if (doc == NULL)
965 {
966 server_error(session, "Couldn't parse the server response");
967 return;
968 }
970 xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
971 if (xpathCtx == NULL)
972 {
973 xmlFreeDoc(doc);
974 server_error(session, "Couldn't create XPath context");
975 return;
976 }
978 xmlXPathObjectPtr xpathObj =
979 xmlXPathCompiledEval(responsePath, xpathCtx);
980 if (xpathObj == NULL)
981 {
982 parse_fault(session, xpathCtx);
984 xmlXPathFreeContext(xpathCtx);
985 xmlFreeDoc(doc);
986 return;
987 }
989 if (xpathObj->type != XPATH_NODESET ||
990 xpathObj->nodesetval->nodeNr != 2)
991 {
992 parse_fault(session, xpathCtx);
994 xmlXPathFreeObject(xpathObj);
995 xmlXPathFreeContext(xpathCtx);
996 xmlFreeDoc(doc);
997 return;
998 }
1000 xmlNode *node0 = xpathObj->nodesetval->nodeTab[0];
1001 xmlNode *node1 = xpathObj->nodesetval->nodeTab[1];
1003 xmlChar *status_code = string_from_value(node0, "string");
1004 if (status_code == NULL)
1006 xmlXPathFreeObject(xpathObj);
1007 xmlXPathFreeContext(xpathCtx);
1008 xmlFreeDoc(doc);
1009 server_error(session, "Server response does not have a Status");
1010 return;
1013 if (strcmp((char *)status_code, "Success"))
1015 parse_failure(session, node1);
1017 xmlFree(status_code);
1018 xmlXPathFreeObject(xpathObj);
1019 xmlXPathFreeContext(xpathCtx);
1020 xmlFreeDoc(doc);
1021 return;
1024 parse_into(session, node1, result_type, value, 0);
1026 xmlFree(status_code);
1027 xmlXPathFreeObject(xpathObj);
1028 xmlXPathFreeContext(xpathCtx);
1029 xmlFreeDoc(doc);
1033 static char *
1034 make_body(const char *method_name, abstract_value params[], int param_count)
1036 char buf[20];
1038 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
1039 xmlNode *methodCall = xmlNewNode(NULL, BAD_CAST "methodCall");
1040 xmlDocSetRootElement(doc, methodCall);
1042 xmlNewChild(methodCall, NULL, BAD_CAST "methodName",
1043 BAD_CAST method_name);
1045 xmlNode *params_node =
1046 xmlNewChild(methodCall, NULL, BAD_CAST "params", NULL);
1048 for (int p = 0; p < param_count; p++)
1050 abstract_value *v = params + p;
1051 switch (v->type->typename)
1053 case STRING:
1054 add_param(params_node, "string", v->u.string_val);
1055 break;
1057 case INT:
1058 snprintf(buf, sizeof(buf), "%"PRId64, v->u.int_val);
1059 add_param(params_node, "string", buf);
1060 break;
1062 case FLOAT:
1063 snprintf(buf, sizeof(buf), "%lf", v->u.float_val);
1064 add_param(params_node, "double", buf);
1065 break;
1067 case BOOL:
1068 add_param(params_node, "boolean", v->u.bool_val ? "1" : "0");
1069 break;
1071 case VOID:
1072 add_param(params_node, "string", "");
1073 break;
1075 case ENUM:
1076 add_param(params_node, "string",
1077 v->type->enum_marshaller(v->u.enum_val));
1078 break;
1080 case STRUCT:
1082 size_t member_count = v->type->member_count;
1084 xmlNode *struct_node = add_param_struct(params_node);
1086 for (size_t i = 0; i < member_count; i++)
1088 const struct struct_member *mem = v->type->members + i;
1089 const char *key = mem->key;
1090 void *struct_value = v->u.struct_val;
1092 add_struct_value(mem->type, struct_value + mem->offset,
1093 add_struct_member, key, struct_node);
1096 break;
1098 default:
1099 assert(false);
1103 xmlBufferPtr buffer = xmlBufferCreate();
1104 xmlSaveCtxtPtr save_ctxt =
1105 xmlSaveToBuffer(buffer, NULL, XML_SAVE_NO_XHTML);
1107 if (xmlSaveDoc(save_ctxt, doc) == -1)
1109 return NULL;
1112 xmlFreeDoc(doc);
1113 xmlSaveClose(save_ctxt);
1114 xmlChar *content = xmlStrdup(xmlBufferContent(buffer));
1115 xmlBufferFree(buffer);
1116 return (char *)content;
1120 static void
1121 add_struct_value(const struct abstract_type *type, void *value,
1122 void (*adder)(xmlNode *node, const char *key,
1123 const char *type, const char *val),
1124 const char *key, xmlNode *node)
1126 char buf[20];
1128 switch (type->typename)
1130 case REF:
1132 arbitrary_record_opt *val = *(arbitrary_record_opt **)value;
1133 if (val != NULL)
1135 if (val->is_record)
1137 adder(node, key, "string", val->u.record->handle);
1139 else
1141 adder(node, key, "string", val->u.handle);
1145 break;
1147 case STRING:
1149 char *val = *(char **)value;
1150 if (val != NULL)
1152 adder(node, key, "string", val);
1155 break;
1157 case INT:
1159 int64_t val = *(int64_t *)value;
1160 snprintf(buf, sizeof(buf), "%"PRId64, val);
1161 adder(node, key, "string", buf);
1163 break;
1165 case FLOAT:
1167 double val = *(double *)value;
1168 snprintf(buf, sizeof(buf), "%lf", val);
1169 adder(node, key, "double", buf);
1171 break;
1173 case BOOL:
1175 bool val = *(bool *)value;
1176 adder(node, key, "boolean", val ? "1" : "0");
1178 break;
1180 case ENUM:
1182 int val = *(int *)value;
1183 adder(node, key, "string", type->enum_marshaller(val));
1185 break;
1187 case SET:
1189 const struct abstract_type *member_type = type->child;
1190 size_t member_size = size_of_member(member_type);
1191 arbitrary_set *set_val = *(arbitrary_set **)value;
1193 if (set_val != NULL)
1195 xmlNode *data_node = add_struct_array(node, key);
1197 for (size_t i = 0; i < set_val->size; i++)
1199 void *member_value = set_val->contents + (i * member_size);
1200 add_struct_value(member_type, member_value,
1201 add_unnamed_value, NULL, data_node);
1205 break;
1207 case STRUCT:
1208 case MAP:
1210 /* XXX Nested structures aren't supported yet, but
1211 fortunately we don't need them, because we don't have
1212 any "deep create" calls. This will need to be
1213 fixed. We don't need maps either. */
1215 break;
1217 default:
1218 assert(false);
1223 static xmlNode *
1224 add_container(xmlNode *parent, const char *name)
1226 return xmlNewChild(parent, NULL, BAD_CAST name, NULL);
1230 static void
1231 add_param(xmlNode *params_node, const char *type, const char *value)
1233 xmlNode *param_node = add_container(params_node, "param");
1234 add_value(param_node, type, value);
1238 static void
1239 add_value(xmlNode *parent, const char *type, const char *value)
1241 xmlNode *value_node = add_container(parent, "value");
1242 xmlNewChild(value_node, NULL, BAD_CAST type, BAD_CAST value);
1246 static void
1247 add_unnamed_value(xmlNode *parent, const char *name, const char *type,
1248 const char *value)
1250 (void)name;
1251 add_value(parent, type, value);
1255 static xmlNode *
1256 add_param_struct(xmlNode *params_node)
1258 xmlNode *param_node = add_container(params_node, "param");
1259 xmlNode *value_node = add_container(param_node, "value");
1261 return xmlNewChild(value_node, NULL, BAD_CAST "struct", NULL);
1265 static void
1266 add_struct_member(xmlNode *struct_node, const char *name, const char *type,
1267 const char *value)
1269 xmlNode *member_node = add_container(struct_node, "member");
1271 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1273 add_value(member_node, type, value);
1277 static xmlNode *
1278 add_struct_array(xmlNode *struct_node, const char *name)
1280 xmlNode *member_node = add_container(struct_node, "member");
1282 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1284 xmlNode *value_node = add_container(member_node, "value");
1285 xmlNode *array_node = add_container(value_node, "array");
1287 return add_container(array_node, "data");
1292 int xen_enum_lookup_(xen_session *session, const char *str,
1293 const char **lookup_table, int n)
1295 if (str != NULL)
1297 for (int i = 0; i < n; i++)
1299 if (0 == strcmp(str, lookup_table[i]))
1301 return i;
1306 server_error_2(session, "Bad enum string", str);
1307 return 0;
1311 char *
1312 xen_strdup_(const char *in)
1314 char *result = malloc(strlen(in) + 1);
1315 strcpy(result, in);
1316 return result;
1320 const abstract_type abstract_type_string = { .typename = STRING };
1321 const abstract_type abstract_type_int = { .typename = INT };
1322 const abstract_type abstract_type_float = { .typename = FLOAT };
1323 const abstract_type abstract_type_bool = { .typename = BOOL };
1324 const abstract_type abstract_type_datetime = { .typename = DATETIME };
1325 const abstract_type abstract_type_ref = { .typename = REF };
1327 const abstract_type abstract_type_string_set =
1329 .typename = SET,
1330 .child = &abstract_type_string
1331 };
1333 const abstract_type abstract_type_ref_set =
1335 .typename = SET,
1336 .child = &abstract_type_ref
1337 };
1339 static const struct struct_member string_string_members[] =
1342 .type = &abstract_type_string,
1343 .offset = offsetof(xen_string_string_map_contents, key)
1344 },
1346 .type = &abstract_type_string,
1347 .offset = offsetof(xen_string_string_map_contents, val)
1349 };
1350 const abstract_type abstract_type_string_string_map =
1352 .typename = MAP,
1353 .struct_size = sizeof(xen_string_string_map_contents),
1354 .members = string_string_members
1355 };
1357 static struct struct_member int_float_members[] =
1360 .type = &abstract_type_int,
1361 .offset = offsetof(xen_int_float_map_contents, key)
1362 },
1364 .type = &abstract_type_float,
1365 .offset = offsetof(xen_int_float_map_contents, val)
1367 };
1368 const abstract_type abstract_type_int_float_map =
1370 .typename = MAP,
1371 .struct_size = sizeof(xen_int_float_map_contents),
1372 .members = int_float_members
1373 };