ia64/xen-unstable

view tools/libxen/src/xen_common.c @ 19264:ae58b4403cae

libxen: fix a problem preventing use of xen_event_register().

The conversion of input parameter xen_string_set to XML format creates
a XML "struct" tag instead of "array". The patch sets the XML tag for
SET now to "array".

Signed-off-by: Lutz Dube <Lutz.Dube@fujitsu-siemens.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 03 11:41:15 2009 +0000 (2009-03-03)
parents 2d9a8a4d7e73
children
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 #define _XOPEN_SOURCE
20 #include <assert.h>
21 #include <stdarg.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
28 #include <libxml/parser.h>
29 #include <libxml/tree.h>
30 #include <libxml/xmlsave.h>
31 #include <libxml/xmlstring.h>
32 #include <libxml/xpath.h>
34 #include "xen/api/xen_common.h"
35 #include "xen/api/xen_host.h"
36 #include "xen_internal.h"
37 #include "xen/api/xen_int_float_map.h"
38 #include "xen/api/xen_int_int_map.h"
39 #include "xen/api/xen_int_string_set_map.h"
40 #include "xen/api/xen_string_string_map.h"
43 /*
44 * Whether to ignore missing structure entries. This is not something we
45 * want to do, once the API has stabilised, as it indicates that the server is
46 * broken, but at the moment, complaining is just slowing development down.
47 */
48 #define PERMISSIVE 1
51 static xmlXPathCompExprPtr responsePath = NULL;
52 static xmlXPathCompExprPtr faultPath = NULL;
55 typedef struct
56 {
57 size_t size;
58 void *contents[];
59 } arbitrary_map;
62 typedef struct
63 {
64 void *handle;
65 } arbitrary_record;
68 typedef struct
69 {
70 bool is_record;
71 union
72 {
73 char *handle;
74 arbitrary_record *record;
75 } u;
76 } arbitrary_record_opt;
79 static char *
80 make_body(const char *, abstract_value [], int);
82 static void
83 parse_result(xen_session *, const char *, const abstract_type *, void *);
85 static void
86 add_value(xmlNode *, const char *, const char *);
87 static void
88 add_param(xmlNode *, const char *, const char *);
90 static xmlNode *
91 add_param_struct(xmlNode *);
92 static xmlNode *
93 add_param_array(xmlNode *);
94 static xmlNode *
95 add_struct_array(xmlNode *, const char *);
96 static xmlNode *
97 add_nested_struct(xmlNode *, const char *);
98 static void
99 add_struct_member(xmlNode *, const char *, const char *, const char *);
100 static void
101 add_unnamed_value(xmlNode *, const char *, const char *, const char *);
103 static void
104 add_struct_value(const struct abstract_type *, void *,
105 void (*)(xmlNode *, const char *, const char *,
106 const char *),
107 const char *, xmlNode *);
109 static xmlNode *
110 add_container(xmlNode *parent, const char *name);
112 static void
113 call_raw(xen_session *, const char *, abstract_value [], int,
114 const abstract_type *, void *);
116 static void
117 parse_structmap_value(xen_session *, xmlNode *, const abstract_type *,
118 void *);
120 static size_t size_of_member(const abstract_type *);
122 static const char *
123 get_val_as_string(const struct abstract_type *, void *, char *, size_t);
126 void
127 xen_init(void)
128 {
129 responsePath =
130 xmlXPathCompile(
131 BAD_CAST(
132 "/methodResponse/params/param/value/struct/member/value"));
133 faultPath =
134 xmlXPathCompile(
135 BAD_CAST("/methodResponse/fault/value/struct/member/value"));
136 }
139 void
140 xen_fini(void)
141 {
142 xmlXPathFreeCompExpr(responsePath);
143 xmlXPathFreeCompExpr(faultPath);
144 responsePath = NULL;
145 faultPath = NULL;
146 }
149 void
150 xen_session_record_free(xen_session_record *record)
151 {
152 if (record == NULL)
153 {
154 return;
155 }
156 free(record->uuid);
157 xen_host_record_opt_free(record->this_host);
158 free(record->this_user);
159 free(record);
160 }
163 xen_session *
164 xen_session_login_with_password(xen_call_func call_func, void *handle,
165 const char *uname, const char *pwd)
166 {
167 abstract_value params[] =
168 {
169 { .type = &abstract_type_string,
170 .u.string_val = uname },
171 { .type = &abstract_type_string,
172 .u.string_val = pwd }
173 };
175 xen_session *session = malloc(sizeof(xen_session));
176 session->call_func = call_func;
177 session->handle = handle;
178 session->session_id = NULL;
179 session->ok = true;
180 session->error_description = NULL;
181 session->error_description_count = 0;
183 call_raw(session, "session.login_with_password", params, 2,
184 &abstract_type_string, &session->session_id);
186 return session;
187 }
190 void
191 xen_session_logout(xen_session *session)
192 {
193 abstract_value params[] =
194 {
195 };
196 xen_call_(session, "session.logout", params, 0, NULL, NULL);
198 if (session->error_description != NULL)
199 {
200 for (int i = 0; i < session->error_description_count; i++)
201 {
202 free(session->error_description[i]);
203 }
204 free(session->error_description);
205 }
207 free((char *)session->session_id);
208 free(session);
209 }
212 void
213 xen_session_clear_error(xen_session *session)
214 {
215 if (session->error_description != NULL)
216 {
217 for (int i = 0; i < session->error_description_count; i++)
218 {
219 free(session->error_description[i]);
220 }
221 free(session->error_description);
222 }
223 session->error_description = NULL;
224 session->error_description_count = 0;
225 session->ok = true;
226 }
229 bool
230 xen_session_get_uuid(xen_session *session, char **result,
231 xen_session *self_session)
232 {
233 abstract_value params[] =
234 {
235 { .type = &abstract_type_string,
236 .u.string_val = self_session->session_id }
237 };
239 xen_call_(session, "session.get_uuid", params, 1,
240 &abstract_type_string, result);
241 return session->ok;
242 }
245 bool
246 xen_session_get_this_host(xen_session *session, xen_host *result,
247 xen_session *self_session)
248 {
249 abstract_value params[] =
250 {
251 { .type = &abstract_type_string,
252 .u.string_val = self_session->session_id }
253 };
255 xen_call_(session, "session.get_this_host", params, 1,
256 &abstract_type_string, result);
257 return session->ok;
258 }
261 bool
262 xen_session_get_this_user(xen_session *session, char **result,
263 xen_session *self_session)
264 {
265 abstract_value params[] =
266 {
267 { .type = &abstract_type_string,
268 .u.string_val = self_session->session_id }
269 };
271 xen_call_(session, "session.get_this_user", params, 1,
272 &abstract_type_string, result);
273 return session->ok;
274 }
277 bool
278 xen_session_get_last_active(xen_session *session, time_t *result,
279 xen_session *self_session)
280 {
281 abstract_value params[] =
282 {
283 { .type = &abstract_type_string,
284 .u.string_val = self_session->session_id }
285 };
287 xen_call_(session, "session.get_last_active", params, 1,
288 &abstract_type_datetime, result);
289 return session->ok;
290 }
293 static const struct_member xen_session_record_struct_members[] =
294 {
295 { .key = "uuid",
296 .type = &abstract_type_string,
297 .offset = offsetof(xen_session_record, uuid) },
298 { .key = "this_host",
299 .type = &abstract_type_ref,
300 .offset = offsetof(xen_session_record, this_host) },
301 { .key = "this_user",
302 .type = &abstract_type_string,
303 .offset = offsetof(xen_session_record, this_user) },
304 { .key = "last_active",
305 .type = &abstract_type_datetime,
306 .offset = offsetof(xen_session_record, last_active) },
307 };
309 const abstract_type xen_session_record_abstract_type_ =
310 {
311 .typename = STRUCT,
312 .struct_size = sizeof(xen_session_record),
313 .member_count =
314 sizeof(xen_session_record_struct_members) / sizeof(struct_member),
315 .members = xen_session_record_struct_members
316 };
319 bool
320 xen_session_get_record(xen_session *session, xen_session_record **result,
321 xen_session *self_session)
322 {
323 abstract_value param_values[] =
324 {
325 { .type = &abstract_type_string,
326 .u.string_val = self_session->session_id }
327 };
329 abstract_type result_type = xen_session_record_abstract_type_;
331 *result = NULL;
332 XEN_CALL_("session.get_record");
334 return session->ok;
335 }
338 #define X "%02x"
339 #define UUID_FORMAT X X X X "-" X X "-" X X "-" X X "-" X X X X X X
342 bool
343 xen_uuid_string_to_bytes(char *uuid, char **bytes)
344 {
345 unsigned int buf[16];
347 *bytes = NULL;
349 if (strlen(uuid) != 36)
350 return false;
352 if (16 != sscanf(uuid, UUID_FORMAT,
353 buf + 0, buf + 1, buf + 2, buf + 3,
354 buf + 4, buf + 5,
355 buf + 6, buf + 7,
356 buf + 8, buf + 9,
357 buf + 10, buf + 11, buf + 12, buf + 13, buf + 14,
358 buf + 15))
359 {
360 return false;
361 }
363 *bytes = malloc(16);
364 if (*bytes == NULL)
365 return false;
367 for (int i = 0; i < 16; i++) {
368 (*bytes)[i] = (char)buf[i];
369 }
371 return true;
372 }
375 bool
376 xen_uuid_bytes_to_string(char *bytes, char **uuid)
377 {
378 *uuid = malloc(37);
379 if (*uuid == NULL)
380 return false;
382 sprintf(*uuid, UUID_FORMAT,
383 bytes[0], bytes[1], bytes[2], bytes[3],
384 bytes[4], bytes[5],
385 bytes[6], bytes[7],
386 bytes[8], bytes[9],
387 bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]);
389 return true;
390 }
393 #undef UUID_FORMAT
394 #undef X
397 void
398 xen_uuid_free(char *uuid)
399 {
400 free(uuid);
401 }
404 void
405 xen_uuid_bytes_free(char *bytes)
406 {
407 free(bytes);
408 }
411 /**
412 * @param value A pointer to the correct location as per the given
413 * result_type. Will be populated if the call succeeds. In that case, and if
414 * value is a char **, the char * itself must be freed by the caller.
415 */
416 void
417 xen_call_(xen_session *s, const char *method_name,
418 abstract_value params[], int param_count,
419 const abstract_type *result_type, void *value)
420 {
421 abstract_value *full_params;
422 if (!s->ok)
423 {
424 return;
425 }
427 full_params = malloc(sizeof(abstract_value) * (param_count + 1));
429 full_params[0].type = &abstract_type_string;
430 full_params[0].u.string_val = s->session_id;
432 memcpy(full_params + 1, params, param_count * sizeof(abstract_value));
434 call_raw(s, method_name, full_params, param_count + 1, result_type,
435 value);
437 free(full_params);
438 }
441 static bool
442 bufferAdd(const void *data, size_t len, void *buffer)
443 {
444 return 0 == xmlBufferAdd((xmlBufferPtr)buffer, data, len);
445 }
448 static void
449 call_raw(xen_session *s, const char *method_name,
450 abstract_value params[], int param_count,
451 const abstract_type *result_type, void *value)
452 {
453 xmlBufferPtr buffer = xmlBufferCreate();
454 char *body = make_body(method_name, params, param_count);
455 int error_code =
456 s->call_func(body, strlen(body), s->handle, buffer, &bufferAdd);
457 free(body);
458 if (error_code)
459 {
460 char **strings = malloc(2 * sizeof(char *));
462 strings[0] = xen_strdup_("TRANSPORT_FAULT");
463 strings[1] = malloc(20);
464 snprintf(strings[1], 20, "%d", error_code);
466 s->ok = false;
467 s->error_description = strings;
468 s->error_description_count = 2;
469 }
470 else
471 {
472 parse_result(s, (char *)xmlBufferContent(buffer), result_type, value);
473 }
474 xmlBufferFree(buffer);
475 }
478 static void server_error(xen_session *session, const char *error_string)
479 {
480 char **strings;
481 if (!session->ok)
482 {
483 /* Don't wipe out the earlier error message with this one. */
484 return;
485 }
487 strings = malloc(2 * sizeof(char *));
489 strings[0] = xen_strdup_("SERVER_FAULT");
490 strings[1] = xen_strdup_(error_string);
492 session->ok = false;
493 session->error_description = strings;
494 session->error_description_count = 2;
495 }
498 static void server_error_2(xen_session *session, const char *error_string,
499 const char *param)
500 {
501 char **strings;
502 if (!session->ok)
503 {
504 /* Don't wipe out the earlier error message with this one. */
505 return;
506 }
508 strings = malloc(3 * sizeof(char *));
510 strings[0] = xen_strdup_("SERVER_FAULT_2");
511 strings[1] = xen_strdup_(error_string);
512 strings[2] = xen_strdup_(param);
514 session->ok = false;
515 session->error_description = strings;
516 session->error_description_count = 3;
517 }
520 static bool is_node(xmlNode *n, char *type)
521 {
522 return
523 n->type == XML_ELEMENT_NODE &&
524 0 == strcmp((char *)n->name, type);
525 }
528 static bool is_container_node(xmlNode *n, char *type)
529 {
530 return
531 is_node(n, type) &&
532 n->children != NULL &&
533 n->children == n->last &&
534 n->children->type == XML_ELEMENT_NODE;
535 }
538 /**
539 * @return The contents of the given value, or NULL if this is not a node with
540 * the given type. If not NULL, the result must be freed with xmlFree().
541 */
542 static xmlChar *string_from_value(xmlNode *n, char *type)
543 {
544 /*
545 <value><type>XYZ</type></value> is normal, but the XML-RPC spec also
546 allows <value>XYZ</value> where XYZ is to be interpreted as a string.
547 */
549 if (is_container_node(n, "value") &&
550 0 == strcmp((char *)n->children->name, type))
551 {
552 return
553 n->children->children == NULL ?
554 xmlStrdup(BAD_CAST("")) :
555 xmlNodeGetContent(n->children->children);
556 }
557 else if (0 == strcmp(type, "string") && is_node(n, "value"))
558 {
559 return
560 n->children == NULL ?
561 xmlStrdup(BAD_CAST("")) :
562 xmlNodeGetContent(n->children);
563 }
564 else
565 {
566 return NULL;
567 }
568 }
571 /**
572 * Find the name node that is a child of the given one, and return its
573 * contents, or NULL if this has no such node. If not NULL, the result must
574 * be freed with xmlFree().
575 */
576 static xmlChar *string_from_name(xmlNode *n)
577 {
578 xmlNode *cur = n->children;
580 while (cur != NULL)
581 {
582 if (0 == strcmp((char *)cur->name, "name"))
583 {
584 return xmlNodeGetContent(cur);
585 }
586 cur = cur->next;
587 }
589 return NULL;
590 }
593 static int count_children(xmlNode *n, const char *name)
594 {
595 int result = 0;
596 xmlNode *cur = n->children;
598 while (cur != NULL)
599 {
600 if (0 == strcmp((char *)cur->name, name))
601 {
602 result++;
603 }
604 cur = cur->next;
605 }
607 return result;
608 }
611 static void destring(xen_session *s, xmlChar *name, const abstract_type *type,
612 void *value)
613 {
614 switch (type->typename)
615 {
616 case STRING:
617 *((char **)value) = xen_strdup_((const char *)name);
618 break;
620 case INT:
621 *((int64_t *)value) = atoll((const char *)name);
622 break;
624 case FLOAT:
625 *((double *)value) = atof((const char *)name);
626 break;
628 default:
629 server_error(s, "Invalid Map key type");
630 }
631 }
634 /**
635 * result_type : STRING => value : char **, the char * is yours.
636 * result_type : ENUM => value : int *
637 * result_type : INT => value : int64_t *
638 * result_type : FLOAT => value : double *
639 * result_type : BOOL => value : bool *
640 * result_type : DATETIME => value : time_t *
641 * result_type : SET => value : arbitrary_set **, the set is yours.
642 * result_type : MAP => value : arbitrary_map **, the map is yours.
643 * result_type : OPT => value : arbitrary_record_opt **,
644 * the record is yours, the handle is
645 * filled.
646 * result_type : STRUCT => value : void **, the void * is yours.
647 */
648 static void parse_into(xen_session *s, xmlNode *value_node,
649 const abstract_type *result_type, void *value,
650 int slot)
651 {
652 if (result_type == NULL)
653 {
654 xmlChar *string = string_from_value(value_node, "string");
655 if (string == NULL || strcmp((char *)string, ""))
656 {
657 server_error(s,
658 "Expected Void from the server, but didn't get it");
659 }
660 else
661 {
662 free(string);
663 }
665 return;
666 }
668 switch (result_type->typename)
669 {
670 case STRING:
671 {
672 xmlChar *string = string_from_value(value_node, "string");
673 if (string == NULL)
674 {
675 server_error(
676 s, "Expected a String from the server, but didn't get one");
677 }
678 else
679 {
680 ((char **)value)[slot] = xen_strdup_((const char *)string);
681 free(string);
682 }
683 }
684 break;
686 case ENUM:
687 {
688 xmlChar *string = string_from_value(value_node, "string");
689 if (string == NULL)
690 {
691 #if PERMISSIVE
692 fprintf(stderr,
693 "Expected an Enum from the server, but didn't get one\n");
694 ((int *)value)[slot] = 0;
695 #else
696 server_error(
697 s, "Expected an Enum from the server, but didn't get one");
698 #endif
699 }
700 else
701 {
702 ((int *)value)[slot] =
703 result_type->enum_demarshaller(s, (const char *)string);
704 free(string);
705 }
706 }
707 break;
709 case INT:
710 {
711 xmlChar *string = string_from_value(value_node, "string");
712 if (string == NULL)
713 {
714 server_error(
715 s, "Expected an Int from the server, but didn't get one");
716 }
717 else
718 {
719 ((int64_t *)value)[slot] = (int64_t)atoll((char *)string);
720 free(string);
721 }
722 }
723 break;
725 case FLOAT:
726 {
727 xmlChar *string = string_from_value(value_node, "double");
728 if (string == NULL)
729 {
730 #if PERMISSIVE
731 fprintf(stderr,
732 "Expected a Float from the server, but didn't get one\n");
733 ((double *)value)[slot] = 0.0;
734 #else
735 server_error(
736 s, "Expected a Float from the server, but didn't get one");
737 #endif
738 }
739 else
740 {
741 ((double *)value)[slot] = atof((char *)string);
742 free(string);
743 }
744 }
745 break;
747 case BOOL:
748 {
749 xmlChar *string = string_from_value(value_node, "boolean");
750 if (string == NULL)
751 {
752 #if PERMISSIVE
753 fprintf(stderr,
754 "Expected a Bool from the server, but didn't get one\n");
755 ((bool *)value)[slot] = false;
756 #else
757 server_error(
758 s, "Expected a Bool from the server, but didn't get one");
759 #endif
760 }
761 else
762 {
763 ((bool *)value)[slot] = (0 == strcmp((char *)string, "1"));
764 free(string);
765 }
766 }
767 break;
769 case DATETIME:
770 {
771 xmlChar *string = string_from_value(value_node, "dateTime.iso8601");
772 if (string == NULL)
773 {
774 server_error(
775 s, "Expected an DateTime from the server but didn't get one");
776 }
777 else
778 {
779 struct tm tm;
780 memset(&tm, 0, sizeof(tm));
781 strptime((char *)string, "%Y%m%dT%H:%M:%S", &tm);
782 ((time_t *)value)[slot] = (time_t)mktime(&tm);
783 free(string);
784 }
785 }
786 break;
788 case SET:
789 {
790 if (!is_container_node(value_node, "value") ||
791 !is_container_node(value_node->children, "array"))
792 {
793 server_error(s,
794 "Expected Set from the server, but didn't get it");
795 }
796 else
797 {
798 arbitrary_set *set;
799 xmlNode *cur, *data_node = value_node->children->children;
800 int i, n = count_children(data_node, "value");
802 const abstract_type *member_type = result_type->child;
803 size_t member_size = size_of_member(member_type);
805 set = calloc(1, sizeof(arbitrary_set) + member_size * n);
806 set->size = n;
807 i = 0;
808 cur = data_node->children;
810 while (cur != NULL)
811 {
812 if (0 == strcmp((char *)cur->name, "value"))
813 {
814 parse_into(s, cur, member_type, set->contents, i);
815 i++;
816 }
817 cur = cur->next;
818 }
820 ((arbitrary_set **)value)[slot] = set;
821 }
822 }
823 break;
825 case MAP:
826 {
827 if (!is_container_node(value_node, "value") ||
828 value_node->children->type != XML_ELEMENT_NODE ||
829 0 != strcmp((char *)value_node->children->name, "struct"))
830 {
831 server_error(s,
832 "Expected Map from the server, but didn't get it");
833 }
834 else
835 {
836 arbitrary_map *map;
837 xmlNode *cur, *struct_node = value_node->children;
838 int i, n = count_children(struct_node, "member");
840 size_t struct_size = result_type->struct_size;
842 const struct struct_member *key_member = result_type->members;
843 const struct struct_member *val_member = result_type->members + 1;
845 map = calloc(1, sizeof(arbitrary_map) + struct_size * n);
846 map->size = n;
847 i = 0;
848 cur = struct_node->children;
850 while (cur != NULL)
851 {
852 if (0 == strcmp((char *)cur->name, "member"))
853 {
854 xmlChar *name;
855 if (cur->children == NULL || cur->last == cur->children)
856 {
857 server_error(s, "Malformed Map");
858 free(map);
859 return;
860 }
862 name = string_from_name(cur);
863 if (name == NULL)
864 {
865 server_error(s, "Malformed Map");
866 free(map);
867 return;
868 }
870 destring(s, name, key_member->type,
871 ((void *)(map + 1)) +
872 (i * struct_size) +
873 key_member->offset);
874 xmlFree(name);
875 if (!s->ok)
876 {
877 free(map);
878 return;
879 }
881 parse_structmap_value(s, cur, val_member->type,
882 ((void *)(map + 1)) +
883 (i * struct_size) +
884 val_member->offset);
885 if (!s->ok)
886 {
887 free(map);
888 return;
889 }
890 i++;
891 }
892 cur = cur->next;
893 }
895 ((arbitrary_map **)value)[slot] = map;
896 }
897 }
898 break;
900 case STRUCT:
901 {
902 if (!is_container_node(value_node, "value") ||
903 value_node->children->type != XML_ELEMENT_NODE ||
904 0 != strcmp((char *)value_node->children->name, "struct") ||
905 value_node->children->children == NULL)
906 {
907 server_error(s,
908 "Expected Map from the server, but didn't get it");
909 }
910 else
911 {
912 xmlNode *struct_node = value_node->children;
914 void *result = calloc(1, result_type->struct_size);
915 xmlNode *cur = struct_node->children;
917 size_t member_count = result_type->member_count;
919 const struct_member **checklist =
920 malloc(sizeof(const struct_member *) * member_count);
921 int seen_count = 0;
923 while (cur != NULL)
924 {
925 if (0 == strcmp((char *)cur->name, "member"))
926 {
927 xmlChar *name;
928 if (cur->children == NULL || cur->last == cur->children)
929 {
930 server_error(s, "Malformed Struct");
931 free(result);
932 free(checklist);
933 return;
934 }
936 name = string_from_name(cur);
937 if (name == NULL)
938 {
939 server_error(s, "Malformed Struct");
940 free(result);
941 free(checklist);
942 return;
943 }
945 for (size_t i = 0; i < member_count; i++)
946 {
947 const struct_member *mem = result_type->members + i;
949 if (0 == strcmp((char *)name, mem->key))
950 {
951 parse_structmap_value(s, cur, mem->type,
952 result + mem->offset);
953 checklist[seen_count] = mem;
954 seen_count++;
955 break;
956 }
957 }
959 /* Note that we're skipping unknown fields implicitly.
960 This means that we'll be forward compatible with
961 new servers. */
963 xmlFree(name);
965 if (!s->ok)
966 {
967 free(result);
968 free(checklist);
969 return;
970 }
971 }
972 cur = cur->next;
973 }
975 /* Check that we've filled all fields. */
976 for (size_t i = 0; i < member_count; i++)
977 {
978 const struct_member *mem = result_type->members + i;
979 int j;
981 for (j = 0; j < seen_count; j++)
982 {
983 if (checklist[j] == mem)
984 {
985 break;
986 }
987 }
989 if (j == seen_count)
990 {
991 #if PERMISSIVE
992 fprintf(stderr,
993 "Struct did not contain expected field %s.\n",
994 mem->key);
995 #else
996 server_error_2(s,
997 "Struct did not contain expected field",
998 mem->key);
999 free(result);
1000 free(checklist);
1001 return;
1002 #endif
1006 free(checklist);
1007 ((void **)value)[slot] = result;
1010 break;
1012 case REF:
1014 arbitrary_record_opt *record_opt =
1015 calloc(1, sizeof(arbitrary_record_opt));
1017 record_opt->is_record = false;
1018 parse_into(s, value_node, &abstract_type_string,
1019 &(record_opt->u.handle), 0);
1021 ((arbitrary_record_opt **)value)[slot] = record_opt;
1023 break;
1025 default:
1026 assert(false);
1031 static size_t size_of_member(const abstract_type *type)
1033 switch (type->typename)
1035 case STRING:
1036 return sizeof(char *);
1038 /*
1039 case INT:
1040 return sizeof(int64_t);
1042 case FLOAT:
1043 return sizeof(double);
1045 case BOOL:
1046 return sizeof(bool);
1047 */
1048 case ENUM:
1049 return sizeof(int);
1051 case REF:
1052 return sizeof(arbitrary_record_opt *);
1054 case STRUCT:
1055 return type->struct_size;
1057 default:
1058 assert(false);
1063 static void parse_structmap_value(xen_session *s, xmlNode *n,
1064 const abstract_type *type, void *value)
1066 xmlNode *cur = n->children;
1068 while (cur != NULL)
1070 if (0 == strcmp((char *)cur->name, "value"))
1072 parse_into(s, cur, type, value, 0);
1073 return;
1075 cur = cur->next;
1078 server_error(s, "Missing value in Map/Struct");
1082 static void parse_fault(xen_session *session, xmlXPathContextPtr xpathCtx)
1084 xmlNode *fault_node0, *fault_node1;
1085 xmlChar *fault_code_str, *fault_string_str;
1086 char **strings;
1088 xmlXPathObjectPtr xpathObj = xmlXPathCompiledEval(faultPath, xpathCtx);
1089 if (xpathObj == NULL)
1091 server_error(session, "Method response is neither result nor fault");
1092 return;
1095 if (xpathObj->type != XPATH_NODESET ||
1096 xpathObj->nodesetval->nodeNr != 2)
1098 xmlXPathFreeObject(xpathObj);
1099 server_error(session, "Method response is neither result nor fault");
1100 return;
1103 fault_node0 = xpathObj->nodesetval->nodeTab[0];
1104 fault_node1 = xpathObj->nodesetval->nodeTab[1];
1106 fault_code_str = string_from_value(fault_node0, "int");
1107 if (fault_code_str == NULL)
1109 fault_code_str = string_from_value(fault_node0, "i4");
1111 if (fault_code_str == NULL)
1113 xmlXPathFreeObject(xpathObj);
1114 server_error(session, "Fault code is malformed");
1115 return;
1118 fault_string_str = string_from_value(fault_node1, "string");
1119 if (fault_string_str == NULL)
1121 xmlFree(fault_code_str);
1122 xmlXPathFreeObject(xpathObj);
1123 server_error(session, "Fault string is malformed");
1124 return;
1127 strings = malloc(3 * sizeof(char *));
1129 strings[0] = xen_strdup_("FAULT");
1130 strings[1] = xen_strdup_((char *)fault_code_str);
1131 strings[2] = xen_strdup_((char *)fault_string_str);
1133 session->ok = false;
1134 session->error_description = strings;
1135 session->error_description_count = 3;
1137 xmlFree(fault_code_str);
1138 xmlFree(fault_string_str);
1139 xmlXPathFreeObject(xpathObj);
1143 static void parse_failure(xen_session *session, xmlNode *node)
1145 abstract_type error_description_type =
1146 { .typename = SET,
1147 .child = &abstract_type_string };
1148 arbitrary_set *error_descriptions;
1150 parse_into(session, node, &error_description_type, &error_descriptions,
1151 0);
1153 if (session->ok)
1155 char **c, **strings;
1156 int n;
1158 session->ok = false;
1160 c = (char **)error_descriptions->contents;
1161 n = error_descriptions->size;
1163 strings = malloc(n * sizeof(char *));
1164 for (int i = 0; i < n; i++)
1166 strings[i] = c[i];
1169 session->error_description_count = n;
1170 session->error_description = strings;
1173 free(error_descriptions);
1177 /**
1178 * Parameters as for xen_call_() above.
1179 */
1180 static void parse_result(xen_session *session, const char *result,
1181 const abstract_type *result_type, void *value)
1183 xmlDocPtr doc =
1184 xmlReadMemory(result, strlen(result), "", NULL, XML_PARSE_NONET);
1185 xmlXPathContextPtr xpathCtx;
1186 xmlXPathObjectPtr xpathObj;
1187 xmlNode *node0, *node1;
1188 xmlChar *status_code;
1190 if (doc == NULL)
1192 server_error(session, "Couldn't parse the server response");
1193 return;
1196 xpathCtx = xmlXPathNewContext(doc);
1197 if (xpathCtx == NULL)
1199 xmlFreeDoc(doc);
1200 server_error(session, "Couldn't create XPath context");
1201 return;
1204 xpathObj = xmlXPathCompiledEval(responsePath, xpathCtx);
1205 if (xpathObj == NULL)
1207 parse_fault(session, xpathCtx);
1209 xmlXPathFreeContext(xpathCtx);
1210 xmlFreeDoc(doc);
1211 return;
1214 if (xpathObj->type != XPATH_NODESET ||
1215 xpathObj->nodesetval->nodeNr != 2)
1217 parse_fault(session, xpathCtx);
1219 xmlXPathFreeObject(xpathObj);
1220 xmlXPathFreeContext(xpathCtx);
1221 xmlFreeDoc(doc);
1222 return;
1225 node0 = xpathObj->nodesetval->nodeTab[0];
1226 node1 = xpathObj->nodesetval->nodeTab[1];
1228 status_code = string_from_value(node0, "string");
1229 if (status_code == NULL)
1231 xmlXPathFreeObject(xpathObj);
1232 xmlXPathFreeContext(xpathCtx);
1233 xmlFreeDoc(doc);
1234 server_error(session, "Server response does not have a Status");
1235 return;
1238 if (strcmp((char *)status_code, "Success"))
1240 parse_failure(session, node1);
1242 xmlFree(status_code);
1243 xmlXPathFreeObject(xpathObj);
1244 xmlXPathFreeContext(xpathCtx);
1245 xmlFreeDoc(doc);
1246 return;
1249 parse_into(session, node1, result_type, value, 0);
1251 xmlFree(status_code);
1252 xmlXPathFreeObject(xpathObj);
1253 xmlXPathFreeContext(xpathCtx);
1254 xmlFreeDoc(doc);
1258 static void
1259 make_body_add_type(enum abstract_typename typename, abstract_value *v,
1260 xmlNode *params_node)
1262 char buf[20];
1263 switch (typename)
1265 case STRING:
1266 add_param(params_node, "string", v->u.string_val);
1267 break;
1269 case INT:
1270 snprintf(buf, sizeof(buf), "%"PRId64, v->u.int_val);
1271 add_param(params_node, "string", buf);
1272 break;
1274 case FLOAT:
1275 snprintf(buf, sizeof(buf), "%lf", v->u.float_val);
1276 add_param(params_node, "double", buf);
1277 break;
1279 case BOOL:
1280 add_param(params_node, "boolean", v->u.bool_val ? "1" : "0");
1281 break;
1283 case VOID:
1284 add_param(params_node, "string", "");
1285 break;
1287 case ENUM:
1288 add_param(params_node, "string",
1289 v->type->enum_marshaller(v->u.enum_val));
1290 break;
1292 case SET:
1294 const struct abstract_type *member_type = v->type->child;
1295 arbitrary_set *set_val = v->u.struct_val;
1296 abstract_value v;
1297 xmlNode *data_node = add_param_array(params_node);
1299 for (size_t i = 0; i < set_val->size; i++)
1301 switch (member_type->typename) {
1302 case STRING:
1303 v.u.string_val = (char *)set_val->contents[i];
1304 make_body_add_type(member_type->typename, &v, data_node);
1305 break;
1306 default:
1307 assert(false);
1311 break;
1313 case STRUCT:
1315 size_t member_count = v->type->member_count;
1317 xmlNode *struct_node = add_param_struct(params_node);
1319 for (size_t i = 0; i < member_count; i++)
1321 const struct struct_member *mem = v->type->members + i;
1322 const char *key = mem->key;
1323 void *struct_value = v->u.struct_val;
1325 add_struct_value(mem->type, struct_value + mem->offset,
1326 add_struct_member, key, struct_node);
1329 break;
1331 case MAP:
1333 const struct struct_member *member = v->type->members;
1334 arbitrary_map *map_val = v->u.struct_val;
1335 xmlNode *param_node = add_param_struct(params_node);
1336 for (size_t i = 0; i < map_val->size; i++) {
1337 enum abstract_typename typename_key = member[0].type->typename;
1338 enum abstract_typename typename_val = member[1].type->typename;
1339 int offset_key = member[0].offset;
1340 int offset_val = member[1].offset;
1341 int struct_size = v->type->struct_size;
1343 switch (typename_key) {
1344 case STRING: {
1345 char **addr = (void *)(map_val + 1) +
1346 (i * struct_size) +
1347 offset_key;
1348 char *key = *addr;
1350 switch (typename_val) {
1351 case STRING: {
1352 char *val;
1353 addr = (void *)(map_val + 1) +
1354 (i * struct_size) +
1355 offset_val;
1356 val = *addr;
1357 add_struct_member(param_node, key, "string", val);
1358 break;
1360 default:
1361 assert(false);
1363 break;
1365 default:
1366 assert(false);
1370 break;
1373 default:
1374 assert(false);
1379 static char *
1380 make_body(const char *method_name, abstract_value params[], int param_count)
1382 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
1383 xmlNode *params_node, *methodCall = xmlNewNode(NULL, BAD_CAST "methodCall");
1384 xmlBufferPtr buffer;
1385 xmlSaveCtxtPtr save_ctxt;
1386 xmlChar *content;
1388 xmlDocSetRootElement(doc, methodCall);
1390 xmlNewChild(methodCall, NULL, BAD_CAST "methodName",
1391 BAD_CAST method_name);
1393 params_node = xmlNewChild(methodCall, NULL, BAD_CAST "params", NULL);
1395 for (int p = 0; p < param_count; p++)
1397 abstract_value *v = params + p;
1398 make_body_add_type(v->type->typename, v, params_node);
1401 buffer = xmlBufferCreate();
1402 save_ctxt = xmlSaveToBuffer(buffer, NULL, XML_SAVE_NO_XHTML);
1404 if (xmlSaveDoc(save_ctxt, doc) == -1)
1406 return NULL;
1409 xmlFreeDoc(doc);
1410 xmlSaveClose(save_ctxt);
1411 content = xmlStrdup(xmlBufferContent(buffer));
1412 xmlBufferFree(buffer);
1413 return (char *)content;
1417 static void
1418 add_struct_value(const struct abstract_type *type, void *value,
1419 void (*adder)(xmlNode *node, const char *key,
1420 const char *type, const char *val),
1421 const char *key, xmlNode *node)
1423 char buf[20];
1425 switch (type->typename)
1427 case REF:
1428 case STRING:
1429 case INT:
1430 case ENUM:
1432 const char *val_as_string =
1433 get_val_as_string(type, value, buf, sizeof(buf));
1434 adder(node, key, "string", val_as_string);
1436 break;
1438 case FLOAT:
1440 double val = *(double *)value;
1441 snprintf(buf, sizeof(buf), "%lf", val);
1442 adder(node, key, "double", buf);
1444 break;
1446 case BOOL:
1448 bool val = *(bool *)value;
1449 adder(node, key, "boolean", val ? "1" : "0");
1451 break;
1453 case SET:
1455 const struct abstract_type *member_type = type->child;
1456 size_t member_size = size_of_member(member_type);
1457 arbitrary_set *set_val = *(arbitrary_set **)value;
1459 if (set_val != NULL)
1461 xmlNode *data_node = add_struct_array(node, key);
1463 for (size_t i = 0; i < set_val->size; i++)
1465 void *member_value = (char *)set_val->contents +
1466 (i * member_size);
1467 add_struct_value(member_type, member_value,
1468 add_unnamed_value, NULL, data_node);
1472 break;
1474 case STRUCT:
1476 assert(false);
1477 /* XXX Nested structures aren't supported yet, but
1478 fortunately we don't need them, because we don't have
1479 any "deep create" calls. This will need to be
1480 fixed. */
1482 break;
1484 case MAP:
1486 size_t member_size = type->struct_size;
1487 const struct abstract_type *l_type = type->members[0].type;
1488 const struct abstract_type *r_type = type->members[1].type;
1489 int l_offset = type->members[0].offset;
1490 int r_offset = type->members[1].offset;
1492 arbitrary_map *map_val = *(arbitrary_map **)value;
1494 if (map_val != NULL)
1496 xmlNode *struct_node = add_nested_struct(node, key);
1498 for (size_t i = 0; i < map_val->size; i++)
1500 void *contents = (void *)map_val->contents;
1501 void *l_value = contents + (i * member_size) + l_offset;
1502 void *r_value = contents + (i * member_size) + r_offset;
1504 const char *l_value_as_string =
1505 get_val_as_string(l_type, l_value, buf, sizeof(buf));
1507 add_struct_value(r_type, r_value, add_struct_member,
1508 l_value_as_string, struct_node);
1512 break;
1514 default:
1515 assert(false);
1520 static const char *
1521 get_val_as_string(const struct abstract_type *type, void *value, char *buf,
1522 size_t bufsize)
1524 switch (type->typename)
1526 case REF:
1528 arbitrary_record_opt *val = *(arbitrary_record_opt **)value;
1529 if (val != NULL)
1531 if (val->is_record)
1533 return val->u.record->handle;
1535 else
1537 return val->u.handle;
1540 else
1542 return NULL;
1545 break;
1547 case STRING:
1549 return *(char **)value;
1551 break;
1553 case INT:
1555 int64_t val = *(int64_t *)value;
1556 snprintf(buf, bufsize, "%"PRId64, val);
1557 return buf;
1559 break;
1561 case ENUM:
1563 int val = *(int *)value;
1564 return type->enum_marshaller(val);
1566 break;
1568 default:
1569 assert(false);
1574 static xmlNode *
1575 add_container(xmlNode *parent, const char *name)
1577 return xmlNewChild(parent, NULL, BAD_CAST name, NULL);
1581 static void
1582 add_param(xmlNode *params_node, const char *type, const char *value)
1584 xmlNode *param_node = add_container(params_node, "param");
1585 add_value(param_node, type, value);
1589 static void
1590 add_value(xmlNode *parent, const char *type, const char *value)
1592 xmlNode *value_node = add_container(parent, "value");
1593 xmlNewChild(value_node, NULL, BAD_CAST type, BAD_CAST value);
1597 static void
1598 add_unnamed_value(xmlNode *parent, const char *name, const char *type,
1599 const char *value)
1601 (void)name;
1602 add_value(parent, type, value);
1606 static xmlNode *
1607 add_param_struct(xmlNode *params_node)
1609 xmlNode *param_node = add_container(params_node, "param");
1610 xmlNode *value_node = add_container(param_node, "value");
1612 return xmlNewChild(value_node, NULL, BAD_CAST "struct", NULL);
1616 static xmlNode *
1617 add_param_array(xmlNode *params_node)
1619 xmlNode *param_node = add_container(params_node, "param");
1620 xmlNode *value_node = add_container(param_node, "value");
1622 return xmlNewChild(value_node, NULL, BAD_CAST "array", NULL);
1626 static void
1627 add_struct_member(xmlNode *struct_node, const char *name, const char *type,
1628 const char *value)
1630 xmlNode *member_node = add_container(struct_node, "member");
1632 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1634 add_value(member_node, type, value);
1638 static xmlNode *
1639 add_struct_array(xmlNode *struct_node, const char *name)
1641 xmlNode *member_node = add_container(struct_node, "member");
1642 xmlNode *value_node, *array_node;
1644 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1646 value_node = add_container(member_node, "value");
1647 array_node = add_container(value_node, "array");
1649 return add_container(array_node, "data");
1653 static xmlNode *
1654 add_nested_struct(xmlNode *struct_node, const char *name)
1656 xmlNode *member_node = add_container(struct_node, "member");
1657 xmlNode *value_node;
1659 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1661 value_node = add_container(member_node, "value");
1663 return add_container(value_node, "struct");
1667 int xen_enum_lookup_(xen_session *session, const char *str,
1668 const char **lookup_table, int n)
1670 if (str != NULL)
1672 for (int i = 0; i < n; i++)
1674 if (0 == strcmp(str, lookup_table[i]))
1676 return i;
1681 server_error_2(session, "Bad enum string", str);
1682 return 0;
1686 char *
1687 xen_strdup_(const char *in)
1689 char *result = malloc(strlen(in) + 1);
1690 strcpy(result, in);
1691 return result;
1695 const abstract_type abstract_type_string = { .typename = STRING };
1696 const abstract_type abstract_type_int = { .typename = INT };
1697 const abstract_type abstract_type_float = { .typename = FLOAT };
1698 const abstract_type abstract_type_bool = { .typename = BOOL };
1699 const abstract_type abstract_type_datetime = { .typename = DATETIME };
1700 const abstract_type abstract_type_ref = { .typename = REF };
1702 const abstract_type abstract_type_string_set =
1704 .typename = SET,
1705 .child = &abstract_type_string
1706 };
1708 const abstract_type abstract_type_ref_set =
1710 .typename = SET,
1711 .child = &abstract_type_ref
1712 };
1714 static const struct struct_member string_string_members[] =
1717 .type = &abstract_type_string,
1718 .offset = offsetof(xen_string_string_map_contents, key)
1719 },
1721 .type = &abstract_type_string,
1722 .offset = offsetof(xen_string_string_map_contents, val)
1724 };
1725 const abstract_type abstract_type_string_string_map =
1727 .typename = MAP,
1728 .struct_size = sizeof(xen_string_string_map_contents),
1729 .members = string_string_members
1730 };
1732 static struct struct_member int_float_members[] =
1735 .type = &abstract_type_int,
1736 .offset = offsetof(xen_int_float_map_contents, key)
1737 },
1739 .type = &abstract_type_float,
1740 .offset = offsetof(xen_int_float_map_contents, val)
1742 };
1743 const abstract_type abstract_type_int_float_map =
1745 .typename = MAP,
1746 .struct_size = sizeof(xen_int_float_map_contents),
1747 .members = int_float_members
1748 };
1750 static struct struct_member int_int_members[] =
1753 .type = &abstract_type_int,
1754 .offset = offsetof(xen_int_int_map_contents, key)
1755 },
1757 .type = &abstract_type_int,
1758 .offset = offsetof(xen_int_int_map_contents, val)
1760 };
1761 const abstract_type abstract_type_int_int_map =
1763 .typename = MAP,
1764 .struct_size = sizeof(xen_int_int_map_contents),
1765 .members = int_int_members
1766 };
1768 static struct struct_member int_string_set_members[] =
1771 .type = &abstract_type_int,
1772 .offset = offsetof(xen_int_string_set_map_contents, key)
1773 },
1775 .type = &abstract_type_string_set,
1776 .offset = offsetof(xen_int_string_set_map_contents, val)
1778 };
1779 const abstract_type abstract_type_int_string_set_map =
1781 .typename = MAP,
1782 .struct_size = sizeof(xen_int_string_set_map_contents),
1783 .members = int_string_set_members
1784 };