ia64/xen-unstable

view tools/libxen/src/xen_common.c @ 16738:2d9a8a4d7e73

libxen: Avoid declarations-after-statement (C++ coding style).
Signed-off-by: Andre Przywara <andre.przywara@amd.com>

libxen: Use build-system CFLAGS and LDFLAGS.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jan 17 15:11:22 2008 +0000 (2008-01-17)
parents 295858ddac87
children ae58b4403cae
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_struct_array(xmlNode *, const char *);
94 static xmlNode *
95 add_nested_struct(xmlNode *, const char *);
96 static void
97 add_struct_member(xmlNode *, const char *, const char *, const char *);
98 static void
99 add_unnamed_value(xmlNode *, const char *, const char *, const char *);
101 static void
102 add_struct_value(const struct abstract_type *, void *,
103 void (*)(xmlNode *, const char *, const char *,
104 const char *),
105 const char *, xmlNode *);
107 static xmlNode *
108 add_container(xmlNode *parent, const char *name);
110 static void
111 call_raw(xen_session *, const char *, abstract_value [], int,
112 const abstract_type *, void *);
114 static void
115 parse_structmap_value(xen_session *, xmlNode *, const abstract_type *,
116 void *);
118 static size_t size_of_member(const abstract_type *);
120 static const char *
121 get_val_as_string(const struct abstract_type *, void *, char *, size_t);
124 void
125 xen_init(void)
126 {
127 responsePath =
128 xmlXPathCompile(
129 BAD_CAST(
130 "/methodResponse/params/param/value/struct/member/value"));
131 faultPath =
132 xmlXPathCompile(
133 BAD_CAST("/methodResponse/fault/value/struct/member/value"));
134 }
137 void
138 xen_fini(void)
139 {
140 xmlXPathFreeCompExpr(responsePath);
141 xmlXPathFreeCompExpr(faultPath);
142 responsePath = NULL;
143 faultPath = NULL;
144 }
147 void
148 xen_session_record_free(xen_session_record *record)
149 {
150 if (record == NULL)
151 {
152 return;
153 }
154 free(record->uuid);
155 xen_host_record_opt_free(record->this_host);
156 free(record->this_user);
157 free(record);
158 }
161 xen_session *
162 xen_session_login_with_password(xen_call_func call_func, void *handle,
163 const char *uname, const char *pwd)
164 {
165 abstract_value params[] =
166 {
167 { .type = &abstract_type_string,
168 .u.string_val = uname },
169 { .type = &abstract_type_string,
170 .u.string_val = pwd }
171 };
173 xen_session *session = malloc(sizeof(xen_session));
174 session->call_func = call_func;
175 session->handle = handle;
176 session->session_id = NULL;
177 session->ok = true;
178 session->error_description = NULL;
179 session->error_description_count = 0;
181 call_raw(session, "session.login_with_password", params, 2,
182 &abstract_type_string, &session->session_id);
184 return session;
185 }
188 void
189 xen_session_logout(xen_session *session)
190 {
191 abstract_value params[] =
192 {
193 };
194 xen_call_(session, "session.logout", params, 0, NULL, NULL);
196 if (session->error_description != NULL)
197 {
198 for (int i = 0; i < session->error_description_count; i++)
199 {
200 free(session->error_description[i]);
201 }
202 free(session->error_description);
203 }
205 free((char *)session->session_id);
206 free(session);
207 }
210 void
211 xen_session_clear_error(xen_session *session)
212 {
213 if (session->error_description != NULL)
214 {
215 for (int i = 0; i < session->error_description_count; i++)
216 {
217 free(session->error_description[i]);
218 }
219 free(session->error_description);
220 }
221 session->error_description = NULL;
222 session->error_description_count = 0;
223 session->ok = true;
224 }
227 bool
228 xen_session_get_uuid(xen_session *session, char **result,
229 xen_session *self_session)
230 {
231 abstract_value params[] =
232 {
233 { .type = &abstract_type_string,
234 .u.string_val = self_session->session_id }
235 };
237 xen_call_(session, "session.get_uuid", params, 1,
238 &abstract_type_string, result);
239 return session->ok;
240 }
243 bool
244 xen_session_get_this_host(xen_session *session, xen_host *result,
245 xen_session *self_session)
246 {
247 abstract_value params[] =
248 {
249 { .type = &abstract_type_string,
250 .u.string_val = self_session->session_id }
251 };
253 xen_call_(session, "session.get_this_host", params, 1,
254 &abstract_type_string, result);
255 return session->ok;
256 }
259 bool
260 xen_session_get_this_user(xen_session *session, char **result,
261 xen_session *self_session)
262 {
263 abstract_value params[] =
264 {
265 { .type = &abstract_type_string,
266 .u.string_val = self_session->session_id }
267 };
269 xen_call_(session, "session.get_this_user", params, 1,
270 &abstract_type_string, result);
271 return session->ok;
272 }
275 bool
276 xen_session_get_last_active(xen_session *session, time_t *result,
277 xen_session *self_session)
278 {
279 abstract_value params[] =
280 {
281 { .type = &abstract_type_string,
282 .u.string_val = self_session->session_id }
283 };
285 xen_call_(session, "session.get_last_active", params, 1,
286 &abstract_type_datetime, result);
287 return session->ok;
288 }
291 static const struct_member xen_session_record_struct_members[] =
292 {
293 { .key = "uuid",
294 .type = &abstract_type_string,
295 .offset = offsetof(xen_session_record, uuid) },
296 { .key = "this_host",
297 .type = &abstract_type_ref,
298 .offset = offsetof(xen_session_record, this_host) },
299 { .key = "this_user",
300 .type = &abstract_type_string,
301 .offset = offsetof(xen_session_record, this_user) },
302 { .key = "last_active",
303 .type = &abstract_type_datetime,
304 .offset = offsetof(xen_session_record, last_active) },
305 };
307 const abstract_type xen_session_record_abstract_type_ =
308 {
309 .typename = STRUCT,
310 .struct_size = sizeof(xen_session_record),
311 .member_count =
312 sizeof(xen_session_record_struct_members) / sizeof(struct_member),
313 .members = xen_session_record_struct_members
314 };
317 bool
318 xen_session_get_record(xen_session *session, xen_session_record **result,
319 xen_session *self_session)
320 {
321 abstract_value param_values[] =
322 {
323 { .type = &abstract_type_string,
324 .u.string_val = self_session->session_id }
325 };
327 abstract_type result_type = xen_session_record_abstract_type_;
329 *result = NULL;
330 XEN_CALL_("session.get_record");
332 return session->ok;
333 }
336 #define X "%02x"
337 #define UUID_FORMAT X X X X "-" X X "-" X X "-" X X "-" X X X X X X
340 bool
341 xen_uuid_string_to_bytes(char *uuid, char **bytes)
342 {
343 unsigned int buf[16];
345 *bytes = NULL;
347 if (strlen(uuid) != 36)
348 return false;
350 if (16 != sscanf(uuid, UUID_FORMAT,
351 buf + 0, buf + 1, buf + 2, buf + 3,
352 buf + 4, buf + 5,
353 buf + 6, buf + 7,
354 buf + 8, buf + 9,
355 buf + 10, buf + 11, buf + 12, buf + 13, buf + 14,
356 buf + 15))
357 {
358 return false;
359 }
361 *bytes = malloc(16);
362 if (*bytes == NULL)
363 return false;
365 for (int i = 0; i < 16; i++) {
366 (*bytes)[i] = (char)buf[i];
367 }
369 return true;
370 }
373 bool
374 xen_uuid_bytes_to_string(char *bytes, char **uuid)
375 {
376 *uuid = malloc(37);
377 if (*uuid == NULL)
378 return false;
380 sprintf(*uuid, UUID_FORMAT,
381 bytes[0], bytes[1], bytes[2], bytes[3],
382 bytes[4], bytes[5],
383 bytes[6], bytes[7],
384 bytes[8], bytes[9],
385 bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]);
387 return true;
388 }
391 #undef UUID_FORMAT
392 #undef X
395 void
396 xen_uuid_free(char *uuid)
397 {
398 free(uuid);
399 }
402 void
403 xen_uuid_bytes_free(char *bytes)
404 {
405 free(bytes);
406 }
409 /**
410 * @param value A pointer to the correct location as per the given
411 * result_type. Will be populated if the call succeeds. In that case, and if
412 * value is a char **, the char * itself must be freed by the caller.
413 */
414 void
415 xen_call_(xen_session *s, const char *method_name,
416 abstract_value params[], int param_count,
417 const abstract_type *result_type, void *value)
418 {
419 abstract_value *full_params;
420 if (!s->ok)
421 {
422 return;
423 }
425 full_params = malloc(sizeof(abstract_value) * (param_count + 1));
427 full_params[0].type = &abstract_type_string;
428 full_params[0].u.string_val = s->session_id;
430 memcpy(full_params + 1, params, param_count * sizeof(abstract_value));
432 call_raw(s, method_name, full_params, param_count + 1, result_type,
433 value);
435 free(full_params);
436 }
439 static bool
440 bufferAdd(const void *data, size_t len, void *buffer)
441 {
442 return 0 == xmlBufferAdd((xmlBufferPtr)buffer, data, len);
443 }
446 static void
447 call_raw(xen_session *s, const char *method_name,
448 abstract_value params[], int param_count,
449 const abstract_type *result_type, void *value)
450 {
451 xmlBufferPtr buffer = xmlBufferCreate();
452 char *body = make_body(method_name, params, param_count);
453 int error_code =
454 s->call_func(body, strlen(body), s->handle, buffer, &bufferAdd);
455 free(body);
456 if (error_code)
457 {
458 char **strings = malloc(2 * sizeof(char *));
460 strings[0] = xen_strdup_("TRANSPORT_FAULT");
461 strings[1] = malloc(20);
462 snprintf(strings[1], 20, "%d", error_code);
464 s->ok = false;
465 s->error_description = strings;
466 s->error_description_count = 2;
467 }
468 else
469 {
470 parse_result(s, (char *)xmlBufferContent(buffer), result_type, value);
471 }
472 xmlBufferFree(buffer);
473 }
476 static void server_error(xen_session *session, const char *error_string)
477 {
478 char **strings;
479 if (!session->ok)
480 {
481 /* Don't wipe out the earlier error message with this one. */
482 return;
483 }
485 strings = malloc(2 * sizeof(char *));
487 strings[0] = xen_strdup_("SERVER_FAULT");
488 strings[1] = xen_strdup_(error_string);
490 session->ok = false;
491 session->error_description = strings;
492 session->error_description_count = 2;
493 }
496 static void server_error_2(xen_session *session, const char *error_string,
497 const char *param)
498 {
499 char **strings;
500 if (!session->ok)
501 {
502 /* Don't wipe out the earlier error message with this one. */
503 return;
504 }
506 strings = malloc(3 * sizeof(char *));
508 strings[0] = xen_strdup_("SERVER_FAULT_2");
509 strings[1] = xen_strdup_(error_string);
510 strings[2] = xen_strdup_(param);
512 session->ok = false;
513 session->error_description = strings;
514 session->error_description_count = 3;
515 }
518 static bool is_node(xmlNode *n, char *type)
519 {
520 return
521 n->type == XML_ELEMENT_NODE &&
522 0 == strcmp((char *)n->name, type);
523 }
526 static bool is_container_node(xmlNode *n, char *type)
527 {
528 return
529 is_node(n, type) &&
530 n->children != NULL &&
531 n->children == n->last &&
532 n->children->type == XML_ELEMENT_NODE;
533 }
536 /**
537 * @return The contents of the given value, or NULL if this is not a node with
538 * the given type. If not NULL, the result must be freed with xmlFree().
539 */
540 static xmlChar *string_from_value(xmlNode *n, char *type)
541 {
542 /*
543 <value><type>XYZ</type></value> is normal, but the XML-RPC spec also
544 allows <value>XYZ</value> where XYZ is to be interpreted as a string.
545 */
547 if (is_container_node(n, "value") &&
548 0 == strcmp((char *)n->children->name, type))
549 {
550 return
551 n->children->children == NULL ?
552 xmlStrdup(BAD_CAST("")) :
553 xmlNodeGetContent(n->children->children);
554 }
555 else if (0 == strcmp(type, "string") && is_node(n, "value"))
556 {
557 return
558 n->children == NULL ?
559 xmlStrdup(BAD_CAST("")) :
560 xmlNodeGetContent(n->children);
561 }
562 else
563 {
564 return NULL;
565 }
566 }
569 /**
570 * Find the name node that is a child of the given one, and return its
571 * contents, or NULL if this has no such node. If not NULL, the result must
572 * be freed with xmlFree().
573 */
574 static xmlChar *string_from_name(xmlNode *n)
575 {
576 xmlNode *cur = n->children;
578 while (cur != NULL)
579 {
580 if (0 == strcmp((char *)cur->name, "name"))
581 {
582 return xmlNodeGetContent(cur);
583 }
584 cur = cur->next;
585 }
587 return NULL;
588 }
591 static int count_children(xmlNode *n, const char *name)
592 {
593 int result = 0;
594 xmlNode *cur = n->children;
596 while (cur != NULL)
597 {
598 if (0 == strcmp((char *)cur->name, name))
599 {
600 result++;
601 }
602 cur = cur->next;
603 }
605 return result;
606 }
609 static void destring(xen_session *s, xmlChar *name, const abstract_type *type,
610 void *value)
611 {
612 switch (type->typename)
613 {
614 case STRING:
615 *((char **)value) = xen_strdup_((const char *)name);
616 break;
618 case INT:
619 *((int64_t *)value) = atoll((const char *)name);
620 break;
622 case FLOAT:
623 *((double *)value) = atof((const char *)name);
624 break;
626 default:
627 server_error(s, "Invalid Map key type");
628 }
629 }
632 /**
633 * result_type : STRING => value : char **, the char * is yours.
634 * result_type : ENUM => value : int *
635 * result_type : INT => value : int64_t *
636 * result_type : FLOAT => value : double *
637 * result_type : BOOL => value : bool *
638 * result_type : DATETIME => value : time_t *
639 * result_type : SET => value : arbitrary_set **, the set is yours.
640 * result_type : MAP => value : arbitrary_map **, the map is yours.
641 * result_type : OPT => value : arbitrary_record_opt **,
642 * the record is yours, the handle is
643 * filled.
644 * result_type : STRUCT => value : void **, the void * is yours.
645 */
646 static void parse_into(xen_session *s, xmlNode *value_node,
647 const abstract_type *result_type, void *value,
648 int slot)
649 {
650 if (result_type == NULL)
651 {
652 xmlChar *string = string_from_value(value_node, "string");
653 if (string == NULL || strcmp((char *)string, ""))
654 {
655 server_error(s,
656 "Expected Void from the server, but didn't get it");
657 }
658 else
659 {
660 free(string);
661 }
663 return;
664 }
666 switch (result_type->typename)
667 {
668 case STRING:
669 {
670 xmlChar *string = string_from_value(value_node, "string");
671 if (string == NULL)
672 {
673 server_error(
674 s, "Expected a String from the server, but didn't get one");
675 }
676 else
677 {
678 ((char **)value)[slot] = xen_strdup_((const char *)string);
679 free(string);
680 }
681 }
682 break;
684 case ENUM:
685 {
686 xmlChar *string = string_from_value(value_node, "string");
687 if (string == NULL)
688 {
689 #if PERMISSIVE
690 fprintf(stderr,
691 "Expected an Enum from the server, but didn't get one\n");
692 ((int *)value)[slot] = 0;
693 #else
694 server_error(
695 s, "Expected an Enum from the server, but didn't get one");
696 #endif
697 }
698 else
699 {
700 ((int *)value)[slot] =
701 result_type->enum_demarshaller(s, (const char *)string);
702 free(string);
703 }
704 }
705 break;
707 case INT:
708 {
709 xmlChar *string = string_from_value(value_node, "string");
710 if (string == NULL)
711 {
712 server_error(
713 s, "Expected an Int from the server, but didn't get one");
714 }
715 else
716 {
717 ((int64_t *)value)[slot] = (int64_t)atoll((char *)string);
718 free(string);
719 }
720 }
721 break;
723 case FLOAT:
724 {
725 xmlChar *string = string_from_value(value_node, "double");
726 if (string == NULL)
727 {
728 #if PERMISSIVE
729 fprintf(stderr,
730 "Expected a Float from the server, but didn't get one\n");
731 ((double *)value)[slot] = 0.0;
732 #else
733 server_error(
734 s, "Expected a Float from the server, but didn't get one");
735 #endif
736 }
737 else
738 {
739 ((double *)value)[slot] = atof((char *)string);
740 free(string);
741 }
742 }
743 break;
745 case BOOL:
746 {
747 xmlChar *string = string_from_value(value_node, "boolean");
748 if (string == NULL)
749 {
750 #if PERMISSIVE
751 fprintf(stderr,
752 "Expected a Bool from the server, but didn't get one\n");
753 ((bool *)value)[slot] = false;
754 #else
755 server_error(
756 s, "Expected a Bool from the server, but didn't get one");
757 #endif
758 }
759 else
760 {
761 ((bool *)value)[slot] = (0 == strcmp((char *)string, "1"));
762 free(string);
763 }
764 }
765 break;
767 case DATETIME:
768 {
769 xmlChar *string = string_from_value(value_node, "dateTime.iso8601");
770 if (string == NULL)
771 {
772 server_error(
773 s, "Expected an DateTime from the server but didn't get one");
774 }
775 else
776 {
777 struct tm tm;
778 memset(&tm, 0, sizeof(tm));
779 strptime((char *)string, "%Y%m%dT%H:%M:%S", &tm);
780 ((time_t *)value)[slot] = (time_t)mktime(&tm);
781 free(string);
782 }
783 }
784 break;
786 case SET:
787 {
788 if (!is_container_node(value_node, "value") ||
789 !is_container_node(value_node->children, "array"))
790 {
791 server_error(s,
792 "Expected Set from the server, but didn't get it");
793 }
794 else
795 {
796 arbitrary_set *set;
797 xmlNode *cur, *data_node = value_node->children->children;
798 int i, n = count_children(data_node, "value");
800 const abstract_type *member_type = result_type->child;
801 size_t member_size = size_of_member(member_type);
803 set = calloc(1, sizeof(arbitrary_set) + member_size * n);
804 set->size = n;
805 i = 0;
806 cur = data_node->children;
808 while (cur != NULL)
809 {
810 if (0 == strcmp((char *)cur->name, "value"))
811 {
812 parse_into(s, cur, member_type, set->contents, i);
813 i++;
814 }
815 cur = cur->next;
816 }
818 ((arbitrary_set **)value)[slot] = set;
819 }
820 }
821 break;
823 case MAP:
824 {
825 if (!is_container_node(value_node, "value") ||
826 value_node->children->type != XML_ELEMENT_NODE ||
827 0 != strcmp((char *)value_node->children->name, "struct"))
828 {
829 server_error(s,
830 "Expected Map from the server, but didn't get it");
831 }
832 else
833 {
834 arbitrary_map *map;
835 xmlNode *cur, *struct_node = value_node->children;
836 int i, n = count_children(struct_node, "member");
838 size_t struct_size = result_type->struct_size;
840 const struct struct_member *key_member = result_type->members;
841 const struct struct_member *val_member = result_type->members + 1;
843 map = calloc(1, sizeof(arbitrary_map) + struct_size * n);
844 map->size = n;
845 i = 0;
846 cur = struct_node->children;
848 while (cur != NULL)
849 {
850 if (0 == strcmp((char *)cur->name, "member"))
851 {
852 xmlChar *name;
853 if (cur->children == NULL || cur->last == cur->children)
854 {
855 server_error(s, "Malformed Map");
856 free(map);
857 return;
858 }
860 name = string_from_name(cur);
861 if (name == NULL)
862 {
863 server_error(s, "Malformed Map");
864 free(map);
865 return;
866 }
868 destring(s, name, key_member->type,
869 ((void *)(map + 1)) +
870 (i * struct_size) +
871 key_member->offset);
872 xmlFree(name);
873 if (!s->ok)
874 {
875 free(map);
876 return;
877 }
879 parse_structmap_value(s, cur, val_member->type,
880 ((void *)(map + 1)) +
881 (i * struct_size) +
882 val_member->offset);
883 if (!s->ok)
884 {
885 free(map);
886 return;
887 }
888 i++;
889 }
890 cur = cur->next;
891 }
893 ((arbitrary_map **)value)[slot] = map;
894 }
895 }
896 break;
898 case STRUCT:
899 {
900 if (!is_container_node(value_node, "value") ||
901 value_node->children->type != XML_ELEMENT_NODE ||
902 0 != strcmp((char *)value_node->children->name, "struct") ||
903 value_node->children->children == NULL)
904 {
905 server_error(s,
906 "Expected Map from the server, but didn't get it");
907 }
908 else
909 {
910 xmlNode *struct_node = value_node->children;
912 void *result = calloc(1, result_type->struct_size);
913 xmlNode *cur = struct_node->children;
915 size_t member_count = result_type->member_count;
917 const struct_member **checklist =
918 malloc(sizeof(const struct_member *) * member_count);
919 int seen_count = 0;
921 while (cur != NULL)
922 {
923 if (0 == strcmp((char *)cur->name, "member"))
924 {
925 xmlChar *name;
926 if (cur->children == NULL || cur->last == cur->children)
927 {
928 server_error(s, "Malformed Struct");
929 free(result);
930 free(checklist);
931 return;
932 }
934 name = string_from_name(cur);
935 if (name == NULL)
936 {
937 server_error(s, "Malformed Struct");
938 free(result);
939 free(checklist);
940 return;
941 }
943 for (size_t i = 0; i < member_count; i++)
944 {
945 const struct_member *mem = result_type->members + i;
947 if (0 == strcmp((char *)name, mem->key))
948 {
949 parse_structmap_value(s, cur, mem->type,
950 result + mem->offset);
951 checklist[seen_count] = mem;
952 seen_count++;
953 break;
954 }
955 }
957 /* Note that we're skipping unknown fields implicitly.
958 This means that we'll be forward compatible with
959 new servers. */
961 xmlFree(name);
963 if (!s->ok)
964 {
965 free(result);
966 free(checklist);
967 return;
968 }
969 }
970 cur = cur->next;
971 }
973 /* Check that we've filled all fields. */
974 for (size_t i = 0; i < member_count; i++)
975 {
976 const struct_member *mem = result_type->members + i;
977 int j;
979 for (j = 0; j < seen_count; j++)
980 {
981 if (checklist[j] == mem)
982 {
983 break;
984 }
985 }
987 if (j == seen_count)
988 {
989 #if PERMISSIVE
990 fprintf(stderr,
991 "Struct did not contain expected field %s.\n",
992 mem->key);
993 #else
994 server_error_2(s,
995 "Struct did not contain expected field",
996 mem->key);
997 free(result);
998 free(checklist);
999 return;
1000 #endif
1004 free(checklist);
1005 ((void **)value)[slot] = result;
1008 break;
1010 case REF:
1012 arbitrary_record_opt *record_opt =
1013 calloc(1, sizeof(arbitrary_record_opt));
1015 record_opt->is_record = false;
1016 parse_into(s, value_node, &abstract_type_string,
1017 &(record_opt->u.handle), 0);
1019 ((arbitrary_record_opt **)value)[slot] = record_opt;
1021 break;
1023 default:
1024 assert(false);
1029 static size_t size_of_member(const abstract_type *type)
1031 switch (type->typename)
1033 case STRING:
1034 return sizeof(char *);
1036 /*
1037 case INT:
1038 return sizeof(int64_t);
1040 case FLOAT:
1041 return sizeof(double);
1043 case BOOL:
1044 return sizeof(bool);
1045 */
1046 case ENUM:
1047 return sizeof(int);
1049 case REF:
1050 return sizeof(arbitrary_record_opt *);
1052 case STRUCT:
1053 return type->struct_size;
1055 default:
1056 assert(false);
1061 static void parse_structmap_value(xen_session *s, xmlNode *n,
1062 const abstract_type *type, void *value)
1064 xmlNode *cur = n->children;
1066 while (cur != NULL)
1068 if (0 == strcmp((char *)cur->name, "value"))
1070 parse_into(s, cur, type, value, 0);
1071 return;
1073 cur = cur->next;
1076 server_error(s, "Missing value in Map/Struct");
1080 static void parse_fault(xen_session *session, xmlXPathContextPtr xpathCtx)
1082 xmlNode *fault_node0, *fault_node1;
1083 xmlChar *fault_code_str, *fault_string_str;
1084 char **strings;
1086 xmlXPathObjectPtr xpathObj = xmlXPathCompiledEval(faultPath, xpathCtx);
1087 if (xpathObj == NULL)
1089 server_error(session, "Method response is neither result nor fault");
1090 return;
1093 if (xpathObj->type != XPATH_NODESET ||
1094 xpathObj->nodesetval->nodeNr != 2)
1096 xmlXPathFreeObject(xpathObj);
1097 server_error(session, "Method response is neither result nor fault");
1098 return;
1101 fault_node0 = xpathObj->nodesetval->nodeTab[0];
1102 fault_node1 = xpathObj->nodesetval->nodeTab[1];
1104 fault_code_str = string_from_value(fault_node0, "int");
1105 if (fault_code_str == NULL)
1107 fault_code_str = string_from_value(fault_node0, "i4");
1109 if (fault_code_str == NULL)
1111 xmlXPathFreeObject(xpathObj);
1112 server_error(session, "Fault code is malformed");
1113 return;
1116 fault_string_str = string_from_value(fault_node1, "string");
1117 if (fault_string_str == NULL)
1119 xmlFree(fault_code_str);
1120 xmlXPathFreeObject(xpathObj);
1121 server_error(session, "Fault string is malformed");
1122 return;
1125 strings = malloc(3 * sizeof(char *));
1127 strings[0] = xen_strdup_("FAULT");
1128 strings[1] = xen_strdup_((char *)fault_code_str);
1129 strings[2] = xen_strdup_((char *)fault_string_str);
1131 session->ok = false;
1132 session->error_description = strings;
1133 session->error_description_count = 3;
1135 xmlFree(fault_code_str);
1136 xmlFree(fault_string_str);
1137 xmlXPathFreeObject(xpathObj);
1141 static void parse_failure(xen_session *session, xmlNode *node)
1143 abstract_type error_description_type =
1144 { .typename = SET,
1145 .child = &abstract_type_string };
1146 arbitrary_set *error_descriptions;
1148 parse_into(session, node, &error_description_type, &error_descriptions,
1149 0);
1151 if (session->ok)
1153 char **c, **strings;
1154 int n;
1156 session->ok = false;
1158 c = (char **)error_descriptions->contents;
1159 n = error_descriptions->size;
1161 strings = malloc(n * sizeof(char *));
1162 for (int i = 0; i < n; i++)
1164 strings[i] = c[i];
1167 session->error_description_count = n;
1168 session->error_description = strings;
1171 free(error_descriptions);
1175 /**
1176 * Parameters as for xen_call_() above.
1177 */
1178 static void parse_result(xen_session *session, const char *result,
1179 const abstract_type *result_type, void *value)
1181 xmlDocPtr doc =
1182 xmlReadMemory(result, strlen(result), "", NULL, XML_PARSE_NONET);
1183 xmlXPathContextPtr xpathCtx;
1184 xmlXPathObjectPtr xpathObj;
1185 xmlNode *node0, *node1;
1186 xmlChar *status_code;
1188 if (doc == NULL)
1190 server_error(session, "Couldn't parse the server response");
1191 return;
1194 xpathCtx = xmlXPathNewContext(doc);
1195 if (xpathCtx == NULL)
1197 xmlFreeDoc(doc);
1198 server_error(session, "Couldn't create XPath context");
1199 return;
1202 xpathObj = xmlXPathCompiledEval(responsePath, xpathCtx);
1203 if (xpathObj == NULL)
1205 parse_fault(session, xpathCtx);
1207 xmlXPathFreeContext(xpathCtx);
1208 xmlFreeDoc(doc);
1209 return;
1212 if (xpathObj->type != XPATH_NODESET ||
1213 xpathObj->nodesetval->nodeNr != 2)
1215 parse_fault(session, xpathCtx);
1217 xmlXPathFreeObject(xpathObj);
1218 xmlXPathFreeContext(xpathCtx);
1219 xmlFreeDoc(doc);
1220 return;
1223 node0 = xpathObj->nodesetval->nodeTab[0];
1224 node1 = xpathObj->nodesetval->nodeTab[1];
1226 status_code = string_from_value(node0, "string");
1227 if (status_code == NULL)
1229 xmlXPathFreeObject(xpathObj);
1230 xmlXPathFreeContext(xpathCtx);
1231 xmlFreeDoc(doc);
1232 server_error(session, "Server response does not have a Status");
1233 return;
1236 if (strcmp((char *)status_code, "Success"))
1238 parse_failure(session, node1);
1240 xmlFree(status_code);
1241 xmlXPathFreeObject(xpathObj);
1242 xmlXPathFreeContext(xpathCtx);
1243 xmlFreeDoc(doc);
1244 return;
1247 parse_into(session, node1, result_type, value, 0);
1249 xmlFree(status_code);
1250 xmlXPathFreeObject(xpathObj);
1251 xmlXPathFreeContext(xpathCtx);
1252 xmlFreeDoc(doc);
1256 static void
1257 make_body_add_type(enum abstract_typename typename, abstract_value *v,
1258 xmlNode *params_node)
1260 char buf[20];
1261 switch (typename)
1263 case STRING:
1264 add_param(params_node, "string", v->u.string_val);
1265 break;
1267 case INT:
1268 snprintf(buf, sizeof(buf), "%"PRId64, v->u.int_val);
1269 add_param(params_node, "string", buf);
1270 break;
1272 case FLOAT:
1273 snprintf(buf, sizeof(buf), "%lf", v->u.float_val);
1274 add_param(params_node, "double", buf);
1275 break;
1277 case BOOL:
1278 add_param(params_node, "boolean", v->u.bool_val ? "1" : "0");
1279 break;
1281 case VOID:
1282 add_param(params_node, "string", "");
1283 break;
1285 case ENUM:
1286 add_param(params_node, "string",
1287 v->type->enum_marshaller(v->u.enum_val));
1288 break;
1290 case SET:
1292 const struct abstract_type *member_type = v->type->child;
1293 arbitrary_set *set_val = v->u.struct_val;
1294 abstract_value v;
1295 xmlNode *data_node = add_param_struct(params_node);
1297 for (size_t i = 0; i < set_val->size; i++)
1299 switch (member_type->typename) {
1300 case STRING:
1301 v.u.string_val = (char *)set_val->contents[i];
1302 make_body_add_type(member_type->typename, &v, data_node);
1303 break;
1304 default:
1305 assert(false);
1309 break;
1311 case STRUCT:
1313 size_t member_count = v->type->member_count;
1315 xmlNode *struct_node = add_param_struct(params_node);
1317 for (size_t i = 0; i < member_count; i++)
1319 const struct struct_member *mem = v->type->members + i;
1320 const char *key = mem->key;
1321 void *struct_value = v->u.struct_val;
1323 add_struct_value(mem->type, struct_value + mem->offset,
1324 add_struct_member, key, struct_node);
1327 break;
1329 case MAP:
1331 const struct struct_member *member = v->type->members;
1332 arbitrary_map *map_val = v->u.struct_val;
1333 xmlNode *param_node = add_param_struct(params_node);
1334 for (size_t i = 0; i < map_val->size; i++) {
1335 enum abstract_typename typename_key = member[0].type->typename;
1336 enum abstract_typename typename_val = member[1].type->typename;
1337 int offset_key = member[0].offset;
1338 int offset_val = member[1].offset;
1339 int struct_size = v->type->struct_size;
1341 switch (typename_key) {
1342 case STRING: {
1343 char **addr = (void *)(map_val + 1) +
1344 (i * struct_size) +
1345 offset_key;
1346 char *key = *addr;
1348 switch (typename_val) {
1349 case STRING: {
1350 char *val;
1351 addr = (void *)(map_val + 1) +
1352 (i * struct_size) +
1353 offset_val;
1354 val = *addr;
1355 add_struct_member(param_node, key, "string", val);
1356 break;
1358 default:
1359 assert(false);
1361 break;
1363 default:
1364 assert(false);
1368 break;
1371 default:
1372 assert(false);
1377 static char *
1378 make_body(const char *method_name, abstract_value params[], int param_count)
1380 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
1381 xmlNode *params_node, *methodCall = xmlNewNode(NULL, BAD_CAST "methodCall");
1382 xmlBufferPtr buffer;
1383 xmlSaveCtxtPtr save_ctxt;
1384 xmlChar *content;
1386 xmlDocSetRootElement(doc, methodCall);
1388 xmlNewChild(methodCall, NULL, BAD_CAST "methodName",
1389 BAD_CAST method_name);
1391 params_node = xmlNewChild(methodCall, NULL, BAD_CAST "params", NULL);
1393 for (int p = 0; p < param_count; p++)
1395 abstract_value *v = params + p;
1396 make_body_add_type(v->type->typename, v, params_node);
1399 buffer = xmlBufferCreate();
1400 save_ctxt = xmlSaveToBuffer(buffer, NULL, XML_SAVE_NO_XHTML);
1402 if (xmlSaveDoc(save_ctxt, doc) == -1)
1404 return NULL;
1407 xmlFreeDoc(doc);
1408 xmlSaveClose(save_ctxt);
1409 content = xmlStrdup(xmlBufferContent(buffer));
1410 xmlBufferFree(buffer);
1411 return (char *)content;
1415 static void
1416 add_struct_value(const struct abstract_type *type, void *value,
1417 void (*adder)(xmlNode *node, const char *key,
1418 const char *type, const char *val),
1419 const char *key, xmlNode *node)
1421 char buf[20];
1423 switch (type->typename)
1425 case REF:
1426 case STRING:
1427 case INT:
1428 case ENUM:
1430 const char *val_as_string =
1431 get_val_as_string(type, value, buf, sizeof(buf));
1432 adder(node, key, "string", val_as_string);
1434 break;
1436 case FLOAT:
1438 double val = *(double *)value;
1439 snprintf(buf, sizeof(buf), "%lf", val);
1440 adder(node, key, "double", buf);
1442 break;
1444 case BOOL:
1446 bool val = *(bool *)value;
1447 adder(node, key, "boolean", val ? "1" : "0");
1449 break;
1451 case SET:
1453 const struct abstract_type *member_type = type->child;
1454 size_t member_size = size_of_member(member_type);
1455 arbitrary_set *set_val = *(arbitrary_set **)value;
1457 if (set_val != NULL)
1459 xmlNode *data_node = add_struct_array(node, key);
1461 for (size_t i = 0; i < set_val->size; i++)
1463 void *member_value = (char *)set_val->contents +
1464 (i * member_size);
1465 add_struct_value(member_type, member_value,
1466 add_unnamed_value, NULL, data_node);
1470 break;
1472 case STRUCT:
1474 assert(false);
1475 /* XXX Nested structures aren't supported yet, but
1476 fortunately we don't need them, because we don't have
1477 any "deep create" calls. This will need to be
1478 fixed. */
1480 break;
1482 case MAP:
1484 size_t member_size = type->struct_size;
1485 const struct abstract_type *l_type = type->members[0].type;
1486 const struct abstract_type *r_type = type->members[1].type;
1487 int l_offset = type->members[0].offset;
1488 int r_offset = type->members[1].offset;
1490 arbitrary_map *map_val = *(arbitrary_map **)value;
1492 if (map_val != NULL)
1494 xmlNode *struct_node = add_nested_struct(node, key);
1496 for (size_t i = 0; i < map_val->size; i++)
1498 void *contents = (void *)map_val->contents;
1499 void *l_value = contents + (i * member_size) + l_offset;
1500 void *r_value = contents + (i * member_size) + r_offset;
1502 const char *l_value_as_string =
1503 get_val_as_string(l_type, l_value, buf, sizeof(buf));
1505 add_struct_value(r_type, r_value, add_struct_member,
1506 l_value_as_string, struct_node);
1510 break;
1512 default:
1513 assert(false);
1518 static const char *
1519 get_val_as_string(const struct abstract_type *type, void *value, char *buf,
1520 size_t bufsize)
1522 switch (type->typename)
1524 case REF:
1526 arbitrary_record_opt *val = *(arbitrary_record_opt **)value;
1527 if (val != NULL)
1529 if (val->is_record)
1531 return val->u.record->handle;
1533 else
1535 return val->u.handle;
1538 else
1540 return NULL;
1543 break;
1545 case STRING:
1547 return *(char **)value;
1549 break;
1551 case INT:
1553 int64_t val = *(int64_t *)value;
1554 snprintf(buf, bufsize, "%"PRId64, val);
1555 return buf;
1557 break;
1559 case ENUM:
1561 int val = *(int *)value;
1562 return type->enum_marshaller(val);
1564 break;
1566 default:
1567 assert(false);
1572 static xmlNode *
1573 add_container(xmlNode *parent, const char *name)
1575 return xmlNewChild(parent, NULL, BAD_CAST name, NULL);
1579 static void
1580 add_param(xmlNode *params_node, const char *type, const char *value)
1582 xmlNode *param_node = add_container(params_node, "param");
1583 add_value(param_node, type, value);
1587 static void
1588 add_value(xmlNode *parent, const char *type, const char *value)
1590 xmlNode *value_node = add_container(parent, "value");
1591 xmlNewChild(value_node, NULL, BAD_CAST type, BAD_CAST value);
1595 static void
1596 add_unnamed_value(xmlNode *parent, const char *name, const char *type,
1597 const char *value)
1599 (void)name;
1600 add_value(parent, type, value);
1604 static xmlNode *
1605 add_param_struct(xmlNode *params_node)
1607 xmlNode *param_node = add_container(params_node, "param");
1608 xmlNode *value_node = add_container(param_node, "value");
1610 return xmlNewChild(value_node, NULL, BAD_CAST "struct", NULL);
1614 static void
1615 add_struct_member(xmlNode *struct_node, const char *name, const char *type,
1616 const char *value)
1618 xmlNode *member_node = add_container(struct_node, "member");
1620 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1622 add_value(member_node, type, value);
1626 static xmlNode *
1627 add_struct_array(xmlNode *struct_node, const char *name)
1629 xmlNode *member_node = add_container(struct_node, "member");
1630 xmlNode *value_node, *array_node;
1632 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1634 value_node = add_container(member_node, "value");
1635 array_node = add_container(value_node, "array");
1637 return add_container(array_node, "data");
1641 static xmlNode *
1642 add_nested_struct(xmlNode *struct_node, const char *name)
1644 xmlNode *member_node = add_container(struct_node, "member");
1645 xmlNode *value_node;
1647 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1649 value_node = add_container(member_node, "value");
1651 return add_container(value_node, "struct");
1655 int xen_enum_lookup_(xen_session *session, const char *str,
1656 const char **lookup_table, int n)
1658 if (str != NULL)
1660 for (int i = 0; i < n; i++)
1662 if (0 == strcmp(str, lookup_table[i]))
1664 return i;
1669 server_error_2(session, "Bad enum string", str);
1670 return 0;
1674 char *
1675 xen_strdup_(const char *in)
1677 char *result = malloc(strlen(in) + 1);
1678 strcpy(result, in);
1679 return result;
1683 const abstract_type abstract_type_string = { .typename = STRING };
1684 const abstract_type abstract_type_int = { .typename = INT };
1685 const abstract_type abstract_type_float = { .typename = FLOAT };
1686 const abstract_type abstract_type_bool = { .typename = BOOL };
1687 const abstract_type abstract_type_datetime = { .typename = DATETIME };
1688 const abstract_type abstract_type_ref = { .typename = REF };
1690 const abstract_type abstract_type_string_set =
1692 .typename = SET,
1693 .child = &abstract_type_string
1694 };
1696 const abstract_type abstract_type_ref_set =
1698 .typename = SET,
1699 .child = &abstract_type_ref
1700 };
1702 static const struct struct_member string_string_members[] =
1705 .type = &abstract_type_string,
1706 .offset = offsetof(xen_string_string_map_contents, key)
1707 },
1709 .type = &abstract_type_string,
1710 .offset = offsetof(xen_string_string_map_contents, val)
1712 };
1713 const abstract_type abstract_type_string_string_map =
1715 .typename = MAP,
1716 .struct_size = sizeof(xen_string_string_map_contents),
1717 .members = string_string_members
1718 };
1720 static struct struct_member int_float_members[] =
1723 .type = &abstract_type_int,
1724 .offset = offsetof(xen_int_float_map_contents, key)
1725 },
1727 .type = &abstract_type_float,
1728 .offset = offsetof(xen_int_float_map_contents, val)
1730 };
1731 const abstract_type abstract_type_int_float_map =
1733 .typename = MAP,
1734 .struct_size = sizeof(xen_int_float_map_contents),
1735 .members = int_float_members
1736 };
1738 static struct struct_member int_int_members[] =
1741 .type = &abstract_type_int,
1742 .offset = offsetof(xen_int_int_map_contents, key)
1743 },
1745 .type = &abstract_type_int,
1746 .offset = offsetof(xen_int_int_map_contents, val)
1748 };
1749 const abstract_type abstract_type_int_int_map =
1751 .typename = MAP,
1752 .struct_size = sizeof(xen_int_int_map_contents),
1753 .members = int_int_members
1754 };
1756 static struct struct_member int_string_set_members[] =
1759 .type = &abstract_type_int,
1760 .offset = offsetof(xen_int_string_set_map_contents, key)
1761 },
1763 .type = &abstract_type_string_set,
1764 .offset = offsetof(xen_int_string_set_map_contents, val)
1766 };
1767 const abstract_type abstract_type_int_string_set_map =
1769 .typename = MAP,
1770 .struct_size = sizeof(xen_int_string_set_map_contents),
1771 .members = int_string_set_members
1772 };