ia64/xen-unstable

view tools/libxen/src/xen_common.c @ 13271:36e00d04278d

Added permissiveness for floats.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Fri Jan 05 12:29:26 2007 +0000 (2007-01-05)
parents 38ad5643aafe
children bb8ae710d829
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 #if PERMISSIVE
561 fprintf(stderr,
562 "Expected a Float from the server, but didn't get one\n");
563 ((double *)value)[slot] = 0.0;
564 #else
565 server_error(
566 s, "Expected a Float from the server, but didn't get one");
567 #endif
568 }
569 else
570 {
571 ((double *)value)[slot] = atof((char *)string);
572 free(string);
573 }
574 }
575 break;
577 case BOOL:
578 {
579 xmlChar *string = string_from_value(value_node, "boolean");
580 if (string == NULL)
581 {
582 #if PERMISSIVE
583 fprintf(stderr,
584 "Expected a Bool from the server, but didn't get one\n");
585 ((bool *)value)[slot] = false;
586 #else
587 server_error(
588 s, "Expected a Bool from the server, but didn't get one");
589 #endif
590 }
591 else
592 {
593 ((bool *)value)[slot] = (0 == strcmp((char *)string, "1"));
594 free(string);
595 }
596 }
597 break;
599 case SET:
600 {
601 if (!is_container_node(value_node, "value") ||
602 !is_container_node(value_node->children, "array"))
603 {
604 server_error(s,
605 "Expected Set from the server, but didn't get it");
606 }
607 else
608 {
609 xmlNode *data_node = value_node->children->children;
610 int n = count_children(data_node, "value");
612 const abstract_type *member_type = result_type->child;
613 size_t member_size = size_of_member(member_type);
615 arbitrary_set *set =
616 calloc(1, sizeof(arbitrary_set) + member_size * n);
617 set->size = n;
618 int i = 0;
619 xmlNode *cur = data_node->children;
621 while (cur != NULL)
622 {
623 if (0 == strcmp((char *)cur->name, "value"))
624 {
625 parse_into(s, cur, member_type, set->contents, i);
626 i++;
627 }
628 cur = cur->next;
629 }
631 ((arbitrary_set **)value)[slot] = set;
632 }
633 }
634 break;
636 case MAP:
637 {
638 if (!is_container_node(value_node, "value") ||
639 value_node->children->type != XML_ELEMENT_NODE ||
640 0 != strcmp((char *)value_node->children->name, "struct") ||
641 value_node->children->children == NULL)
642 {
643 server_error(s,
644 "Expected Map from the server, but didn't get it");
645 }
646 else
647 {
648 xmlNode *struct_node = value_node->children;
649 int n = count_children(struct_node, "member");
651 size_t struct_size = result_type->struct_size;
653 const struct struct_member *key_member = result_type->members;
654 const struct struct_member *val_member = result_type->members + 1;
656 arbitrary_map *map =
657 calloc(1, sizeof(arbitrary_map) + struct_size * n);
658 map->size = n;
659 int i = 0;
660 xmlNode *cur = struct_node->children;
662 while (cur != NULL)
663 {
664 if (0 == strcmp((char *)cur->name, "member"))
665 {
666 if (cur->children == NULL || cur->last == cur->children)
667 {
668 server_error(s, "Malformed Map");
669 free(map);
670 return;
671 }
673 xmlChar *name = string_from_name(cur);
674 if (name == NULL)
675 {
676 server_error(s, "Malformed Map");
677 free(map);
678 return;
679 }
681 destring(s, name, key_member->type,
682 ((void *)(map + 1)) +
683 (i * struct_size) +
684 key_member->offset);
685 xmlFree(name);
686 if (!s->ok)
687 {
688 free(map);
689 return;
690 }
692 parse_structmap_value(s, cur, val_member->type,
693 ((void *)(map + 1)) +
694 (i * struct_size) +
695 val_member->offset);
696 if (!s->ok)
697 {
698 free(map);
699 return;
700 }
701 i++;
702 }
703 cur = cur->next;
704 }
706 ((arbitrary_map **)value)[slot] = map;
707 }
708 }
709 break;
711 case STRUCT:
712 {
713 if (!is_container_node(value_node, "value") ||
714 value_node->children->type != XML_ELEMENT_NODE ||
715 0 != strcmp((char *)value_node->children->name, "struct") ||
716 value_node->children->children == NULL)
717 {
718 server_error(s,
719 "Expected Map from the server, but didn't get it");
720 }
721 else
722 {
723 xmlNode *struct_node = value_node->children;
725 void *result = calloc(1, result_type->struct_size);
726 xmlNode *cur = struct_node->children;
728 size_t member_count = result_type->member_count;
730 const struct_member **checklist =
731 malloc(sizeof(const struct_member *) * member_count);
732 int seen_count = 0;
734 while (cur != NULL)
735 {
736 if (0 == strcmp((char *)cur->name, "member"))
737 {
738 if (cur->children == NULL || cur->last == cur->children)
739 {
740 server_error(s, "Malformed Struct");
741 free(result);
742 free(checklist);
743 return;
744 }
746 xmlChar *name = string_from_name(cur);
747 if (name == NULL)
748 {
749 server_error(s, "Malformed Struct");
750 free(result);
751 free(checklist);
752 return;
753 }
755 for (size_t i = 0; i < member_count; i++)
756 {
757 const struct_member *mem = result_type->members + i;
759 if (0 == strcmp((char *)name, mem->key))
760 {
761 parse_structmap_value(s, cur, mem->type,
762 result + mem->offset);
763 checklist[seen_count] = mem;
764 seen_count++;
765 break;
766 }
767 }
769 /* Note that we're skipping unknown fields implicitly.
770 This means that we'll be forward compatible with
771 new servers. */
773 xmlFree(name);
775 if (!s->ok)
776 {
777 free(result);
778 free(checklist);
779 return;
780 }
781 }
782 cur = cur->next;
783 }
785 /* Check that we've filled all fields. */
786 for (size_t i = 0; i < member_count; i++)
787 {
788 const struct_member *mem = result_type->members + i;
789 int j;
791 for (j = 0; j < seen_count; j++)
792 {
793 if (checklist[j] == mem)
794 {
795 break;
796 }
797 }
799 if (j == seen_count)
800 {
801 #if PERMISSIVE
802 fprintf(stderr,
803 "Struct did not contain expected field %s.\n",
804 mem->key);
805 #else
806 server_error_2(s,
807 "Struct did not contain expected field",
808 mem->key);
809 free(result);
810 free(checklist);
811 return;
812 #endif
813 }
814 }
816 free(checklist);
817 ((void **)value)[slot] = result;
818 }
819 }
820 break;
822 case REF:
823 {
824 arbitrary_record_opt *record_opt =
825 calloc(1, sizeof(arbitrary_record_opt));
827 record_opt->is_record = false;
828 parse_into(s, value_node, &abstract_type_string,
829 &(record_opt->u.handle), 0);
831 ((arbitrary_record_opt **)value)[slot] = record_opt;
832 }
833 break;
835 default:
836 assert(false);
837 }
838 }
841 static size_t size_of_member(const abstract_type *type)
842 {
843 switch (type->typename)
844 {
845 case STRING:
846 return sizeof(char *);
848 /*
849 case INT:
850 return sizeof(int64_t);
852 case FLOAT:
853 return sizeof(double);
855 case BOOL:
856 return sizeof(bool);
857 */
858 case ENUM:
859 return sizeof(int);
861 case REF:
862 return sizeof(arbitrary_record_opt *);
864 default:
865 assert(false);
866 }
867 }
870 static void parse_structmap_value(xen_session *s, xmlNode *n,
871 const abstract_type *type, void *value)
872 {
873 xmlNode *cur = n->children;
875 while (cur != NULL)
876 {
877 if (0 == strcmp((char *)cur->name, "value"))
878 {
879 parse_into(s, cur, type, value, 0);
880 return;
881 }
882 cur = cur->next;
883 }
885 server_error(s, "Missing value in Map/Struct");
886 }
889 static void parse_fault(xen_session *session, xmlXPathContextPtr xpathCtx)
890 {
891 xmlXPathObjectPtr xpathObj = xmlXPathCompiledEval(faultPath, xpathCtx);
892 if (xpathObj == NULL)
893 {
894 server_error(session, "Method response is neither result nor fault");
895 return;
896 }
898 if (xpathObj->type != XPATH_NODESET ||
899 xpathObj->nodesetval->nodeNr != 2)
900 {
901 xmlXPathFreeObject(xpathObj);
902 server_error(session, "Method response is neither result nor fault");
903 return;
904 }
906 xmlNode *fault_node0 = xpathObj->nodesetval->nodeTab[0];
907 xmlNode *fault_node1 = xpathObj->nodesetval->nodeTab[1];
909 xmlChar *fault_code_str = string_from_value(fault_node0, "int");
910 if (fault_code_str == NULL)
911 {
912 fault_code_str = string_from_value(fault_node0, "i4");
913 }
914 if (fault_code_str == NULL)
915 {
916 xmlXPathFreeObject(xpathObj);
917 server_error(session, "Fault code is malformed");
918 return;
919 }
921 xmlChar *fault_string_str = string_from_value(fault_node1, "string");
922 if (fault_string_str == NULL)
923 {
924 xmlFree(fault_code_str);
925 xmlXPathFreeObject(xpathObj);
926 server_error(session, "Fault string is malformed");
927 return;
928 }
930 char **strings = malloc(3 * sizeof(char *));
932 strings[0] = xen_strdup_("FAULT");
933 strings[1] = xen_strdup_((char *)fault_code_str);
934 strings[2] = xen_strdup_((char *)fault_string_str);
936 session->ok = false;
937 session->error_description = strings;
938 session->error_description_count = 3;
940 xmlFree(fault_code_str);
941 xmlFree(fault_string_str);
942 xmlXPathFreeObject(xpathObj);
943 }
946 static void parse_failure(xen_session *session, xmlNode *node)
947 {
948 abstract_type error_description_type =
949 { .typename = SET,
950 .child = &abstract_type_string };
951 arbitrary_set *error_descriptions;
953 parse_into(session, node, &error_description_type, &error_descriptions,
954 0);
956 if (session->ok)
957 {
958 session->ok = false;
960 char **c = (char **)error_descriptions->contents;
961 int n = error_descriptions->size;
963 char **strings = malloc(3 * sizeof(char *));
964 for (int i = 0; i < n; i++)
965 {
966 strings[i] = xen_strdup_(c[i]);
967 }
969 session->error_description_count = n;
970 session->error_description = strings;
971 }
973 free(error_descriptions);
974 }
977 /**
978 * Parameters as for xen_call_() above.
979 */
980 static void parse_result(xen_session *session, const char *result,
981 const abstract_type *result_type, void *value)
982 {
983 xmlDocPtr doc =
984 xmlReadMemory(result, strlen(result), "", NULL, XML_PARSE_NONET);
986 if (doc == NULL)
987 {
988 server_error(session, "Couldn't parse the server response");
989 return;
990 }
992 xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
993 if (xpathCtx == NULL)
994 {
995 xmlFreeDoc(doc);
996 server_error(session, "Couldn't create XPath context");
997 return;
998 }
1000 xmlXPathObjectPtr xpathObj =
1001 xmlXPathCompiledEval(responsePath, xpathCtx);
1002 if (xpathObj == NULL)
1004 parse_fault(session, xpathCtx);
1006 xmlXPathFreeContext(xpathCtx);
1007 xmlFreeDoc(doc);
1008 return;
1011 if (xpathObj->type != XPATH_NODESET ||
1012 xpathObj->nodesetval->nodeNr != 2)
1014 parse_fault(session, xpathCtx);
1016 xmlXPathFreeObject(xpathObj);
1017 xmlXPathFreeContext(xpathCtx);
1018 xmlFreeDoc(doc);
1019 return;
1022 xmlNode *node0 = xpathObj->nodesetval->nodeTab[0];
1023 xmlNode *node1 = xpathObj->nodesetval->nodeTab[1];
1025 xmlChar *status_code = string_from_value(node0, "string");
1026 if (status_code == NULL)
1028 xmlXPathFreeObject(xpathObj);
1029 xmlXPathFreeContext(xpathCtx);
1030 xmlFreeDoc(doc);
1031 server_error(session, "Server response does not have a Status");
1032 return;
1035 if (strcmp((char *)status_code, "Success"))
1037 parse_failure(session, node1);
1039 xmlFree(status_code);
1040 xmlXPathFreeObject(xpathObj);
1041 xmlXPathFreeContext(xpathCtx);
1042 xmlFreeDoc(doc);
1043 return;
1046 parse_into(session, node1, result_type, value, 0);
1048 xmlFree(status_code);
1049 xmlXPathFreeObject(xpathObj);
1050 xmlXPathFreeContext(xpathCtx);
1051 xmlFreeDoc(doc);
1055 static char *
1056 make_body(const char *method_name, abstract_value params[], int param_count)
1058 char buf[20];
1060 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
1061 xmlNode *methodCall = xmlNewNode(NULL, BAD_CAST "methodCall");
1062 xmlDocSetRootElement(doc, methodCall);
1064 xmlNewChild(methodCall, NULL, BAD_CAST "methodName",
1065 BAD_CAST method_name);
1067 xmlNode *params_node =
1068 xmlNewChild(methodCall, NULL, BAD_CAST "params", NULL);
1070 for (int p = 0; p < param_count; p++)
1072 abstract_value *v = params + p;
1073 switch (v->type->typename)
1075 case STRING:
1076 add_param(params_node, "string", v->u.string_val);
1077 break;
1079 case INT:
1080 snprintf(buf, sizeof(buf), "%"PRId64, v->u.int_val);
1081 add_param(params_node, "string", buf);
1082 break;
1084 case FLOAT:
1085 snprintf(buf, sizeof(buf), "%lf", v->u.float_val);
1086 add_param(params_node, "double", buf);
1087 break;
1089 case BOOL:
1090 add_param(params_node, "boolean", v->u.bool_val ? "1" : "0");
1091 break;
1093 case VOID:
1094 add_param(params_node, "string", "");
1095 break;
1097 case ENUM:
1098 add_param(params_node, "string",
1099 v->type->enum_marshaller(v->u.enum_val));
1100 break;
1102 case STRUCT:
1104 size_t member_count = v->type->member_count;
1106 xmlNode *struct_node = add_param_struct(params_node);
1108 for (size_t i = 0; i < member_count; i++)
1110 const struct struct_member *mem = v->type->members + i;
1111 const char *key = mem->key;
1112 void *struct_value = v->u.struct_val;
1114 add_struct_value(mem->type, struct_value + mem->offset,
1115 add_struct_member, key, struct_node);
1118 break;
1120 default:
1121 assert(false);
1125 xmlBufferPtr buffer = xmlBufferCreate();
1126 xmlSaveCtxtPtr save_ctxt =
1127 xmlSaveToBuffer(buffer, NULL, XML_SAVE_NO_XHTML);
1129 if (xmlSaveDoc(save_ctxt, doc) == -1)
1131 return NULL;
1134 xmlFreeDoc(doc);
1135 xmlSaveClose(save_ctxt);
1136 xmlChar *content = xmlStrdup(xmlBufferContent(buffer));
1137 xmlBufferFree(buffer);
1138 return (char *)content;
1142 static void
1143 add_struct_value(const struct abstract_type *type, void *value,
1144 void (*adder)(xmlNode *node, const char *key,
1145 const char *type, const char *val),
1146 const char *key, xmlNode *node)
1148 char buf[20];
1150 switch (type->typename)
1152 case REF:
1154 arbitrary_record_opt *val = *(arbitrary_record_opt **)value;
1155 if (val != NULL)
1157 if (val->is_record)
1159 adder(node, key, "string", val->u.record->handle);
1161 else
1163 adder(node, key, "string", val->u.handle);
1167 break;
1169 case STRING:
1171 char *val = *(char **)value;
1172 if (val != NULL)
1174 adder(node, key, "string", val);
1177 break;
1179 case INT:
1181 int64_t val = *(int64_t *)value;
1182 snprintf(buf, sizeof(buf), "%"PRId64, val);
1183 adder(node, key, "string", buf);
1185 break;
1187 case FLOAT:
1189 double val = *(double *)value;
1190 snprintf(buf, sizeof(buf), "%lf", val);
1191 adder(node, key, "double", buf);
1193 break;
1195 case BOOL:
1197 bool val = *(bool *)value;
1198 adder(node, key, "boolean", val ? "1" : "0");
1200 break;
1202 case ENUM:
1204 int val = *(int *)value;
1205 adder(node, key, "string", type->enum_marshaller(val));
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 = set_val->contents + (i * member_size);
1222 add_struct_value(member_type, member_value,
1223 add_unnamed_value, NULL, data_node);
1227 break;
1229 case STRUCT:
1230 case MAP:
1232 /* XXX Nested structures aren't supported yet, but
1233 fortunately we don't need them, because we don't have
1234 any "deep create" calls. This will need to be
1235 fixed. We don't need maps either. */
1237 break;
1239 default:
1240 assert(false);
1245 static xmlNode *
1246 add_container(xmlNode *parent, const char *name)
1248 return xmlNewChild(parent, NULL, BAD_CAST name, NULL);
1252 static void
1253 add_param(xmlNode *params_node, const char *type, const char *value)
1255 xmlNode *param_node = add_container(params_node, "param");
1256 add_value(param_node, type, value);
1260 static void
1261 add_value(xmlNode *parent, const char *type, const char *value)
1263 xmlNode *value_node = add_container(parent, "value");
1264 xmlNewChild(value_node, NULL, BAD_CAST type, BAD_CAST value);
1268 static void
1269 add_unnamed_value(xmlNode *parent, const char *name, const char *type,
1270 const char *value)
1272 (void)name;
1273 add_value(parent, type, value);
1277 static xmlNode *
1278 add_param_struct(xmlNode *params_node)
1280 xmlNode *param_node = add_container(params_node, "param");
1281 xmlNode *value_node = add_container(param_node, "value");
1283 return xmlNewChild(value_node, NULL, BAD_CAST "struct", NULL);
1287 static void
1288 add_struct_member(xmlNode *struct_node, const char *name, const char *type,
1289 const char *value)
1291 xmlNode *member_node = add_container(struct_node, "member");
1293 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1295 add_value(member_node, type, value);
1299 static xmlNode *
1300 add_struct_array(xmlNode *struct_node, const char *name)
1302 xmlNode *member_node = add_container(struct_node, "member");
1304 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1306 xmlNode *value_node = add_container(member_node, "value");
1307 xmlNode *array_node = add_container(value_node, "array");
1309 return add_container(array_node, "data");
1314 int xen_enum_lookup_(xen_session *session, const char *str,
1315 const char **lookup_table, int n)
1317 if (str != NULL)
1319 for (int i = 0; i < n; i++)
1321 if (0 == strcmp(str, lookup_table[i]))
1323 return i;
1328 server_error_2(session, "Bad enum string", str);
1329 return 0;
1333 char *
1334 xen_strdup_(const char *in)
1336 char *result = malloc(strlen(in) + 1);
1337 strcpy(result, in);
1338 return result;
1342 const abstract_type abstract_type_string = { .typename = STRING };
1343 const abstract_type abstract_type_int = { .typename = INT };
1344 const abstract_type abstract_type_float = { .typename = FLOAT };
1345 const abstract_type abstract_type_bool = { .typename = BOOL };
1346 const abstract_type abstract_type_datetime = { .typename = DATETIME };
1347 const abstract_type abstract_type_ref = { .typename = REF };
1349 const abstract_type abstract_type_string_set =
1351 .typename = SET,
1352 .child = &abstract_type_string
1353 };
1355 const abstract_type abstract_type_ref_set =
1357 .typename = SET,
1358 .child = &abstract_type_ref
1359 };
1361 static const struct struct_member string_string_members[] =
1364 .type = &abstract_type_string,
1365 .offset = offsetof(xen_string_string_map_contents, key)
1366 },
1368 .type = &abstract_type_string,
1369 .offset = offsetof(xen_string_string_map_contents, val)
1371 };
1372 const abstract_type abstract_type_string_string_map =
1374 .typename = MAP,
1375 .struct_size = sizeof(xen_string_string_map_contents),
1376 .members = string_string_members
1377 };
1379 static struct struct_member int_float_members[] =
1382 .type = &abstract_type_int,
1383 .offset = offsetof(xen_int_float_map_contents, key)
1384 },
1386 .type = &abstract_type_float,
1387 .offset = offsetof(xen_int_float_map_contents, val)
1389 };
1390 const abstract_type abstract_type_int_float_map =
1392 .typename = MAP,
1393 .struct_size = sizeof(xen_int_float_map_contents),
1394 .members = int_float_members
1395 };