ia64/xen-unstable

view tools/libxen/src/xen_common.c @ 14051:2414007d92ba

Fix allocation of the error_description fields.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Wed Feb 21 00:04:06 2007 +0000 (2007-02-21)
parents 0fb5df09de94
children 6ff2a1286484
line source
1 /*
2 * Copyright (c) 2006-2007 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 xmlNode *
90 add_nested_struct(xmlNode *, const char *);
91 static void
92 add_struct_member(xmlNode *, const char *, const char *, const char *);
93 static void
94 add_unnamed_value(xmlNode *, const char *, const char *, const char *);
96 static void
97 add_struct_value(const struct abstract_type *, void *,
98 void (*)(xmlNode *, const char *, const char *,
99 const char *),
100 const char *, xmlNode *);
102 static void
103 call_raw(xen_session *, const char *, abstract_value [], int,
104 const abstract_type *, void *);
106 static void
107 parse_structmap_value(xen_session *, xmlNode *, const abstract_type *,
108 void *);
110 static size_t size_of_member(const abstract_type *);
112 static const char *
113 get_val_as_string(const struct abstract_type *, void *, char *);
116 void
117 xen_init(void)
118 {
119 responsePath =
120 xmlXPathCompile(
121 BAD_CAST(
122 "/methodResponse/params/param/value/struct/member/value"));
123 faultPath =
124 xmlXPathCompile(
125 BAD_CAST("/methodResponse/fault/value/struct/member/value"));
126 }
129 void
130 xen_fini(void)
131 {
132 xmlXPathFreeCompExpr(responsePath);
133 xmlXPathFreeCompExpr(faultPath);
134 responsePath = NULL;
135 faultPath = NULL;
136 }
139 xen_session *
140 xen_session_login_with_password(xen_call_func call_func, void *handle,
141 const char *uname, const char *pwd)
142 {
143 abstract_value params[] =
144 {
145 { .type = &abstract_type_string,
146 .u.string_val = uname },
147 { .type = &abstract_type_string,
148 .u.string_val = pwd }
149 };
151 xen_session *session = malloc(sizeof(xen_session));
152 session->call_func = call_func;
153 session->handle = handle;
154 session->session_id = NULL;
155 session->ok = true;
156 session->error_description = NULL;
157 session->error_description_count = 0;
159 call_raw(session, "session.login_with_password", params, 2,
160 &abstract_type_string, &session->session_id);
162 return session;
163 }
166 void
167 xen_session_logout(xen_session *session)
168 {
169 abstract_value params[] =
170 {
171 };
172 xen_call_(session, "session.logout", params, 0, NULL, NULL);
174 if (session->error_description != NULL)
175 {
176 for (int i = 0; i < session->error_description_count; i++)
177 {
178 free(session->error_description[i]);
179 }
180 free(session->error_description);
181 }
183 free((char *)session->session_id);
184 free(session);
185 }
188 int
189 xen_session_get_this_host(xen_session *session, xen_host *result)
190 {
191 abstract_value params[] =
192 {
193 };
195 xen_call_(session, "session.get_this_host", params, 0,
196 &abstract_type_string, result);
197 return session->ok;
198 }
201 #define X "%02x"
202 #define UUID_FORMAT X X X X "-" X X "-" X X "-" X X "-" X X X X X X
205 bool
206 xen_uuid_string_to_bytes(char *uuid, char **bytes)
207 {
208 unsigned int buf[16];
210 *bytes = NULL;
212 if (strlen(uuid) != 36)
213 return false;
215 if (16 != sscanf(uuid, UUID_FORMAT,
216 buf + 0, buf + 1, buf + 2, buf + 3,
217 buf + 4, buf + 5,
218 buf + 6, buf + 7,
219 buf + 8, buf + 9,
220 buf + 10, buf + 11, buf + 12, buf + 13, buf + 14,
221 buf + 15))
222 {
223 return false;
224 }
226 *bytes = malloc(16);
227 if (*bytes == NULL)
228 return false;
230 for (int i = 0; i < 16; i++) {
231 (*bytes)[i] = (char)buf[i];
232 }
234 return true;
235 }
238 bool
239 xen_uuid_bytes_to_string(char *bytes, char **uuid)
240 {
241 *uuid = malloc(37);
242 if (*uuid == NULL)
243 return false;
245 sprintf(*uuid, UUID_FORMAT,
246 bytes[0], bytes[1], bytes[2], bytes[3],
247 bytes[4], bytes[5],
248 bytes[6], bytes[7],
249 bytes[8], bytes[9],
250 bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]);
252 return true;
253 }
256 #undef UUID_FORMAT
257 #undef X
260 void
261 xen_uuid_free(char *uuid)
262 {
263 free(uuid);
264 }
267 void
268 xen_uuid_bytes_free(char *bytes)
269 {
270 free(bytes);
271 }
274 /**
275 * @param value A pointer to the correct location as per the given
276 * result_type. Will be populated if the call succeeds. In that case, and if
277 * value is a char **, the char * itself must be freed by the caller.
278 */
279 void
280 xen_call_(xen_session *s, const char *method_name,
281 abstract_value params[], int param_count,
282 const abstract_type *result_type, void *value)
283 {
284 if (!s->ok)
285 {
286 return;
287 }
289 abstract_value *full_params =
290 malloc(sizeof(abstract_value) * (param_count + 1));
292 full_params[0].type = &abstract_type_string;
293 full_params[0].u.string_val = s->session_id;
295 memcpy(full_params + 1, params, param_count * sizeof(abstract_value));
297 call_raw(s, method_name, full_params, param_count + 1, result_type,
298 value);
300 free(full_params);
301 }
304 static bool
305 bufferAdd(const void *data, size_t len, void *buffer)
306 {
307 return 0 == xmlBufferAdd((xmlBufferPtr)buffer, data, len);
308 }
311 static void
312 call_raw(xen_session *s, const char *method_name,
313 abstract_value params[], int param_count,
314 const abstract_type *result_type, void *value)
315 {
316 xmlBufferPtr buffer = xmlBufferCreate();
317 char *body = make_body(method_name, params, param_count);
318 int error_code =
319 s->call_func(body, strlen(body), s->handle, buffer, &bufferAdd);
320 free(body);
321 if (error_code)
322 {
323 char **strings = malloc(2 * sizeof(char *));
325 strings[0] = xen_strdup_("TRANSPORT_FAULT");
326 strings[1] = malloc(20);
327 snprintf(strings[1], 20, "%d", error_code);
329 s->ok = false;
330 s->error_description = strings;
331 s->error_description_count = 2;
332 }
333 else
334 {
335 parse_result(s, (char *)xmlBufferContent(buffer), result_type, value);
336 }
337 xmlBufferFree(buffer);
338 }
341 static void server_error(xen_session *session, const char *error_string)
342 {
343 if (!session->ok)
344 {
345 /* Don't wipe out the earlier error message with this one. */
346 return;
347 }
349 char **strings = malloc(2 * sizeof(char *));
351 strings[0] = xen_strdup_("SERVER_FAULT");
352 strings[1] = xen_strdup_(error_string);
354 session->ok = false;
355 session->error_description = strings;
356 session->error_description_count = 2;
357 }
360 static void server_error_2(xen_session *session, const char *error_string,
361 const char *param)
362 {
363 if (!session->ok)
364 {
365 /* Don't wipe out the earlier error message with this one. */
366 return;
367 }
369 char **strings = malloc(3 * sizeof(char *));
371 strings[0] = xen_strdup_("SERVER_FAULT_2");
372 strings[1] = xen_strdup_(error_string);
373 strings[2] = xen_strdup_(param);
375 session->ok = false;
376 session->error_description = strings;
377 session->error_description_count = 3;
378 }
381 static bool is_node(xmlNode *n, char *type)
382 {
383 return
384 n->type == XML_ELEMENT_NODE &&
385 0 == strcmp((char *)n->name, type);
386 }
389 static bool is_container_node(xmlNode *n, char *type)
390 {
391 return
392 is_node(n, type) &&
393 n->children != NULL &&
394 n->children == n->last &&
395 n->children->type == XML_ELEMENT_NODE;
396 }
399 /**
400 * @return The contents of the given value, or NULL if this is not a node with
401 * the given type. If not NULL, the result must be freed with xmlFree().
402 */
403 static xmlChar *string_from_value(xmlNode *n, char *type)
404 {
405 /*
406 <value><type>XYZ</type></value> is normal, but the XML-RPC spec also
407 allows <value>XYZ</value> where XYZ is to be interpreted as a string.
408 */
410 if (is_container_node(n, "value") &&
411 0 == strcmp((char *)n->children->name, type))
412 {
413 return
414 n->children->children == NULL ?
415 xmlStrdup(BAD_CAST("")) :
416 xmlNodeGetContent(n->children->children);
417 }
418 else if (0 == strcmp(type, "string") && is_node(n, "value"))
419 {
420 return
421 n->children == NULL ?
422 xmlStrdup(BAD_CAST("")) :
423 xmlNodeGetContent(n->children);
424 }
425 else
426 {
427 return NULL;
428 }
429 }
432 /**
433 * Find the name node that is a child of the given one, and return its
434 * contents, or NULL if this has no such node. If not NULL, the result must
435 * be freed with xmlFree().
436 */
437 static xmlChar *string_from_name(xmlNode *n)
438 {
439 xmlNode *cur = n->children;
441 while (cur != NULL)
442 {
443 if (0 == strcmp((char *)cur->name, "name"))
444 {
445 return xmlNodeGetContent(cur);
446 }
447 cur = cur->next;
448 }
450 return NULL;
451 }
454 static int count_children(xmlNode *n, const char *name)
455 {
456 int result = 0;
457 xmlNode *cur = n->children;
459 while (cur != NULL)
460 {
461 if (0 == strcmp((char *)cur->name, name))
462 {
463 result++;
464 }
465 cur = cur->next;
466 }
468 return result;
469 }
472 static void destring(xen_session *s, xmlChar *name, const abstract_type *type,
473 void *value)
474 {
475 switch (type->typename)
476 {
477 case STRING:
478 *((char **)value) = xen_strdup_((const char *)name);
479 break;
481 case INT:
482 *((int64_t *)value) = atoll((const char *)name);
483 break;
485 case FLOAT:
486 *((double *)value) = atof((const char *)name);
487 break;
489 default:
490 server_error(s, "Invalid Map key type");
491 }
492 }
495 /**
496 * result_type : STRING => value : char **, the char * is yours.
497 * result_type : ENUM => value : int *
498 * result_type : INT => value : int64_t *
499 * result_type : FLOAT => value : double *
500 * result_type : BOOL => value : bool *
501 * result_type : SET => value : arbitrary_set **, the set is yours.
502 * result_type : MAP => value : arbitrary_map **, the map is yours.
503 * result_type : OPT => value : arbitrary_record_opt **,
504 * the record is yours, the handle is filled.
505 * result_type : STRUCT => value : void **, the void * is yours.
506 */
507 static void parse_into(xen_session *s, xmlNode *value_node,
508 const abstract_type *result_type, void *value,
509 int slot)
510 {
511 if (result_type == NULL)
512 {
513 xmlChar *string = string_from_value(value_node, "string");
514 if (string == NULL || strcmp((char *)string, ""))
515 {
516 server_error(s,
517 "Expected Void from the server, but didn't get it");
518 }
519 else
520 {
521 free(string);
522 }
524 return;
525 }
527 switch (result_type->typename)
528 {
529 case STRING:
530 {
531 xmlChar *string = string_from_value(value_node, "string");
532 if (string == NULL)
533 {
534 server_error(
535 s, "Expected a String from the server, but didn't get one");
536 }
537 else
538 {
539 ((char **)value)[slot] = xen_strdup_((const char *)string);
540 free(string);
541 }
542 }
543 break;
545 case ENUM:
546 {
547 xmlChar *string = string_from_value(value_node, "string");
548 if (string == NULL)
549 {
550 #if PERMISSIVE
551 fprintf(stderr,
552 "Expected an Enum from the server, but didn't get one\n");
553 ((int *)value)[slot] = 0;
554 #else
555 server_error(
556 s, "Expected an Enum from the server, but didn't get one");
557 #endif
558 }
559 else
560 {
561 ((int *)value)[slot] =
562 result_type->enum_demarshaller(s, (const char *)string);
563 free(string);
564 }
565 }
566 break;
568 case INT:
569 {
570 xmlChar *string = string_from_value(value_node, "string");
571 if (string == NULL)
572 {
573 server_error(
574 s, "Expected an Int from the server, but didn't get one");
575 }
576 else
577 {
578 ((int64_t *)value)[slot] = (int64_t)atoll((char *)string);
579 free(string);
580 }
581 }
582 break;
584 case FLOAT:
585 {
586 xmlChar *string = string_from_value(value_node, "double");
587 if (string == NULL)
588 {
589 #if PERMISSIVE
590 fprintf(stderr,
591 "Expected a Float from the server, but didn't get one\n");
592 ((double *)value)[slot] = 0.0;
593 #else
594 server_error(
595 s, "Expected a Float from the server, but didn't get one");
596 #endif
597 }
598 else
599 {
600 ((double *)value)[slot] = atof((char *)string);
601 free(string);
602 }
603 }
604 break;
606 case BOOL:
607 {
608 xmlChar *string = string_from_value(value_node, "boolean");
609 if (string == NULL)
610 {
611 #if PERMISSIVE
612 fprintf(stderr,
613 "Expected a Bool from the server, but didn't get one\n");
614 ((bool *)value)[slot] = false;
615 #else
616 server_error(
617 s, "Expected a Bool from the server, but didn't get one");
618 #endif
619 }
620 else
621 {
622 ((bool *)value)[slot] = (0 == strcmp((char *)string, "1"));
623 free(string);
624 }
625 }
626 break;
628 case SET:
629 {
630 if (!is_container_node(value_node, "value") ||
631 !is_container_node(value_node->children, "array"))
632 {
633 server_error(s,
634 "Expected Set from the server, but didn't get it");
635 }
636 else
637 {
638 xmlNode *data_node = value_node->children->children;
639 int n = count_children(data_node, "value");
641 const abstract_type *member_type = result_type->child;
642 size_t member_size = size_of_member(member_type);
644 arbitrary_set *set =
645 calloc(1, sizeof(arbitrary_set) + member_size * n);
646 set->size = n;
647 int i = 0;
648 xmlNode *cur = data_node->children;
650 while (cur != NULL)
651 {
652 if (0 == strcmp((char *)cur->name, "value"))
653 {
654 parse_into(s, cur, member_type, set->contents, i);
655 i++;
656 }
657 cur = cur->next;
658 }
660 ((arbitrary_set **)value)[slot] = set;
661 }
662 }
663 break;
665 case MAP:
666 {
667 if (!is_container_node(value_node, "value") ||
668 value_node->children->type != XML_ELEMENT_NODE ||
669 0 != strcmp((char *)value_node->children->name, "struct") ||
670 value_node->children->children == NULL)
671 {
672 server_error(s,
673 "Expected Map from the server, but didn't get it");
674 }
675 else
676 {
677 xmlNode *struct_node = value_node->children;
678 int n = count_children(struct_node, "member");
680 size_t struct_size = result_type->struct_size;
682 const struct struct_member *key_member = result_type->members;
683 const struct struct_member *val_member = result_type->members + 1;
685 arbitrary_map *map =
686 calloc(1, sizeof(arbitrary_map) + struct_size * n);
687 map->size = n;
688 int i = 0;
689 xmlNode *cur = struct_node->children;
691 while (cur != NULL)
692 {
693 if (0 == strcmp((char *)cur->name, "member"))
694 {
695 if (cur->children == NULL || cur->last == cur->children)
696 {
697 server_error(s, "Malformed Map");
698 free(map);
699 return;
700 }
702 xmlChar *name = string_from_name(cur);
703 if (name == NULL)
704 {
705 server_error(s, "Malformed Map");
706 free(map);
707 return;
708 }
710 destring(s, name, key_member->type,
711 ((void *)(map + 1)) +
712 (i * struct_size) +
713 key_member->offset);
714 xmlFree(name);
715 if (!s->ok)
716 {
717 free(map);
718 return;
719 }
721 parse_structmap_value(s, cur, val_member->type,
722 ((void *)(map + 1)) +
723 (i * struct_size) +
724 val_member->offset);
725 if (!s->ok)
726 {
727 free(map);
728 return;
729 }
730 i++;
731 }
732 cur = cur->next;
733 }
735 ((arbitrary_map **)value)[slot] = map;
736 }
737 }
738 break;
740 case STRUCT:
741 {
742 if (!is_container_node(value_node, "value") ||
743 value_node->children->type != XML_ELEMENT_NODE ||
744 0 != strcmp((char *)value_node->children->name, "struct") ||
745 value_node->children->children == NULL)
746 {
747 server_error(s,
748 "Expected Map from the server, but didn't get it");
749 }
750 else
751 {
752 xmlNode *struct_node = value_node->children;
754 void *result = calloc(1, result_type->struct_size);
755 xmlNode *cur = struct_node->children;
757 size_t member_count = result_type->member_count;
759 const struct_member **checklist =
760 malloc(sizeof(const struct_member *) * member_count);
761 int seen_count = 0;
763 while (cur != NULL)
764 {
765 if (0 == strcmp((char *)cur->name, "member"))
766 {
767 if (cur->children == NULL || cur->last == cur->children)
768 {
769 server_error(s, "Malformed Struct");
770 free(result);
771 free(checklist);
772 return;
773 }
775 xmlChar *name = string_from_name(cur);
776 if (name == NULL)
777 {
778 server_error(s, "Malformed Struct");
779 free(result);
780 free(checklist);
781 return;
782 }
784 for (size_t i = 0; i < member_count; i++)
785 {
786 const struct_member *mem = result_type->members + i;
788 if (0 == strcmp((char *)name, mem->key))
789 {
790 parse_structmap_value(s, cur, mem->type,
791 result + mem->offset);
792 checklist[seen_count] = mem;
793 seen_count++;
794 break;
795 }
796 }
798 /* Note that we're skipping unknown fields implicitly.
799 This means that we'll be forward compatible with
800 new servers. */
802 xmlFree(name);
804 if (!s->ok)
805 {
806 free(result);
807 free(checklist);
808 return;
809 }
810 }
811 cur = cur->next;
812 }
814 /* Check that we've filled all fields. */
815 for (size_t i = 0; i < member_count; i++)
816 {
817 const struct_member *mem = result_type->members + i;
818 int j;
820 for (j = 0; j < seen_count; j++)
821 {
822 if (checklist[j] == mem)
823 {
824 break;
825 }
826 }
828 if (j == seen_count)
829 {
830 #if PERMISSIVE
831 fprintf(stderr,
832 "Struct did not contain expected field %s.\n",
833 mem->key);
834 #else
835 server_error_2(s,
836 "Struct did not contain expected field",
837 mem->key);
838 free(result);
839 free(checklist);
840 return;
841 #endif
842 }
843 }
845 free(checklist);
846 ((void **)value)[slot] = result;
847 }
848 }
849 break;
851 case REF:
852 {
853 arbitrary_record_opt *record_opt =
854 calloc(1, sizeof(arbitrary_record_opt));
856 record_opt->is_record = false;
857 parse_into(s, value_node, &abstract_type_string,
858 &(record_opt->u.handle), 0);
860 ((arbitrary_record_opt **)value)[slot] = record_opt;
861 }
862 break;
864 default:
865 assert(false);
866 }
867 }
870 static size_t size_of_member(const abstract_type *type)
871 {
872 switch (type->typename)
873 {
874 case STRING:
875 return sizeof(char *);
877 /*
878 case INT:
879 return sizeof(int64_t);
881 case FLOAT:
882 return sizeof(double);
884 case BOOL:
885 return sizeof(bool);
886 */
887 case ENUM:
888 return sizeof(int);
890 case REF:
891 return sizeof(arbitrary_record_opt *);
893 default:
894 assert(false);
895 }
896 }
899 static void parse_structmap_value(xen_session *s, xmlNode *n,
900 const abstract_type *type, void *value)
901 {
902 xmlNode *cur = n->children;
904 while (cur != NULL)
905 {
906 if (0 == strcmp((char *)cur->name, "value"))
907 {
908 parse_into(s, cur, type, value, 0);
909 return;
910 }
911 cur = cur->next;
912 }
914 server_error(s, "Missing value in Map/Struct");
915 }
918 static void parse_fault(xen_session *session, xmlXPathContextPtr xpathCtx)
919 {
920 xmlXPathObjectPtr xpathObj = xmlXPathCompiledEval(faultPath, xpathCtx);
921 if (xpathObj == NULL)
922 {
923 server_error(session, "Method response is neither result nor fault");
924 return;
925 }
927 if (xpathObj->type != XPATH_NODESET ||
928 xpathObj->nodesetval->nodeNr != 2)
929 {
930 xmlXPathFreeObject(xpathObj);
931 server_error(session, "Method response is neither result nor fault");
932 return;
933 }
935 xmlNode *fault_node0 = xpathObj->nodesetval->nodeTab[0];
936 xmlNode *fault_node1 = xpathObj->nodesetval->nodeTab[1];
938 xmlChar *fault_code_str = string_from_value(fault_node0, "int");
939 if (fault_code_str == NULL)
940 {
941 fault_code_str = string_from_value(fault_node0, "i4");
942 }
943 if (fault_code_str == NULL)
944 {
945 xmlXPathFreeObject(xpathObj);
946 server_error(session, "Fault code is malformed");
947 return;
948 }
950 xmlChar *fault_string_str = string_from_value(fault_node1, "string");
951 if (fault_string_str == NULL)
952 {
953 xmlFree(fault_code_str);
954 xmlXPathFreeObject(xpathObj);
955 server_error(session, "Fault string is malformed");
956 return;
957 }
959 char **strings = malloc(3 * sizeof(char *));
961 strings[0] = xen_strdup_("FAULT");
962 strings[1] = xen_strdup_((char *)fault_code_str);
963 strings[2] = xen_strdup_((char *)fault_string_str);
965 session->ok = false;
966 session->error_description = strings;
967 session->error_description_count = 3;
969 xmlFree(fault_code_str);
970 xmlFree(fault_string_str);
971 xmlXPathFreeObject(xpathObj);
972 }
975 static void parse_failure(xen_session *session, xmlNode *node)
976 {
977 abstract_type error_description_type =
978 { .typename = SET,
979 .child = &abstract_type_string };
980 arbitrary_set *error_descriptions;
982 parse_into(session, node, &error_description_type, &error_descriptions,
983 0);
985 if (session->ok)
986 {
987 session->ok = false;
989 char **c = (char **)error_descriptions->contents;
990 int n = error_descriptions->size;
992 char **strings = malloc(n * sizeof(char *));
993 for (int i = 0; i < n; i++)
994 {
995 strings[i] = c[i];
996 }
998 session->error_description_count = n;
999 session->error_description = strings;
1002 free(error_descriptions);
1006 /**
1007 * Parameters as for xen_call_() above.
1008 */
1009 static void parse_result(xen_session *session, const char *result,
1010 const abstract_type *result_type, void *value)
1012 xmlDocPtr doc =
1013 xmlReadMemory(result, strlen(result), "", NULL, XML_PARSE_NONET);
1015 if (doc == NULL)
1017 server_error(session, "Couldn't parse the server response");
1018 return;
1021 xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
1022 if (xpathCtx == NULL)
1024 xmlFreeDoc(doc);
1025 server_error(session, "Couldn't create XPath context");
1026 return;
1029 xmlXPathObjectPtr xpathObj =
1030 xmlXPathCompiledEval(responsePath, xpathCtx);
1031 if (xpathObj == NULL)
1033 parse_fault(session, xpathCtx);
1035 xmlXPathFreeContext(xpathCtx);
1036 xmlFreeDoc(doc);
1037 return;
1040 if (xpathObj->type != XPATH_NODESET ||
1041 xpathObj->nodesetval->nodeNr != 2)
1043 parse_fault(session, xpathCtx);
1045 xmlXPathFreeObject(xpathObj);
1046 xmlXPathFreeContext(xpathCtx);
1047 xmlFreeDoc(doc);
1048 return;
1051 xmlNode *node0 = xpathObj->nodesetval->nodeTab[0];
1052 xmlNode *node1 = xpathObj->nodesetval->nodeTab[1];
1054 xmlChar *status_code = string_from_value(node0, "string");
1055 if (status_code == NULL)
1057 xmlXPathFreeObject(xpathObj);
1058 xmlXPathFreeContext(xpathCtx);
1059 xmlFreeDoc(doc);
1060 server_error(session, "Server response does not have a Status");
1061 return;
1064 if (strcmp((char *)status_code, "Success"))
1066 parse_failure(session, node1);
1068 xmlFree(status_code);
1069 xmlXPathFreeObject(xpathObj);
1070 xmlXPathFreeContext(xpathCtx);
1071 xmlFreeDoc(doc);
1072 return;
1075 parse_into(session, node1, result_type, value, 0);
1077 xmlFree(status_code);
1078 xmlXPathFreeObject(xpathObj);
1079 xmlXPathFreeContext(xpathCtx);
1080 xmlFreeDoc(doc);
1084 static char *
1085 make_body(const char *method_name, abstract_value params[], int param_count)
1087 char buf[20];
1089 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
1090 xmlNode *methodCall = xmlNewNode(NULL, BAD_CAST "methodCall");
1091 xmlDocSetRootElement(doc, methodCall);
1093 xmlNewChild(methodCall, NULL, BAD_CAST "methodName",
1094 BAD_CAST method_name);
1096 xmlNode *params_node =
1097 xmlNewChild(methodCall, NULL, BAD_CAST "params", NULL);
1099 for (int p = 0; p < param_count; p++)
1101 abstract_value *v = params + p;
1102 switch (v->type->typename)
1104 case STRING:
1105 add_param(params_node, "string", v->u.string_val);
1106 break;
1108 case INT:
1109 snprintf(buf, sizeof(buf), "%"PRId64, v->u.int_val);
1110 add_param(params_node, "string", buf);
1111 break;
1113 case FLOAT:
1114 snprintf(buf, sizeof(buf), "%lf", v->u.float_val);
1115 add_param(params_node, "double", buf);
1116 break;
1118 case BOOL:
1119 add_param(params_node, "boolean", v->u.bool_val ? "1" : "0");
1120 break;
1122 case VOID:
1123 add_param(params_node, "string", "");
1124 break;
1126 case ENUM:
1127 add_param(params_node, "string",
1128 v->type->enum_marshaller(v->u.enum_val));
1129 break;
1131 case STRUCT:
1133 size_t member_count = v->type->member_count;
1135 xmlNode *struct_node = add_param_struct(params_node);
1137 for (size_t i = 0; i < member_count; i++)
1139 const struct struct_member *mem = v->type->members + i;
1140 const char *key = mem->key;
1141 void *struct_value = v->u.struct_val;
1143 add_struct_value(mem->type, struct_value + mem->offset,
1144 add_struct_member, key, struct_node);
1147 break;
1149 default:
1150 assert(false);
1154 xmlBufferPtr buffer = xmlBufferCreate();
1155 xmlSaveCtxtPtr save_ctxt =
1156 xmlSaveToBuffer(buffer, NULL, XML_SAVE_NO_XHTML);
1158 if (xmlSaveDoc(save_ctxt, doc) == -1)
1160 return NULL;
1163 xmlFreeDoc(doc);
1164 xmlSaveClose(save_ctxt);
1165 xmlChar *content = xmlStrdup(xmlBufferContent(buffer));
1166 xmlBufferFree(buffer);
1167 return (char *)content;
1171 static void
1172 add_struct_value(const struct abstract_type *type, void *value,
1173 void (*adder)(xmlNode *node, const char *key,
1174 const char *type, const char *val),
1175 const char *key, xmlNode *node)
1177 char buf[20];
1179 switch (type->typename)
1181 case REF:
1182 case STRING:
1183 case INT:
1184 case ENUM:
1186 const char *val_as_string = get_val_as_string(type, value, buf);
1187 adder(node, key, "string", val_as_string);
1189 break;
1191 case FLOAT:
1193 double val = *(double *)value;
1194 snprintf(buf, sizeof(buf), "%lf", val);
1195 adder(node, key, "double", buf);
1197 break;
1199 case BOOL:
1201 bool val = *(bool *)value;
1202 adder(node, key, "boolean", val ? "1" : "0");
1204 break;
1206 case SET:
1208 const struct abstract_type *member_type = type->child;
1209 size_t member_size = size_of_member(member_type);
1210 arbitrary_set *set_val = *(arbitrary_set **)value;
1212 if (set_val != NULL)
1214 xmlNode *data_node = add_struct_array(node, key);
1216 for (size_t i = 0; i < set_val->size; i++)
1218 void *member_value = set_val->contents + (i * member_size);
1219 add_struct_value(member_type, member_value,
1220 add_unnamed_value, NULL, data_node);
1224 break;
1226 case STRUCT:
1228 assert(false);
1229 /* XXX Nested structures aren't supported yet, but
1230 fortunately we don't need them, because we don't have
1231 any "deep create" calls. This will need to be
1232 fixed. */
1234 break;
1236 case MAP:
1238 size_t member_size = type->struct_size;
1239 const struct abstract_type *l_type = type->members[0].type;
1240 const struct abstract_type *r_type = type->members[1].type;
1241 int l_offset = type->members[0].offset;
1242 int r_offset = type->members[1].offset;
1244 arbitrary_map *map_val = *(arbitrary_map **)value;
1246 if (map_val != NULL)
1248 xmlNode *struct_node = add_nested_struct(node, key);
1250 for (size_t i = 0; i < map_val->size; i++)
1252 void *contents = (void *)map_val->contents;
1253 void *l_value = contents + (i * member_size) + l_offset;
1254 void *r_value = contents + (i * member_size) + r_offset;
1256 const char *l_value_as_string =
1257 get_val_as_string(l_type, l_value, buf);
1259 add_struct_value(r_type, r_value, add_struct_member,
1260 l_value_as_string, struct_node);
1264 break;
1266 default:
1267 assert(false);
1272 static const char *
1273 get_val_as_string(const struct abstract_type *type, void *value, char *buf)
1275 switch (type->typename)
1277 case REF:
1279 arbitrary_record_opt *val = *(arbitrary_record_opt **)value;
1280 if (val != NULL)
1282 if (val->is_record)
1284 return val->u.record->handle;
1286 else
1288 return val->u.handle;
1291 else
1293 return NULL;
1296 break;
1298 case STRING:
1300 return *(char **)value;
1302 break;
1304 case INT:
1306 int64_t val = *(int64_t *)value;
1307 snprintf(buf, sizeof(buf), "%"PRId64, val);
1308 return buf;
1310 break;
1312 case ENUM:
1314 int val = *(int *)value;
1315 return type->enum_marshaller(val);
1317 break;
1319 default:
1320 assert(false);
1325 static xmlNode *
1326 add_container(xmlNode *parent, const char *name)
1328 return xmlNewChild(parent, NULL, BAD_CAST name, NULL);
1332 static void
1333 add_param(xmlNode *params_node, const char *type, const char *value)
1335 xmlNode *param_node = add_container(params_node, "param");
1336 add_value(param_node, type, value);
1340 static void
1341 add_value(xmlNode *parent, const char *type, const char *value)
1343 xmlNode *value_node = add_container(parent, "value");
1344 xmlNewChild(value_node, NULL, BAD_CAST type, BAD_CAST value);
1348 static void
1349 add_unnamed_value(xmlNode *parent, const char *name, const char *type,
1350 const char *value)
1352 (void)name;
1353 add_value(parent, type, value);
1357 static xmlNode *
1358 add_param_struct(xmlNode *params_node)
1360 xmlNode *param_node = add_container(params_node, "param");
1361 xmlNode *value_node = add_container(param_node, "value");
1363 return xmlNewChild(value_node, NULL, BAD_CAST "struct", NULL);
1367 static void
1368 add_struct_member(xmlNode *struct_node, const char *name, const char *type,
1369 const char *value)
1371 xmlNode *member_node = add_container(struct_node, "member");
1373 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1375 add_value(member_node, type, value);
1379 static xmlNode *
1380 add_struct_array(xmlNode *struct_node, const char *name)
1382 xmlNode *member_node = add_container(struct_node, "member");
1384 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1386 xmlNode *value_node = add_container(member_node, "value");
1387 xmlNode *array_node = add_container(value_node, "array");
1389 return add_container(array_node, "data");
1393 static xmlNode *
1394 add_nested_struct(xmlNode *struct_node, const char *name)
1396 xmlNode *member_node = add_container(struct_node, "member");
1398 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1400 xmlNode *value_node = add_container(member_node, "value");
1402 return add_container(value_node, "struct");
1406 int xen_enum_lookup_(xen_session *session, const char *str,
1407 const char **lookup_table, int n)
1409 if (str != NULL)
1411 for (int i = 0; i < n; i++)
1413 if (0 == strcmp(str, lookup_table[i]))
1415 return i;
1420 server_error_2(session, "Bad enum string", str);
1421 return 0;
1425 char *
1426 xen_strdup_(const char *in)
1428 char *result = malloc(strlen(in) + 1);
1429 strcpy(result, in);
1430 return result;
1434 const abstract_type abstract_type_string = { .typename = STRING };
1435 const abstract_type abstract_type_int = { .typename = INT };
1436 const abstract_type abstract_type_float = { .typename = FLOAT };
1437 const abstract_type abstract_type_bool = { .typename = BOOL };
1438 const abstract_type abstract_type_datetime = { .typename = DATETIME };
1439 const abstract_type abstract_type_ref = { .typename = REF };
1441 const abstract_type abstract_type_string_set =
1443 .typename = SET,
1444 .child = &abstract_type_string
1445 };
1447 const abstract_type abstract_type_ref_set =
1449 .typename = SET,
1450 .child = &abstract_type_ref
1451 };
1453 static const struct struct_member string_string_members[] =
1456 .type = &abstract_type_string,
1457 .offset = offsetof(xen_string_string_map_contents, key)
1458 },
1460 .type = &abstract_type_string,
1461 .offset = offsetof(xen_string_string_map_contents, val)
1463 };
1464 const abstract_type abstract_type_string_string_map =
1466 .typename = MAP,
1467 .struct_size = sizeof(xen_string_string_map_contents),
1468 .members = string_string_members
1469 };
1471 static struct struct_member int_float_members[] =
1474 .type = &abstract_type_int,
1475 .offset = offsetof(xen_int_float_map_contents, key)
1476 },
1478 .type = &abstract_type_float,
1479 .offset = offsetof(xen_int_float_map_contents, val)
1481 };
1482 const abstract_type abstract_type_int_float_map =
1484 .typename = MAP,
1485 .struct_size = sizeof(xen_int_float_map_contents),
1486 .members = int_float_members
1487 };