direct-io.hg

view tools/libxen/src/xen_common.c @ 14333:798a7dc1ac6d

Fix get_val_as_string so that it does not truncate integers.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Sat Mar 10 14:41:06 2007 +0000 (2007-03-10)
parents 6b057bdf0354
children 931c4b77ea7d
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 *, size_t);
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 {
671 server_error(s,
672 "Expected Map from the server, but didn't get it");
673 }
674 else
675 {
676 xmlNode *struct_node = value_node->children;
677 int n = count_children(struct_node, "member");
679 size_t struct_size = result_type->struct_size;
681 const struct struct_member *key_member = result_type->members;
682 const struct struct_member *val_member = result_type->members + 1;
684 arbitrary_map *map =
685 calloc(1, sizeof(arbitrary_map) + struct_size * n);
686 map->size = n;
687 int i = 0;
688 xmlNode *cur = struct_node->children;
690 while (cur != NULL)
691 {
692 if (0 == strcmp((char *)cur->name, "member"))
693 {
694 if (cur->children == NULL || cur->last == cur->children)
695 {
696 server_error(s, "Malformed Map");
697 free(map);
698 return;
699 }
701 xmlChar *name = string_from_name(cur);
702 if (name == NULL)
703 {
704 server_error(s, "Malformed Map");
705 free(map);
706 return;
707 }
709 destring(s, name, key_member->type,
710 ((void *)(map + 1)) +
711 (i * struct_size) +
712 key_member->offset);
713 xmlFree(name);
714 if (!s->ok)
715 {
716 free(map);
717 return;
718 }
720 parse_structmap_value(s, cur, val_member->type,
721 ((void *)(map + 1)) +
722 (i * struct_size) +
723 val_member->offset);
724 if (!s->ok)
725 {
726 free(map);
727 return;
728 }
729 i++;
730 }
731 cur = cur->next;
732 }
734 ((arbitrary_map **)value)[slot] = map;
735 }
736 }
737 break;
739 case STRUCT:
740 {
741 if (!is_container_node(value_node, "value") ||
742 value_node->children->type != XML_ELEMENT_NODE ||
743 0 != strcmp((char *)value_node->children->name, "struct") ||
744 value_node->children->children == NULL)
745 {
746 server_error(s,
747 "Expected Map from the server, but didn't get it");
748 }
749 else
750 {
751 xmlNode *struct_node = value_node->children;
753 void *result = calloc(1, result_type->struct_size);
754 xmlNode *cur = struct_node->children;
756 size_t member_count = result_type->member_count;
758 const struct_member **checklist =
759 malloc(sizeof(const struct_member *) * member_count);
760 int seen_count = 0;
762 while (cur != NULL)
763 {
764 if (0 == strcmp((char *)cur->name, "member"))
765 {
766 if (cur->children == NULL || cur->last == cur->children)
767 {
768 server_error(s, "Malformed Struct");
769 free(result);
770 free(checklist);
771 return;
772 }
774 xmlChar *name = string_from_name(cur);
775 if (name == NULL)
776 {
777 server_error(s, "Malformed Struct");
778 free(result);
779 free(checklist);
780 return;
781 }
783 for (size_t i = 0; i < member_count; i++)
784 {
785 const struct_member *mem = result_type->members + i;
787 if (0 == strcmp((char *)name, mem->key))
788 {
789 parse_structmap_value(s, cur, mem->type,
790 result + mem->offset);
791 checklist[seen_count] = mem;
792 seen_count++;
793 break;
794 }
795 }
797 /* Note that we're skipping unknown fields implicitly.
798 This means that we'll be forward compatible with
799 new servers. */
801 xmlFree(name);
803 if (!s->ok)
804 {
805 free(result);
806 free(checklist);
807 return;
808 }
809 }
810 cur = cur->next;
811 }
813 /* Check that we've filled all fields. */
814 for (size_t i = 0; i < member_count; i++)
815 {
816 const struct_member *mem = result_type->members + i;
817 int j;
819 for (j = 0; j < seen_count; j++)
820 {
821 if (checklist[j] == mem)
822 {
823 break;
824 }
825 }
827 if (j == seen_count)
828 {
829 #if PERMISSIVE
830 fprintf(stderr,
831 "Struct did not contain expected field %s.\n",
832 mem->key);
833 #else
834 server_error_2(s,
835 "Struct did not contain expected field",
836 mem->key);
837 free(result);
838 free(checklist);
839 return;
840 #endif
841 }
842 }
844 free(checklist);
845 ((void **)value)[slot] = result;
846 }
847 }
848 break;
850 case REF:
851 {
852 arbitrary_record_opt *record_opt =
853 calloc(1, sizeof(arbitrary_record_opt));
855 record_opt->is_record = false;
856 parse_into(s, value_node, &abstract_type_string,
857 &(record_opt->u.handle), 0);
859 ((arbitrary_record_opt **)value)[slot] = record_opt;
860 }
861 break;
863 default:
864 assert(false);
865 }
866 }
869 static size_t size_of_member(const abstract_type *type)
870 {
871 switch (type->typename)
872 {
873 case STRING:
874 return sizeof(char *);
876 /*
877 case INT:
878 return sizeof(int64_t);
880 case FLOAT:
881 return sizeof(double);
883 case BOOL:
884 return sizeof(bool);
885 */
886 case ENUM:
887 return sizeof(int);
889 case REF:
890 return sizeof(arbitrary_record_opt *);
892 case STRUCT:
893 return type->struct_size;
895 default:
896 assert(false);
897 }
898 }
901 static void parse_structmap_value(xen_session *s, xmlNode *n,
902 const abstract_type *type, void *value)
903 {
904 xmlNode *cur = n->children;
906 while (cur != NULL)
907 {
908 if (0 == strcmp((char *)cur->name, "value"))
909 {
910 parse_into(s, cur, type, value, 0);
911 return;
912 }
913 cur = cur->next;
914 }
916 server_error(s, "Missing value in Map/Struct");
917 }
920 static void parse_fault(xen_session *session, xmlXPathContextPtr xpathCtx)
921 {
922 xmlXPathObjectPtr xpathObj = xmlXPathCompiledEval(faultPath, xpathCtx);
923 if (xpathObj == NULL)
924 {
925 server_error(session, "Method response is neither result nor fault");
926 return;
927 }
929 if (xpathObj->type != XPATH_NODESET ||
930 xpathObj->nodesetval->nodeNr != 2)
931 {
932 xmlXPathFreeObject(xpathObj);
933 server_error(session, "Method response is neither result nor fault");
934 return;
935 }
937 xmlNode *fault_node0 = xpathObj->nodesetval->nodeTab[0];
938 xmlNode *fault_node1 = xpathObj->nodesetval->nodeTab[1];
940 xmlChar *fault_code_str = string_from_value(fault_node0, "int");
941 if (fault_code_str == NULL)
942 {
943 fault_code_str = string_from_value(fault_node0, "i4");
944 }
945 if (fault_code_str == NULL)
946 {
947 xmlXPathFreeObject(xpathObj);
948 server_error(session, "Fault code is malformed");
949 return;
950 }
952 xmlChar *fault_string_str = string_from_value(fault_node1, "string");
953 if (fault_string_str == NULL)
954 {
955 xmlFree(fault_code_str);
956 xmlXPathFreeObject(xpathObj);
957 server_error(session, "Fault string is malformed");
958 return;
959 }
961 char **strings = malloc(3 * sizeof(char *));
963 strings[0] = xen_strdup_("FAULT");
964 strings[1] = xen_strdup_((char *)fault_code_str);
965 strings[2] = xen_strdup_((char *)fault_string_str);
967 session->ok = false;
968 session->error_description = strings;
969 session->error_description_count = 3;
971 xmlFree(fault_code_str);
972 xmlFree(fault_string_str);
973 xmlXPathFreeObject(xpathObj);
974 }
977 static void parse_failure(xen_session *session, xmlNode *node)
978 {
979 abstract_type error_description_type =
980 { .typename = SET,
981 .child = &abstract_type_string };
982 arbitrary_set *error_descriptions;
984 parse_into(session, node, &error_description_type, &error_descriptions,
985 0);
987 if (session->ok)
988 {
989 session->ok = false;
991 char **c = (char **)error_descriptions->contents;
992 int n = error_descriptions->size;
994 char **strings = malloc(n * sizeof(char *));
995 for (int i = 0; i < n; i++)
996 {
997 strings[i] = c[i];
998 }
1000 session->error_description_count = n;
1001 session->error_description = strings;
1004 free(error_descriptions);
1008 /**
1009 * Parameters as for xen_call_() above.
1010 */
1011 static void parse_result(xen_session *session, const char *result,
1012 const abstract_type *result_type, void *value)
1014 xmlDocPtr doc =
1015 xmlReadMemory(result, strlen(result), "", NULL, XML_PARSE_NONET);
1017 if (doc == NULL)
1019 server_error(session, "Couldn't parse the server response");
1020 return;
1023 xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
1024 if (xpathCtx == NULL)
1026 xmlFreeDoc(doc);
1027 server_error(session, "Couldn't create XPath context");
1028 return;
1031 xmlXPathObjectPtr xpathObj =
1032 xmlXPathCompiledEval(responsePath, xpathCtx);
1033 if (xpathObj == NULL)
1035 parse_fault(session, xpathCtx);
1037 xmlXPathFreeContext(xpathCtx);
1038 xmlFreeDoc(doc);
1039 return;
1042 if (xpathObj->type != XPATH_NODESET ||
1043 xpathObj->nodesetval->nodeNr != 2)
1045 parse_fault(session, xpathCtx);
1047 xmlXPathFreeObject(xpathObj);
1048 xmlXPathFreeContext(xpathCtx);
1049 xmlFreeDoc(doc);
1050 return;
1053 xmlNode *node0 = xpathObj->nodesetval->nodeTab[0];
1054 xmlNode *node1 = xpathObj->nodesetval->nodeTab[1];
1056 xmlChar *status_code = string_from_value(node0, "string");
1057 if (status_code == NULL)
1059 xmlXPathFreeObject(xpathObj);
1060 xmlXPathFreeContext(xpathCtx);
1061 xmlFreeDoc(doc);
1062 server_error(session, "Server response does not have a Status");
1063 return;
1066 if (strcmp((char *)status_code, "Success"))
1068 parse_failure(session, node1);
1070 xmlFree(status_code);
1071 xmlXPathFreeObject(xpathObj);
1072 xmlXPathFreeContext(xpathCtx);
1073 xmlFreeDoc(doc);
1074 return;
1077 parse_into(session, node1, result_type, value, 0);
1079 xmlFree(status_code);
1080 xmlXPathFreeObject(xpathObj);
1081 xmlXPathFreeContext(xpathCtx);
1082 xmlFreeDoc(doc);
1086 static char *
1087 make_body(const char *method_name, abstract_value params[], int param_count)
1089 char buf[20];
1091 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
1092 xmlNode *methodCall = xmlNewNode(NULL, BAD_CAST "methodCall");
1093 xmlDocSetRootElement(doc, methodCall);
1095 xmlNewChild(methodCall, NULL, BAD_CAST "methodName",
1096 BAD_CAST method_name);
1098 xmlNode *params_node =
1099 xmlNewChild(methodCall, NULL, BAD_CAST "params", NULL);
1101 for (int p = 0; p < param_count; p++)
1103 abstract_value *v = params + p;
1104 switch (v->type->typename)
1106 case STRING:
1107 add_param(params_node, "string", v->u.string_val);
1108 break;
1110 case INT:
1111 snprintf(buf, sizeof(buf), "%"PRId64, v->u.int_val);
1112 add_param(params_node, "string", buf);
1113 break;
1115 case FLOAT:
1116 snprintf(buf, sizeof(buf), "%lf", v->u.float_val);
1117 add_param(params_node, "double", buf);
1118 break;
1120 case BOOL:
1121 add_param(params_node, "boolean", v->u.bool_val ? "1" : "0");
1122 break;
1124 case VOID:
1125 add_param(params_node, "string", "");
1126 break;
1128 case ENUM:
1129 add_param(params_node, "string",
1130 v->type->enum_marshaller(v->u.enum_val));
1131 break;
1133 case STRUCT:
1135 size_t member_count = v->type->member_count;
1137 xmlNode *struct_node = add_param_struct(params_node);
1139 for (size_t i = 0; i < member_count; i++)
1141 const struct struct_member *mem = v->type->members + i;
1142 const char *key = mem->key;
1143 void *struct_value = v->u.struct_val;
1145 add_struct_value(mem->type, struct_value + mem->offset,
1146 add_struct_member, key, struct_node);
1149 break;
1151 default:
1152 assert(false);
1156 xmlBufferPtr buffer = xmlBufferCreate();
1157 xmlSaveCtxtPtr save_ctxt =
1158 xmlSaveToBuffer(buffer, NULL, XML_SAVE_NO_XHTML);
1160 if (xmlSaveDoc(save_ctxt, doc) == -1)
1162 return NULL;
1165 xmlFreeDoc(doc);
1166 xmlSaveClose(save_ctxt);
1167 xmlChar *content = xmlStrdup(xmlBufferContent(buffer));
1168 xmlBufferFree(buffer);
1169 return (char *)content;
1173 static void
1174 add_struct_value(const struct abstract_type *type, void *value,
1175 void (*adder)(xmlNode *node, const char *key,
1176 const char *type, const char *val),
1177 const char *key, xmlNode *node)
1179 char buf[20];
1181 switch (type->typename)
1183 case REF:
1184 case STRING:
1185 case INT:
1186 case ENUM:
1188 const char *val_as_string =
1189 get_val_as_string(type, value, buf, sizeof(buf));
1190 adder(node, key, "string", val_as_string);
1192 break;
1194 case FLOAT:
1196 double val = *(double *)value;
1197 snprintf(buf, sizeof(buf), "%lf", val);
1198 adder(node, key, "double", buf);
1200 break;
1202 case BOOL:
1204 bool val = *(bool *)value;
1205 adder(node, key, "boolean", val ? "1" : "0");
1207 break;
1209 case SET:
1211 const struct abstract_type *member_type = type->child;
1212 size_t member_size = size_of_member(member_type);
1213 arbitrary_set *set_val = *(arbitrary_set **)value;
1215 if (set_val != NULL)
1217 xmlNode *data_node = add_struct_array(node, key);
1219 for (size_t i = 0; i < set_val->size; i++)
1221 void *member_value = (char *)set_val->contents +
1222 (i * member_size);
1223 add_struct_value(member_type, member_value,
1224 add_unnamed_value, NULL, data_node);
1228 break;
1230 case STRUCT:
1232 assert(false);
1233 /* XXX Nested structures aren't supported yet, but
1234 fortunately we don't need them, because we don't have
1235 any "deep create" calls. This will need to be
1236 fixed. */
1238 break;
1240 case MAP:
1242 size_t member_size = type->struct_size;
1243 const struct abstract_type *l_type = type->members[0].type;
1244 const struct abstract_type *r_type = type->members[1].type;
1245 int l_offset = type->members[0].offset;
1246 int r_offset = type->members[1].offset;
1248 arbitrary_map *map_val = *(arbitrary_map **)value;
1250 if (map_val != NULL)
1252 xmlNode *struct_node = add_nested_struct(node, key);
1254 for (size_t i = 0; i < map_val->size; i++)
1256 void *contents = (void *)map_val->contents;
1257 void *l_value = contents + (i * member_size) + l_offset;
1258 void *r_value = contents + (i * member_size) + r_offset;
1260 const char *l_value_as_string =
1261 get_val_as_string(l_type, l_value, buf, sizeof(buf));
1263 add_struct_value(r_type, r_value, add_struct_member,
1264 l_value_as_string, struct_node);
1268 break;
1270 default:
1271 assert(false);
1276 static const char *
1277 get_val_as_string(const struct abstract_type *type, void *value, char *buf,
1278 size_t bufsize)
1280 switch (type->typename)
1282 case REF:
1284 arbitrary_record_opt *val = *(arbitrary_record_opt **)value;
1285 if (val != NULL)
1287 if (val->is_record)
1289 return val->u.record->handle;
1291 else
1293 return val->u.handle;
1296 else
1298 return NULL;
1301 break;
1303 case STRING:
1305 return *(char **)value;
1307 break;
1309 case INT:
1311 int64_t val = *(int64_t *)value;
1312 snprintf(buf, bufsize, "%"PRId64, val);
1313 return buf;
1315 break;
1317 case ENUM:
1319 int val = *(int *)value;
1320 return type->enum_marshaller(val);
1322 break;
1324 default:
1325 assert(false);
1330 static xmlNode *
1331 add_container(xmlNode *parent, const char *name)
1333 return xmlNewChild(parent, NULL, BAD_CAST name, NULL);
1337 static void
1338 add_param(xmlNode *params_node, const char *type, const char *value)
1340 xmlNode *param_node = add_container(params_node, "param");
1341 add_value(param_node, type, value);
1345 static void
1346 add_value(xmlNode *parent, const char *type, const char *value)
1348 xmlNode *value_node = add_container(parent, "value");
1349 xmlNewChild(value_node, NULL, BAD_CAST type, BAD_CAST value);
1353 static void
1354 add_unnamed_value(xmlNode *parent, const char *name, const char *type,
1355 const char *value)
1357 (void)name;
1358 add_value(parent, type, value);
1362 static xmlNode *
1363 add_param_struct(xmlNode *params_node)
1365 xmlNode *param_node = add_container(params_node, "param");
1366 xmlNode *value_node = add_container(param_node, "value");
1368 return xmlNewChild(value_node, NULL, BAD_CAST "struct", NULL);
1372 static void
1373 add_struct_member(xmlNode *struct_node, const char *name, const char *type,
1374 const char *value)
1376 xmlNode *member_node = add_container(struct_node, "member");
1378 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1380 add_value(member_node, type, value);
1384 static xmlNode *
1385 add_struct_array(xmlNode *struct_node, const char *name)
1387 xmlNode *member_node = add_container(struct_node, "member");
1389 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1391 xmlNode *value_node = add_container(member_node, "value");
1392 xmlNode *array_node = add_container(value_node, "array");
1394 return add_container(array_node, "data");
1398 static xmlNode *
1399 add_nested_struct(xmlNode *struct_node, const char *name)
1401 xmlNode *member_node = add_container(struct_node, "member");
1403 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1405 xmlNode *value_node = add_container(member_node, "value");
1407 return add_container(value_node, "struct");
1411 int xen_enum_lookup_(xen_session *session, const char *str,
1412 const char **lookup_table, int n)
1414 if (str != NULL)
1416 for (int i = 0; i < n; i++)
1418 if (0 == strcmp(str, lookup_table[i]))
1420 return i;
1425 server_error_2(session, "Bad enum string", str);
1426 return 0;
1430 char *
1431 xen_strdup_(const char *in)
1433 char *result = malloc(strlen(in) + 1);
1434 strcpy(result, in);
1435 return result;
1439 const abstract_type abstract_type_string = { .typename = STRING };
1440 const abstract_type abstract_type_int = { .typename = INT };
1441 const abstract_type abstract_type_float = { .typename = FLOAT };
1442 const abstract_type abstract_type_bool = { .typename = BOOL };
1443 const abstract_type abstract_type_datetime = { .typename = DATETIME };
1444 const abstract_type abstract_type_ref = { .typename = REF };
1446 const abstract_type abstract_type_string_set =
1448 .typename = SET,
1449 .child = &abstract_type_string
1450 };
1452 const abstract_type abstract_type_ref_set =
1454 .typename = SET,
1455 .child = &abstract_type_ref
1456 };
1458 static const struct struct_member string_string_members[] =
1461 .type = &abstract_type_string,
1462 .offset = offsetof(xen_string_string_map_contents, key)
1463 },
1465 .type = &abstract_type_string,
1466 .offset = offsetof(xen_string_string_map_contents, val)
1468 };
1469 const abstract_type abstract_type_string_string_map =
1471 .typename = MAP,
1472 .struct_size = sizeof(xen_string_string_map_contents),
1473 .members = string_string_members
1474 };
1476 static struct struct_member int_float_members[] =
1479 .type = &abstract_type_int,
1480 .offset = offsetof(xen_int_float_map_contents, key)
1481 },
1483 .type = &abstract_type_float,
1484 .offset = offsetof(xen_int_float_map_contents, val)
1486 };
1487 const abstract_type abstract_type_int_float_map =
1489 .typename = MAP,
1490 .struct_size = sizeof(xen_int_float_map_contents),
1491 .members = int_float_members
1492 };