ia64/xen-unstable

view tools/libxen/src/xen_common.c @ 12783:38ad5643aafe

With PERMISSIVE turned on, diagnose missing Enums and Bools, and improve the
diagnosis of missing structure values.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Mon Dec 04 10:20:56 2006 +0000 (2006-12-04)
parents fe15bf5a58ad
children 36e00d04278d
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 #if PERMISSIVE
522 fprintf(stderr,
523 "Expected an Enum from the server, but didn't get one\n");
524 ((int *)value)[slot] = 0;
525 #else
526 server_error(
527 s, "Expected an Enum from the server, but didn't get one");
528 #endif
529 }
530 else
531 {
532 ((int *)value)[slot] =
533 result_type->enum_demarshaller(s, (const char *)string);
534 free(string);
535 }
536 }
537 break;
539 case INT:
540 {
541 xmlChar *string = string_from_value(value_node, "string");
542 if (string == NULL)
543 {
544 server_error(
545 s, "Expected an Int from the server, but didn't get one");
546 }
547 else
548 {
549 ((int64_t *)value)[slot] = (int64_t)atoll((char *)string);
550 free(string);
551 }
552 }
553 break;
555 case FLOAT:
556 {
557 xmlChar *string = string_from_value(value_node, "double");
558 if (string == NULL)
559 {
560 server_error(
561 s, "Expected a Float from the server, but didn't get one");
562 }
563 else
564 {
565 ((double *)value)[slot] = atof((char *)string);
566 free(string);
567 }
568 }
569 break;
571 case BOOL:
572 {
573 xmlChar *string = string_from_value(value_node, "boolean");
574 if (string == NULL)
575 {
576 #if PERMISSIVE
577 fprintf(stderr,
578 "Expected a Bool from the server, but didn't get one\n");
579 ((bool *)value)[slot] = false;
580 #else
581 server_error(
582 s, "Expected a Bool from the server, but didn't get one");
583 #endif
584 }
585 else
586 {
587 ((bool *)value)[slot] = (0 == strcmp((char *)string, "1"));
588 free(string);
589 }
590 }
591 break;
593 case SET:
594 {
595 if (!is_container_node(value_node, "value") ||
596 !is_container_node(value_node->children, "array"))
597 {
598 server_error(s,
599 "Expected Set from the server, but didn't get it");
600 }
601 else
602 {
603 xmlNode *data_node = value_node->children->children;
604 int n = count_children(data_node, "value");
606 const abstract_type *member_type = result_type->child;
607 size_t member_size = size_of_member(member_type);
609 arbitrary_set *set =
610 calloc(1, sizeof(arbitrary_set) + member_size * n);
611 set->size = n;
612 int i = 0;
613 xmlNode *cur = data_node->children;
615 while (cur != NULL)
616 {
617 if (0 == strcmp((char *)cur->name, "value"))
618 {
619 parse_into(s, cur, member_type, set->contents, i);
620 i++;
621 }
622 cur = cur->next;
623 }
625 ((arbitrary_set **)value)[slot] = set;
626 }
627 }
628 break;
630 case MAP:
631 {
632 if (!is_container_node(value_node, "value") ||
633 value_node->children->type != XML_ELEMENT_NODE ||
634 0 != strcmp((char *)value_node->children->name, "struct") ||
635 value_node->children->children == NULL)
636 {
637 server_error(s,
638 "Expected Map from the server, but didn't get it");
639 }
640 else
641 {
642 xmlNode *struct_node = value_node->children;
643 int n = count_children(struct_node, "member");
645 size_t struct_size = result_type->struct_size;
647 const struct struct_member *key_member = result_type->members;
648 const struct struct_member *val_member = result_type->members + 1;
650 arbitrary_map *map =
651 calloc(1, sizeof(arbitrary_map) + struct_size * n);
652 map->size = n;
653 int i = 0;
654 xmlNode *cur = struct_node->children;
656 while (cur != NULL)
657 {
658 if (0 == strcmp((char *)cur->name, "member"))
659 {
660 if (cur->children == NULL || cur->last == cur->children)
661 {
662 server_error(s, "Malformed Map");
663 free(map);
664 return;
665 }
667 xmlChar *name = string_from_name(cur);
668 if (name == NULL)
669 {
670 server_error(s, "Malformed Map");
671 free(map);
672 return;
673 }
675 destring(s, name, key_member->type,
676 ((void *)(map + 1)) +
677 (i * struct_size) +
678 key_member->offset);
679 xmlFree(name);
680 if (!s->ok)
681 {
682 free(map);
683 return;
684 }
686 parse_structmap_value(s, cur, val_member->type,
687 ((void *)(map + 1)) +
688 (i * struct_size) +
689 val_member->offset);
690 if (!s->ok)
691 {
692 free(map);
693 return;
694 }
695 i++;
696 }
697 cur = cur->next;
698 }
700 ((arbitrary_map **)value)[slot] = map;
701 }
702 }
703 break;
705 case STRUCT:
706 {
707 if (!is_container_node(value_node, "value") ||
708 value_node->children->type != XML_ELEMENT_NODE ||
709 0 != strcmp((char *)value_node->children->name, "struct") ||
710 value_node->children->children == NULL)
711 {
712 server_error(s,
713 "Expected Map from the server, but didn't get it");
714 }
715 else
716 {
717 xmlNode *struct_node = value_node->children;
719 void *result = calloc(1, result_type->struct_size);
720 xmlNode *cur = struct_node->children;
722 size_t member_count = result_type->member_count;
724 const struct_member **checklist =
725 malloc(sizeof(const struct_member *) * member_count);
726 int seen_count = 0;
728 while (cur != NULL)
729 {
730 if (0 == strcmp((char *)cur->name, "member"))
731 {
732 if (cur->children == NULL || cur->last == cur->children)
733 {
734 server_error(s, "Malformed Struct");
735 free(result);
736 free(checklist);
737 return;
738 }
740 xmlChar *name = string_from_name(cur);
741 if (name == NULL)
742 {
743 server_error(s, "Malformed Struct");
744 free(result);
745 free(checklist);
746 return;
747 }
749 for (size_t i = 0; i < member_count; i++)
750 {
751 const struct_member *mem = result_type->members + i;
753 if (0 == strcmp((char *)name, mem->key))
754 {
755 parse_structmap_value(s, cur, mem->type,
756 result + mem->offset);
757 checklist[seen_count] = mem;
758 seen_count++;
759 break;
760 }
761 }
763 /* Note that we're skipping unknown fields implicitly.
764 This means that we'll be forward compatible with
765 new servers. */
767 xmlFree(name);
769 if (!s->ok)
770 {
771 free(result);
772 free(checklist);
773 return;
774 }
775 }
776 cur = cur->next;
777 }
779 /* Check that we've filled all fields. */
780 for (size_t i = 0; i < member_count; i++)
781 {
782 const struct_member *mem = result_type->members + i;
783 int j;
785 for (j = 0; j < seen_count; j++)
786 {
787 if (checklist[j] == mem)
788 {
789 break;
790 }
791 }
793 if (j == seen_count)
794 {
795 #if PERMISSIVE
796 fprintf(stderr,
797 "Struct did not contain expected field %s.\n",
798 mem->key);
799 #else
800 server_error_2(s,
801 "Struct did not contain expected field",
802 mem->key);
803 free(result);
804 free(checklist);
805 return;
806 #endif
807 }
808 }
810 free(checklist);
811 ((void **)value)[slot] = result;
812 }
813 }
814 break;
816 case REF:
817 {
818 arbitrary_record_opt *record_opt =
819 calloc(1, sizeof(arbitrary_record_opt));
821 record_opt->is_record = false;
822 parse_into(s, value_node, &abstract_type_string,
823 &(record_opt->u.handle), 0);
825 ((arbitrary_record_opt **)value)[slot] = record_opt;
826 }
827 break;
829 default:
830 assert(false);
831 }
832 }
835 static size_t size_of_member(const abstract_type *type)
836 {
837 switch (type->typename)
838 {
839 case STRING:
840 return sizeof(char *);
842 /*
843 case INT:
844 return sizeof(int64_t);
846 case FLOAT:
847 return sizeof(double);
849 case BOOL:
850 return sizeof(bool);
851 */
852 case ENUM:
853 return sizeof(int);
855 case REF:
856 return sizeof(arbitrary_record_opt *);
858 default:
859 assert(false);
860 }
861 }
864 static void parse_structmap_value(xen_session *s, xmlNode *n,
865 const abstract_type *type, void *value)
866 {
867 xmlNode *cur = n->children;
869 while (cur != NULL)
870 {
871 if (0 == strcmp((char *)cur->name, "value"))
872 {
873 parse_into(s, cur, type, value, 0);
874 return;
875 }
876 cur = cur->next;
877 }
879 server_error(s, "Missing value in Map/Struct");
880 }
883 static void parse_fault(xen_session *session, xmlXPathContextPtr xpathCtx)
884 {
885 xmlXPathObjectPtr xpathObj = xmlXPathCompiledEval(faultPath, xpathCtx);
886 if (xpathObj == NULL)
887 {
888 server_error(session, "Method response is neither result nor fault");
889 return;
890 }
892 if (xpathObj->type != XPATH_NODESET ||
893 xpathObj->nodesetval->nodeNr != 2)
894 {
895 xmlXPathFreeObject(xpathObj);
896 server_error(session, "Method response is neither result nor fault");
897 return;
898 }
900 xmlNode *fault_node0 = xpathObj->nodesetval->nodeTab[0];
901 xmlNode *fault_node1 = xpathObj->nodesetval->nodeTab[1];
903 xmlChar *fault_code_str = string_from_value(fault_node0, "int");
904 if (fault_code_str == NULL)
905 {
906 fault_code_str = string_from_value(fault_node0, "i4");
907 }
908 if (fault_code_str == NULL)
909 {
910 xmlXPathFreeObject(xpathObj);
911 server_error(session, "Fault code is malformed");
912 return;
913 }
915 xmlChar *fault_string_str = string_from_value(fault_node1, "string");
916 if (fault_string_str == NULL)
917 {
918 xmlFree(fault_code_str);
919 xmlXPathFreeObject(xpathObj);
920 server_error(session, "Fault string is malformed");
921 return;
922 }
924 char **strings = malloc(3 * sizeof(char *));
926 strings[0] = xen_strdup_("FAULT");
927 strings[1] = xen_strdup_((char *)fault_code_str);
928 strings[2] = xen_strdup_((char *)fault_string_str);
930 session->ok = false;
931 session->error_description = strings;
932 session->error_description_count = 3;
934 xmlFree(fault_code_str);
935 xmlFree(fault_string_str);
936 xmlXPathFreeObject(xpathObj);
937 }
940 static void parse_failure(xen_session *session, xmlNode *node)
941 {
942 abstract_type error_description_type =
943 { .typename = SET,
944 .child = &abstract_type_string };
945 arbitrary_set *error_descriptions;
947 parse_into(session, node, &error_description_type, &error_descriptions,
948 0);
950 if (session->ok)
951 {
952 session->ok = false;
954 char **c = (char **)error_descriptions->contents;
955 int n = error_descriptions->size;
957 char **strings = malloc(3 * sizeof(char *));
958 for (int i = 0; i < n; i++)
959 {
960 strings[i] = xen_strdup_(c[i]);
961 }
963 session->error_description_count = n;
964 session->error_description = strings;
965 }
967 free(error_descriptions);
968 }
971 /**
972 * Parameters as for xen_call_() above.
973 */
974 static void parse_result(xen_session *session, const char *result,
975 const abstract_type *result_type, void *value)
976 {
977 xmlDocPtr doc =
978 xmlReadMemory(result, strlen(result), "", NULL, XML_PARSE_NONET);
980 if (doc == NULL)
981 {
982 server_error(session, "Couldn't parse the server response");
983 return;
984 }
986 xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
987 if (xpathCtx == NULL)
988 {
989 xmlFreeDoc(doc);
990 server_error(session, "Couldn't create XPath context");
991 return;
992 }
994 xmlXPathObjectPtr xpathObj =
995 xmlXPathCompiledEval(responsePath, xpathCtx);
996 if (xpathObj == NULL)
997 {
998 parse_fault(session, xpathCtx);
1000 xmlXPathFreeContext(xpathCtx);
1001 xmlFreeDoc(doc);
1002 return;
1005 if (xpathObj->type != XPATH_NODESET ||
1006 xpathObj->nodesetval->nodeNr != 2)
1008 parse_fault(session, xpathCtx);
1010 xmlXPathFreeObject(xpathObj);
1011 xmlXPathFreeContext(xpathCtx);
1012 xmlFreeDoc(doc);
1013 return;
1016 xmlNode *node0 = xpathObj->nodesetval->nodeTab[0];
1017 xmlNode *node1 = xpathObj->nodesetval->nodeTab[1];
1019 xmlChar *status_code = string_from_value(node0, "string");
1020 if (status_code == NULL)
1022 xmlXPathFreeObject(xpathObj);
1023 xmlXPathFreeContext(xpathCtx);
1024 xmlFreeDoc(doc);
1025 server_error(session, "Server response does not have a Status");
1026 return;
1029 if (strcmp((char *)status_code, "Success"))
1031 parse_failure(session, node1);
1033 xmlFree(status_code);
1034 xmlXPathFreeObject(xpathObj);
1035 xmlXPathFreeContext(xpathCtx);
1036 xmlFreeDoc(doc);
1037 return;
1040 parse_into(session, node1, result_type, value, 0);
1042 xmlFree(status_code);
1043 xmlXPathFreeObject(xpathObj);
1044 xmlXPathFreeContext(xpathCtx);
1045 xmlFreeDoc(doc);
1049 static char *
1050 make_body(const char *method_name, abstract_value params[], int param_count)
1052 char buf[20];
1054 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
1055 xmlNode *methodCall = xmlNewNode(NULL, BAD_CAST "methodCall");
1056 xmlDocSetRootElement(doc, methodCall);
1058 xmlNewChild(methodCall, NULL, BAD_CAST "methodName",
1059 BAD_CAST method_name);
1061 xmlNode *params_node =
1062 xmlNewChild(methodCall, NULL, BAD_CAST "params", NULL);
1064 for (int p = 0; p < param_count; p++)
1066 abstract_value *v = params + p;
1067 switch (v->type->typename)
1069 case STRING:
1070 add_param(params_node, "string", v->u.string_val);
1071 break;
1073 case INT:
1074 snprintf(buf, sizeof(buf), "%"PRId64, v->u.int_val);
1075 add_param(params_node, "string", buf);
1076 break;
1078 case FLOAT:
1079 snprintf(buf, sizeof(buf), "%lf", v->u.float_val);
1080 add_param(params_node, "double", buf);
1081 break;
1083 case BOOL:
1084 add_param(params_node, "boolean", v->u.bool_val ? "1" : "0");
1085 break;
1087 case VOID:
1088 add_param(params_node, "string", "");
1089 break;
1091 case ENUM:
1092 add_param(params_node, "string",
1093 v->type->enum_marshaller(v->u.enum_val));
1094 break;
1096 case STRUCT:
1098 size_t member_count = v->type->member_count;
1100 xmlNode *struct_node = add_param_struct(params_node);
1102 for (size_t i = 0; i < member_count; i++)
1104 const struct struct_member *mem = v->type->members + i;
1105 const char *key = mem->key;
1106 void *struct_value = v->u.struct_val;
1108 add_struct_value(mem->type, struct_value + mem->offset,
1109 add_struct_member, key, struct_node);
1112 break;
1114 default:
1115 assert(false);
1119 xmlBufferPtr buffer = xmlBufferCreate();
1120 xmlSaveCtxtPtr save_ctxt =
1121 xmlSaveToBuffer(buffer, NULL, XML_SAVE_NO_XHTML);
1123 if (xmlSaveDoc(save_ctxt, doc) == -1)
1125 return NULL;
1128 xmlFreeDoc(doc);
1129 xmlSaveClose(save_ctxt);
1130 xmlChar *content = xmlStrdup(xmlBufferContent(buffer));
1131 xmlBufferFree(buffer);
1132 return (char *)content;
1136 static void
1137 add_struct_value(const struct abstract_type *type, void *value,
1138 void (*adder)(xmlNode *node, const char *key,
1139 const char *type, const char *val),
1140 const char *key, xmlNode *node)
1142 char buf[20];
1144 switch (type->typename)
1146 case REF:
1148 arbitrary_record_opt *val = *(arbitrary_record_opt **)value;
1149 if (val != NULL)
1151 if (val->is_record)
1153 adder(node, key, "string", val->u.record->handle);
1155 else
1157 adder(node, key, "string", val->u.handle);
1161 break;
1163 case STRING:
1165 char *val = *(char **)value;
1166 if (val != NULL)
1168 adder(node, key, "string", val);
1171 break;
1173 case INT:
1175 int64_t val = *(int64_t *)value;
1176 snprintf(buf, sizeof(buf), "%"PRId64, val);
1177 adder(node, key, "string", buf);
1179 break;
1181 case FLOAT:
1183 double val = *(double *)value;
1184 snprintf(buf, sizeof(buf), "%lf", val);
1185 adder(node, key, "double", buf);
1187 break;
1189 case BOOL:
1191 bool val = *(bool *)value;
1192 adder(node, key, "boolean", val ? "1" : "0");
1194 break;
1196 case ENUM:
1198 int val = *(int *)value;
1199 adder(node, key, "string", type->enum_marshaller(val));
1201 break;
1203 case SET:
1205 const struct abstract_type *member_type = type->child;
1206 size_t member_size = size_of_member(member_type);
1207 arbitrary_set *set_val = *(arbitrary_set **)value;
1209 if (set_val != NULL)
1211 xmlNode *data_node = add_struct_array(node, key);
1213 for (size_t i = 0; i < set_val->size; i++)
1215 void *member_value = set_val->contents + (i * member_size);
1216 add_struct_value(member_type, member_value,
1217 add_unnamed_value, NULL, data_node);
1221 break;
1223 case STRUCT:
1224 case MAP:
1226 /* XXX Nested structures aren't supported yet, but
1227 fortunately we don't need them, because we don't have
1228 any "deep create" calls. This will need to be
1229 fixed. We don't need maps either. */
1231 break;
1233 default:
1234 assert(false);
1239 static xmlNode *
1240 add_container(xmlNode *parent, const char *name)
1242 return xmlNewChild(parent, NULL, BAD_CAST name, NULL);
1246 static void
1247 add_param(xmlNode *params_node, const char *type, const char *value)
1249 xmlNode *param_node = add_container(params_node, "param");
1250 add_value(param_node, type, value);
1254 static void
1255 add_value(xmlNode *parent, const char *type, const char *value)
1257 xmlNode *value_node = add_container(parent, "value");
1258 xmlNewChild(value_node, NULL, BAD_CAST type, BAD_CAST value);
1262 static void
1263 add_unnamed_value(xmlNode *parent, const char *name, const char *type,
1264 const char *value)
1266 (void)name;
1267 add_value(parent, type, value);
1271 static xmlNode *
1272 add_param_struct(xmlNode *params_node)
1274 xmlNode *param_node = add_container(params_node, "param");
1275 xmlNode *value_node = add_container(param_node, "value");
1277 return xmlNewChild(value_node, NULL, BAD_CAST "struct", NULL);
1281 static void
1282 add_struct_member(xmlNode *struct_node, const char *name, const char *type,
1283 const char *value)
1285 xmlNode *member_node = add_container(struct_node, "member");
1287 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1289 add_value(member_node, type, value);
1293 static xmlNode *
1294 add_struct_array(xmlNode *struct_node, const char *name)
1296 xmlNode *member_node = add_container(struct_node, "member");
1298 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1300 xmlNode *value_node = add_container(member_node, "value");
1301 xmlNode *array_node = add_container(value_node, "array");
1303 return add_container(array_node, "data");
1308 int xen_enum_lookup_(xen_session *session, const char *str,
1309 const char **lookup_table, int n)
1311 if (str != NULL)
1313 for (int i = 0; i < n; i++)
1315 if (0 == strcmp(str, lookup_table[i]))
1317 return i;
1322 server_error_2(session, "Bad enum string", str);
1323 return 0;
1327 char *
1328 xen_strdup_(const char *in)
1330 char *result = malloc(strlen(in) + 1);
1331 strcpy(result, in);
1332 return result;
1336 const abstract_type abstract_type_string = { .typename = STRING };
1337 const abstract_type abstract_type_int = { .typename = INT };
1338 const abstract_type abstract_type_float = { .typename = FLOAT };
1339 const abstract_type abstract_type_bool = { .typename = BOOL };
1340 const abstract_type abstract_type_datetime = { .typename = DATETIME };
1341 const abstract_type abstract_type_ref = { .typename = REF };
1343 const abstract_type abstract_type_string_set =
1345 .typename = SET,
1346 .child = &abstract_type_string
1347 };
1349 const abstract_type abstract_type_ref_set =
1351 .typename = SET,
1352 .child = &abstract_type_ref
1353 };
1355 static const struct struct_member string_string_members[] =
1358 .type = &abstract_type_string,
1359 .offset = offsetof(xen_string_string_map_contents, key)
1360 },
1362 .type = &abstract_type_string,
1363 .offset = offsetof(xen_string_string_map_contents, val)
1365 };
1366 const abstract_type abstract_type_string_string_map =
1368 .typename = MAP,
1369 .struct_size = sizeof(xen_string_string_map_contents),
1370 .members = string_string_members
1371 };
1373 static struct struct_member int_float_members[] =
1376 .type = &abstract_type_int,
1377 .offset = offsetof(xen_int_float_map_contents, key)
1378 },
1380 .type = &abstract_type_float,
1381 .offset = offsetof(xen_int_float_map_contents, val)
1383 };
1384 const abstract_type abstract_type_int_float_map =
1386 .typename = MAP,
1387 .struct_size = sizeof(xen_int_float_map_contents),
1388 .members = int_float_members
1389 };