ia64/xen-unstable

annotate tools/libxen/src/xen_common.c @ 12783:38ad5643aafe

With PERMISSIVE turned on, diagnose missing Enums and Bools, and improve the
diagnosis of missing structure values.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Mon Dec 04 10:20:56 2006 +0000 (2006-12-04)
parents fe15bf5a58ad
children 36e00d04278d
rev   line source
ewan@12117 1 /*
ewan@12177 2 * Copyright (c) 2006 XenSource, Inc.
ewan@12117 3 *
ewan@12117 4 * This library is free software; you can redistribute it and/or
ewan@12117 5 * modify it under the terms of the GNU Lesser General Public
ewan@12117 6 * License as published by the Free Software Foundation; either
ewan@12117 7 * version 2.1 of the License, or (at your option) any later version.
ewan@12117 8 *
ewan@12117 9 * This library is distributed in the hope that it will be useful,
ewan@12117 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
ewan@12117 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
ewan@12117 12 * Lesser General Public License for more details.
ewan@12117 13 *
ewan@12117 14 * You should have received a copy of the GNU Lesser General Public
ewan@12117 15 * License along with this library; if not, write to the Free Software
ewan@12117 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
ewan@12177 17 */
ewan@12117 18
ewan@12117 19 #include <assert.h>
ewan@12117 20 #include <stdarg.h>
ewan@12117 21 #include <stddef.h>
ewan@12117 22 #include <stdio.h>
ewan@12117 23 #include <stdlib.h>
ewan@12117 24 #include <string.h>
ewan@12117 25
ewan@12117 26 #include <libxml/parser.h>
ewan@12117 27 #include <libxml/tree.h>
ewan@12117 28 #include <libxml/xmlsave.h>
ewan@12117 29 #include <libxml/xmlstring.h>
ewan@12117 30 #include <libxml/xpath.h>
ewan@12117 31
ewan@12117 32 #include "xen_common.h"
ewan@12117 33 #include "xen_internal.h"
ewan@12117 34 #include "xen_int_float_map.h"
ewan@12117 35 #include "xen_string_string_map.h"
ewan@12117 36
ewan@12117 37
ewan@12635 38 /*
ewan@12635 39 * Whether to ignore missing structure entries. This is not something we
ewan@12635 40 * want to do, once the API has stabilised, as it indicates that the server is
ewan@12635 41 * broken, but at the moment, complaining is just slowing development down.
ewan@12635 42 */
ewan@12635 43 #define PERMISSIVE 1
ewan@12635 44
ewan@12635 45
ewan@12117 46 static xmlXPathCompExprPtr responsePath = NULL;
ewan@12117 47 static xmlXPathCompExprPtr faultPath = NULL;
ewan@12117 48
ewan@12117 49
ewan@12117 50 typedef struct
ewan@12117 51 {
ewan@12117 52 size_t size;
ewan@12117 53 void *contents[];
ewan@12117 54 } arbitrary_map;
ewan@12117 55
ewan@12117 56
ewan@12117 57 typedef struct
ewan@12117 58 {
ewan@12177 59 void *handle;
ewan@12177 60 } arbitrary_record;
ewan@12177 61
ewan@12177 62
ewan@12177 63 typedef struct
ewan@12177 64 {
ewan@12117 65 bool is_record;
ewan@12117 66 union
ewan@12117 67 {
ewan@12117 68 char *handle;
ewan@12177 69 arbitrary_record *record;
ewan@12117 70 } u;
ewan@12117 71 } arbitrary_record_opt;
ewan@12117 72
ewan@12117 73
ewan@12117 74 static char *
ewan@12117 75 make_body(const char *, abstract_value [], int);
ewan@12117 76
ewan@12117 77 static void
ewan@12117 78 parse_result(xen_session *, const char *, const abstract_type *, void *);
ewan@12117 79
ewan@12117 80 static void
ewan@12117 81 add_value(xmlNode *, const char *, const char *);
ewan@12117 82 static void
ewan@12117 83 add_param(xmlNode *, const char *, const char *);
ewan@12117 84
ewan@12117 85 static xmlNode *
ewan@12117 86 add_param_struct(xmlNode *);
ewan@12117 87 static xmlNode *
ewan@12117 88 add_struct_array(xmlNode *, const char *);
ewan@12117 89 static void
ewan@12117 90 add_struct_member(xmlNode *, const char *, const char *, const char *);
ewan@12117 91 static void
ewan@12117 92 add_unnamed_value(xmlNode *, const char *, const char *, const char *);
ewan@12117 93
ewan@12117 94 static void
ewan@12117 95 add_struct_value(const struct abstract_type *, void *,
ewan@12117 96 void (*)(xmlNode *, const char *, const char *,
ewan@12117 97 const char *),
ewan@12117 98 const char *, xmlNode *);
ewan@12117 99
ewan@12117 100 static void
ewan@12117 101 call_raw(xen_session *, const char *, abstract_value [], int,
ewan@12117 102 const abstract_type *, void *);
ewan@12117 103
ewan@12117 104 static void
ewan@12117 105 parse_structmap_value(xen_session *, xmlNode *, const abstract_type *,
ewan@12117 106 void *);
ewan@12117 107
ewan@12117 108 static size_t size_of_member(const abstract_type *);
ewan@12117 109
ewan@12117 110
ewan@12117 111 void
ewan@12117 112 xen_init(void)
ewan@12117 113 {
ewan@12117 114 responsePath =
ewan@12117 115 xmlXPathCompile(
ewan@12117 116 BAD_CAST(
ewan@12117 117 "/methodResponse/params/param/value/struct/member/value"));
ewan@12117 118 faultPath =
ewan@12117 119 xmlXPathCompile(
ewan@12117 120 BAD_CAST("/methodResponse/fault/value/struct/member/value"));
ewan@12117 121 }
ewan@12117 122
ewan@12117 123
ewan@12117 124 void
ewan@12117 125 xen_fini(void)
ewan@12117 126 {
ewan@12117 127 xmlXPathFreeCompExpr(responsePath);
ewan@12117 128 xmlXPathFreeCompExpr(faultPath);
ewan@12117 129 responsePath = NULL;
ewan@12117 130 faultPath = NULL;
ewan@12117 131 }
ewan@12117 132
ewan@12117 133
ewan@12117 134 xen_session *
ewan@12117 135 xen_session_login_with_password(xen_call_func call_func, void *handle,
ewan@12117 136 const char *uname, const char *pwd)
ewan@12117 137 {
ewan@12117 138 abstract_value params[] =
ewan@12117 139 {
ewan@12117 140 { .type = &abstract_type_string,
ewan@12117 141 .u.string_val = uname },
ewan@12117 142 { .type = &abstract_type_string,
ewan@12117 143 .u.string_val = pwd }
ewan@12117 144 };
ewan@12117 145
ewan@12117 146 xen_session *session = malloc(sizeof(xen_session));
ewan@12117 147 session->call_func = call_func;
ewan@12117 148 session->handle = handle;
ewan@12117 149 session->session_id = NULL;
ewan@12117 150 session->ok = true;
ewan@12117 151 session->error_description = NULL;
ewan@12117 152 session->error_description_count = 0;
ewan@12117 153
ewan@12150 154 call_raw(session, "session.login_with_password", params, 2,
ewan@12117 155 &abstract_type_string, &session->session_id);
ewan@12117 156
ewan@12117 157 return session;
ewan@12117 158 }
ewan@12117 159
ewan@12117 160
ewan@12117 161 void
ewan@12117 162 xen_session_logout(xen_session *session)
ewan@12117 163 {
ewan@12117 164 abstract_value params[] =
ewan@12117 165 {
ewan@12117 166 };
ewan@12150 167 xen_call_(session, "session.logout", params, 0, NULL, NULL);
ewan@12117 168
ewan@12117 169 if (session->error_description != NULL)
ewan@12117 170 {
ewan@12117 171 for (int i = 0; i < session->error_description_count; i++)
ewan@12117 172 {
ewan@12117 173 free(session->error_description[i]);
ewan@12117 174 }
ewan@12117 175 free(session->error_description);
ewan@12117 176 }
ewan@12117 177
ewan@12117 178 free((char *)session->session_id);
ewan@12117 179 free(session);
ewan@12117 180 }
ewan@12117 181
ewan@12117 182
ewan@12117 183 int
ewan@12117 184 xen_session_get_this_host(xen_session *session, xen_host *result)
ewan@12117 185 {
ewan@12117 186 abstract_value params[] =
ewan@12117 187 {
ewan@12117 188 };
ewan@12117 189
ewan@12150 190 xen_call_(session, "session.get_this_host", params, 0,
ewan@12117 191 &abstract_type_string, result);
ewan@12117 192 return session->ok;
ewan@12117 193 }
ewan@12117 194
ewan@12117 195
ewan@12117 196 #define X "%02x"
ewan@12117 197 #define UUID_FORMAT X X X X "-" X X "-" X X "-" X X "-" X X X X X X
ewan@12117 198
ewan@12117 199
ewan@12117 200 bool
ewan@12117 201 xen_uuid_string_to_bytes(char *uuid, char **bytes)
ewan@12117 202 {
ewan@12117 203 unsigned int buf[16];
ewan@12117 204
ewan@12117 205 *bytes = NULL;
ewan@12117 206
ewan@12117 207 if (strlen(uuid) != 36)
ewan@12117 208 return false;
ewan@12117 209
ewan@12117 210 if (16 != sscanf(uuid, UUID_FORMAT,
ewan@12117 211 buf + 0, buf + 1, buf + 2, buf + 3,
ewan@12117 212 buf + 4, buf + 5,
ewan@12117 213 buf + 6, buf + 7,
ewan@12117 214 buf + 8, buf + 9,
ewan@12117 215 buf + 10, buf + 11, buf + 12, buf + 13, buf + 14,
ewan@12117 216 buf + 15))
ewan@12117 217 {
ewan@12117 218 return false;
ewan@12117 219 }
ewan@12117 220
ewan@12117 221 *bytes = malloc(16);
ewan@12117 222 if (*bytes == NULL)
ewan@12117 223 return false;
ewan@12117 224
ewan@12117 225 for (int i = 0; i < 16; i++) {
ewan@12117 226 (*bytes)[i] = (char)buf[i];
ewan@12117 227 }
ewan@12117 228
ewan@12117 229 return true;
ewan@12117 230 }
ewan@12117 231
ewan@12117 232
ewan@12117 233 bool
ewan@12117 234 xen_uuid_bytes_to_string(char *bytes, char **uuid)
ewan@12117 235 {
ewan@12117 236 *uuid = malloc(37);
ewan@12117 237 if (*uuid == NULL)
ewan@12117 238 return false;
ewan@12117 239
ewan@12117 240 sprintf(*uuid, UUID_FORMAT,
ewan@12117 241 bytes[0], bytes[1], bytes[2], bytes[3],
ewan@12117 242 bytes[4], bytes[5],
ewan@12117 243 bytes[6], bytes[7],
ewan@12117 244 bytes[8], bytes[9],
ewan@12117 245 bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]);
ewan@12117 246
ewan@12117 247 return true;
ewan@12117 248 }
ewan@12117 249
ewan@12117 250
ewan@12117 251 #undef UUID_FORMAT
ewan@12117 252 #undef X
ewan@12117 253
ewan@12117 254
ewan@12117 255 void
ewan@12117 256 xen_uuid_free(char *uuid)
ewan@12117 257 {
ewan@12117 258 free(uuid);
ewan@12117 259 }
ewan@12117 260
ewan@12117 261
ewan@12117 262 void
ewan@12117 263 xen_uuid_bytes_free(char *bytes)
ewan@12117 264 {
ewan@12117 265 free(bytes);
ewan@12117 266 }
ewan@12117 267
ewan@12117 268
ewan@12117 269 /**
ewan@12117 270 * @param value A pointer to the correct location as per the given
ewan@12117 271 * result_type. Will be populated if the call succeeds. In that case, and if
ewan@12117 272 * value is a char **, the char * itself must be freed by the caller.
ewan@12117 273 */
ewan@12117 274 void
ewan@12117 275 xen_call_(xen_session *s, const char *method_name,
ewan@12117 276 abstract_value params[], int param_count,
ewan@12117 277 const abstract_type *result_type, void *value)
ewan@12117 278 {
ewan@12117 279 if (!s->ok)
ewan@12117 280 {
ewan@12117 281 return;
ewan@12117 282 }
ewan@12117 283
ewan@12117 284 abstract_value *full_params =
ewan@12117 285 malloc(sizeof(abstract_value) * (param_count + 1));
ewan@12117 286
ewan@12117 287 full_params[0].type = &abstract_type_string;
ewan@12117 288 full_params[0].u.string_val = s->session_id;
ewan@12117 289
ewan@12117 290 memcpy(full_params + 1, params, param_count * sizeof(abstract_value));
ewan@12117 291
ewan@12117 292 call_raw(s, method_name, full_params, param_count + 1, result_type,
ewan@12117 293 value);
ewan@12117 294
ewan@12117 295 free(full_params);
ewan@12117 296 }
ewan@12117 297
ewan@12117 298
ewan@12117 299 static bool
ewan@12117 300 bufferAdd(const void *data, size_t len, void *buffer)
ewan@12117 301 {
ewan@12117 302 return 0 == xmlBufferAdd((xmlBufferPtr)buffer, data, len);
ewan@12117 303 }
ewan@12117 304
ewan@12117 305
ewan@12117 306 static void
ewan@12117 307 call_raw(xen_session *s, const char *method_name,
ewan@12117 308 abstract_value params[], int param_count,
ewan@12117 309 const abstract_type *result_type, void *value)
ewan@12117 310 {
ewan@12117 311 xmlBufferPtr buffer = xmlBufferCreate();
ewan@12117 312 char *body = make_body(method_name, params, param_count);
ewan@12117 313 int error_code =
ewan@12117 314 s->call_func(body, strlen(body), s->handle, buffer, &bufferAdd);
ewan@12117 315 free(body);
ewan@12117 316 if (error_code)
ewan@12117 317 {
ewan@12117 318 char **strings = malloc(2 * sizeof(char *));
ewan@12117 319
ewan@12117 320 strings[0] = xen_strdup_("TRANSPORT_FAULT");
ewan@12117 321 strings[1] = malloc(20);
ewan@12117 322 snprintf(strings[1], 20, "%d", error_code);
ewan@12117 323
ewan@12117 324 s->ok = false;
ewan@12117 325 s->error_description = strings;
ewan@12117 326 s->error_description_count = 2;
ewan@12117 327 }
ewan@12117 328 else
ewan@12117 329 {
ewan@12117 330 parse_result(s, (char *)xmlBufferContent(buffer), result_type, value);
ewan@12117 331 }
ewan@12117 332 xmlBufferFree(buffer);
ewan@12117 333 }
ewan@12117 334
ewan@12117 335
ewan@12117 336 static void server_error(xen_session *session, const char *error_string)
ewan@12117 337 {
ewan@12117 338 if (!session->ok)
ewan@12117 339 {
ewan@12117 340 /* Don't wipe out the earlier error message with this one. */
ewan@12117 341 return;
ewan@12117 342 }
ewan@12117 343
ewan@12117 344 char **strings = malloc(2 * sizeof(char *));
ewan@12117 345
ewan@12117 346 strings[0] = xen_strdup_("SERVER_FAULT");
ewan@12117 347 strings[1] = xen_strdup_(error_string);
ewan@12117 348
ewan@12117 349 session->ok = false;
ewan@12117 350 session->error_description = strings;
ewan@12117 351 session->error_description_count = 2;
ewan@12117 352 }
ewan@12117 353
ewan@12117 354
ewan@12117 355 static void server_error_2(xen_session *session, const char *error_string,
ewan@12117 356 const char *param)
ewan@12117 357 {
ewan@12117 358 if (!session->ok)
ewan@12117 359 {
ewan@12117 360 /* Don't wipe out the earlier error message with this one. */
ewan@12117 361 return;
ewan@12117 362 }
ewan@12117 363
ewan@12117 364 char **strings = malloc(3 * sizeof(char *));
ewan@12117 365
ewan@12117 366 strings[0] = xen_strdup_("SERVER_FAULT_2");
ewan@12117 367 strings[1] = xen_strdup_(error_string);
ewan@12117 368 strings[2] = xen_strdup_(param);
ewan@12117 369
ewan@12117 370 session->ok = false;
ewan@12117 371 session->error_description = strings;
ewan@12117 372 session->error_description_count = 3;
ewan@12117 373 }
ewan@12117 374
ewan@12117 375
ewan@12117 376 static bool is_container_node(xmlNode *n, char *type)
ewan@12117 377 {
ewan@12117 378 return
ewan@12117 379 n->type == XML_ELEMENT_NODE &&
ewan@12117 380 0 == strcmp((char *)n->name, type) &&
ewan@12117 381 n->children != NULL &&
ewan@12117 382 n->children == n->last &&
ewan@12117 383 n->children->type == XML_ELEMENT_NODE;
ewan@12117 384 }
ewan@12117 385
ewan@12117 386
ewan@12117 387 /**
ewan@12117 388 * @return The contents of the given value, or NULL if this is not a node with
ewan@12117 389 * the given type. If not NULL, the result must be freed with xmlFree().
ewan@12117 390 */
ewan@12117 391 static xmlChar *string_from_value(xmlNode *n, char *type)
ewan@12117 392 {
ewan@12117 393 return
ewan@12117 394 is_container_node(n, "value") &&
ewan@12117 395 0 == strcmp((char *)n->children->name, type) ?
ewan@12117 396 (n->children->children == NULL ?
ewan@12117 397 xmlStrdup(BAD_CAST("")) :
ewan@12117 398 xmlNodeGetContent(n->children->children)) :
ewan@12117 399 NULL;
ewan@12117 400 }
ewan@12117 401
ewan@12117 402
ewan@12117 403 /**
ewan@12117 404 * Find the name node that is a child of the given one, and return its
ewan@12117 405 * contents, or NULL if this has no such node. If not NULL, the result must
ewan@12117 406 * be freed with xmlFree().
ewan@12117 407 */
ewan@12117 408 static xmlChar *string_from_name(xmlNode *n)
ewan@12117 409 {
ewan@12117 410 xmlNode *cur = n->children;
ewan@12117 411
ewan@12117 412 while (cur != NULL)
ewan@12117 413 {
ewan@12117 414 if (0 == strcmp((char *)cur->name, "name"))
ewan@12117 415 {
ewan@12117 416 return xmlNodeGetContent(cur);
ewan@12117 417 }
ewan@12117 418 cur = cur->next;
ewan@12117 419 }
ewan@12117 420
ewan@12117 421 return NULL;
ewan@12117 422 }
ewan@12117 423
ewan@12117 424
ewan@12117 425 static int count_children(xmlNode *n, const char *name)
ewan@12117 426 {
ewan@12117 427 int result = 0;
ewan@12117 428 xmlNode *cur = n->children;
ewan@12117 429
ewan@12117 430 while (cur != NULL)
ewan@12117 431 {
ewan@12117 432 if (0 == strcmp((char *)cur->name, name))
ewan@12117 433 {
ewan@12117 434 result++;
ewan@12117 435 }
ewan@12117 436 cur = cur->next;
ewan@12117 437 }
ewan@12117 438
ewan@12117 439 return result;
ewan@12117 440 }
ewan@12117 441
ewan@12117 442
ewan@12117 443 static void destring(xen_session *s, xmlChar *name, const abstract_type *type,
ewan@12117 444 void *value)
ewan@12117 445 {
ewan@12117 446 switch (type->typename)
ewan@12117 447 {
ewan@12117 448 case STRING:
ewan@12117 449 *((char **)value) = xen_strdup_((const char *)name);
ewan@12117 450 break;
ewan@12117 451
ewan@12117 452 case INT:
ewan@12181 453 *((int64_t *)value) = atoll((const char *)name);
ewan@12117 454 break;
ewan@12117 455
ewan@12117 456 case FLOAT:
ewan@12117 457 *((double *)value) = atof((const char *)name);
ewan@12117 458 break;
ewan@12117 459
ewan@12117 460 default:
ewan@12117 461 server_error(s, "Invalid Map key type");
ewan@12117 462 }
ewan@12117 463 }
ewan@12117 464
ewan@12117 465
ewan@12177 466 /**
ewan@12177 467 * result_type : STRING => value : char **, the char * is yours.
ewan@12177 468 * result_type : ENUM => value : int *
ewan@12181 469 * result_type : INT => value : int64_t *
ewan@12177 470 * result_type : FLOAT => value : double *
ewan@12177 471 * result_type : BOOL => value : bool *
ewan@12177 472 * result_type : SET => value : arbitrary_set **, the set is yours.
ewan@12177 473 * result_type : MAP => value : arbitrary_map **, the map is yours.
ewan@12177 474 * result_type : OPT => value : arbitrary_record_opt **,
ewan@12177 475 * the record is yours, the handle is filled.
ewan@12177 476 * result_type : STRUCT => value : void **, the void * is yours.
ewan@12177 477 */
ewan@12117 478 static void parse_into(xen_session *s, xmlNode *value_node,
ewan@12117 479 const abstract_type *result_type, void *value,
ewan@12117 480 int slot)
ewan@12117 481 {
ewan@12117 482 if (result_type == NULL)
ewan@12117 483 {
ewan@12117 484 xmlChar *string = string_from_value(value_node, "string");
ewan@12117 485 if (string == NULL || strcmp((char *)string, ""))
ewan@12117 486 {
ewan@12117 487 server_error(s,
ewan@12117 488 "Expected Void from the server, but didn't get it");
ewan@12117 489 }
ewan@12117 490 else
ewan@12117 491 {
ewan@12117 492 free(string);
ewan@12117 493 }
ewan@12117 494
ewan@12117 495 return;
ewan@12117 496 }
ewan@12117 497
ewan@12117 498 switch (result_type->typename)
ewan@12117 499 {
ewan@12117 500 case STRING:
ewan@12117 501 {
ewan@12117 502 xmlChar *string = string_from_value(value_node, "string");
ewan@12117 503 if (string == NULL)
ewan@12117 504 {
ewan@12117 505 server_error(
ewan@12117 506 s, "Expected a String from the server, but didn't get one");
ewan@12117 507 }
ewan@12117 508 else
ewan@12117 509 {
ewan@12117 510 ((char **)value)[slot] = xen_strdup_((const char *)string);
ewan@12117 511 free(string);
ewan@12117 512 }
ewan@12117 513 }
ewan@12117 514 break;
ewan@12117 515
ewan@12117 516 case ENUM:
ewan@12117 517 {
ewan@12117 518 xmlChar *string = string_from_value(value_node, "string");
ewan@12117 519 if (string == NULL)
ewan@12117 520 {
ewan@12783 521 #if PERMISSIVE
ewan@12783 522 fprintf(stderr,
ewan@12783 523 "Expected an Enum from the server, but didn't get one\n");
ewan@12783 524 ((int *)value)[slot] = 0;
ewan@12783 525 #else
ewan@12117 526 server_error(
ewan@12117 527 s, "Expected an Enum from the server, but didn't get one");
ewan@12783 528 #endif
ewan@12117 529 }
ewan@12117 530 else
ewan@12117 531 {
ewan@12117 532 ((int *)value)[slot] =
ewan@12117 533 result_type->enum_demarshaller(s, (const char *)string);
ewan@12117 534 free(string);
ewan@12117 535 }
ewan@12117 536 }
ewan@12117 537 break;
ewan@12117 538
ewan@12117 539 case INT:
ewan@12117 540 {
ewan@12117 541 xmlChar *string = string_from_value(value_node, "string");
ewan@12117 542 if (string == NULL)
ewan@12117 543 {
ewan@12117 544 server_error(
ewan@12117 545 s, "Expected an Int from the server, but didn't get one");
ewan@12117 546 }
ewan@12117 547 else
ewan@12117 548 {
ewan@12181 549 ((int64_t *)value)[slot] = (int64_t)atoll((char *)string);
ewan@12117 550 free(string);
ewan@12117 551 }
ewan@12117 552 }
ewan@12117 553 break;
ewan@12117 554
ewan@12117 555 case FLOAT:
ewan@12117 556 {
ewan@12117 557 xmlChar *string = string_from_value(value_node, "double");
ewan@12117 558 if (string == NULL)
ewan@12117 559 {
ewan@12117 560 server_error(
ewan@12117 561 s, "Expected a Float from the server, but didn't get one");
ewan@12117 562 }
ewan@12117 563 else
ewan@12117 564 {
ewan@12117 565 ((double *)value)[slot] = atof((char *)string);
ewan@12117 566 free(string);
ewan@12117 567 }
ewan@12117 568 }
ewan@12117 569 break;
ewan@12117 570
ewan@12117 571 case BOOL:
ewan@12117 572 {
ewan@12117 573 xmlChar *string = string_from_value(value_node, "boolean");
ewan@12117 574 if (string == NULL)
ewan@12117 575 {
ewan@12783 576 #if PERMISSIVE
ewan@12783 577 fprintf(stderr,
ewan@12783 578 "Expected a Bool from the server, but didn't get one\n");
ewan@12783 579 ((bool *)value)[slot] = false;
ewan@12783 580 #else
ewan@12117 581 server_error(
ewan@12117 582 s, "Expected a Bool from the server, but didn't get one");
ewan@12783 583 #endif
ewan@12117 584 }
ewan@12117 585 else
ewan@12117 586 {
ewan@12117 587 ((bool *)value)[slot] = (0 == strcmp((char *)string, "1"));
ewan@12117 588 free(string);
ewan@12117 589 }
ewan@12117 590 }
ewan@12117 591 break;
ewan@12117 592
ewan@12117 593 case SET:
ewan@12117 594 {
ewan@12117 595 if (!is_container_node(value_node, "value") ||
ewan@12117 596 !is_container_node(value_node->children, "array"))
ewan@12117 597 {
ewan@12117 598 server_error(s,
ewan@12117 599 "Expected Set from the server, but didn't get it");
ewan@12117 600 }
ewan@12117 601 else
ewan@12117 602 {
ewan@12117 603 xmlNode *data_node = value_node->children->children;
ewan@12117 604 int n = count_children(data_node, "value");
ewan@12117 605
ewan@12117 606 const abstract_type *member_type = result_type->child;
ewan@12117 607 size_t member_size = size_of_member(member_type);
ewan@12117 608
ewan@12117 609 arbitrary_set *set =
ewan@12117 610 calloc(1, sizeof(arbitrary_set) + member_size * n);
ewan@12117 611 set->size = n;
ewan@12117 612 int i = 0;
ewan@12117 613 xmlNode *cur = data_node->children;
ewan@12117 614
ewan@12117 615 while (cur != NULL)
ewan@12117 616 {
ewan@12117 617 if (0 == strcmp((char *)cur->name, "value"))
ewan@12117 618 {
ewan@12117 619 parse_into(s, cur, member_type, set->contents, i);
ewan@12117 620 i++;
ewan@12117 621 }
ewan@12117 622 cur = cur->next;
ewan@12117 623 }
ewan@12117 624
ewan@12117 625 ((arbitrary_set **)value)[slot] = set;
ewan@12117 626 }
ewan@12117 627 }
ewan@12117 628 break;
ewan@12117 629
ewan@12117 630 case MAP:
ewan@12117 631 {
ewan@12117 632 if (!is_container_node(value_node, "value") ||
ewan@12117 633 value_node->children->type != XML_ELEMENT_NODE ||
ewan@12117 634 0 != strcmp((char *)value_node->children->name, "struct") ||
ewan@12117 635 value_node->children->children == NULL)
ewan@12117 636 {
ewan@12117 637 server_error(s,
ewan@12117 638 "Expected Map from the server, but didn't get it");
ewan@12117 639 }
ewan@12117 640 else
ewan@12117 641 {
ewan@12117 642 xmlNode *struct_node = value_node->children;
ewan@12117 643 int n = count_children(struct_node, "member");
ewan@12117 644
ewan@12117 645 size_t struct_size = result_type->struct_size;
ewan@12117 646
ewan@12117 647 const struct struct_member *key_member = result_type->members;
ewan@12117 648 const struct struct_member *val_member = result_type->members + 1;
ewan@12117 649
ewan@12117 650 arbitrary_map *map =
ewan@12117 651 calloc(1, sizeof(arbitrary_map) + struct_size * n);
ewan@12117 652 map->size = n;
ewan@12117 653 int i = 0;
ewan@12117 654 xmlNode *cur = struct_node->children;
ewan@12117 655
ewan@12117 656 while (cur != NULL)
ewan@12117 657 {
ewan@12117 658 if (0 == strcmp((char *)cur->name, "member"))
ewan@12117 659 {
ewan@12117 660 if (cur->children == NULL || cur->last == cur->children)
ewan@12117 661 {
ewan@12117 662 server_error(s, "Malformed Map");
ewan@12117 663 free(map);
ewan@12117 664 return;
ewan@12117 665 }
ewan@12117 666
ewan@12117 667 xmlChar *name = string_from_name(cur);
ewan@12117 668 if (name == NULL)
ewan@12117 669 {
ewan@12117 670 server_error(s, "Malformed Map");
ewan@12117 671 free(map);
ewan@12117 672 return;
ewan@12117 673 }
ewan@12117 674
ewan@12117 675 destring(s, name, key_member->type,
ewan@12117 676 ((void *)(map + 1)) +
ewan@12117 677 (i * struct_size) +
ewan@12117 678 key_member->offset);
ewan@12117 679 xmlFree(name);
ewan@12117 680 if (!s->ok)
ewan@12117 681 {
ewan@12117 682 free(map);
ewan@12117 683 return;
ewan@12117 684 }
ewan@12117 685
ewan@12117 686 parse_structmap_value(s, cur, val_member->type,
ewan@12117 687 ((void *)(map + 1)) +
ewan@12117 688 (i * struct_size) +
ewan@12117 689 val_member->offset);
ewan@12117 690 if (!s->ok)
ewan@12117 691 {
ewan@12117 692 free(map);
ewan@12117 693 return;
ewan@12117 694 }
ewan@12117 695 i++;
ewan@12117 696 }
ewan@12117 697 cur = cur->next;
ewan@12117 698 }
ewan@12117 699
ewan@12117 700 ((arbitrary_map **)value)[slot] = map;
ewan@12117 701 }
ewan@12117 702 }
ewan@12117 703 break;
ewan@12117 704
ewan@12117 705 case STRUCT:
ewan@12117 706 {
ewan@12117 707 if (!is_container_node(value_node, "value") ||
ewan@12117 708 value_node->children->type != XML_ELEMENT_NODE ||
ewan@12117 709 0 != strcmp((char *)value_node->children->name, "struct") ||
ewan@12117 710 value_node->children->children == NULL)
ewan@12117 711 {
ewan@12117 712 server_error(s,
ewan@12117 713 "Expected Map from the server, but didn't get it");
ewan@12117 714 }
ewan@12117 715 else
ewan@12117 716 {
ewan@12117 717 xmlNode *struct_node = value_node->children;
ewan@12117 718
ewan@12117 719 void *result = calloc(1, result_type->struct_size);
ewan@12117 720 xmlNode *cur = struct_node->children;
ewan@12117 721
ewan@12117 722 size_t member_count = result_type->member_count;
ewan@12117 723
ewan@12117 724 const struct_member **checklist =
ewan@12117 725 malloc(sizeof(const struct_member *) * member_count);
ewan@12117 726 int seen_count = 0;
ewan@12117 727
ewan@12117 728 while (cur != NULL)
ewan@12117 729 {
ewan@12117 730 if (0 == strcmp((char *)cur->name, "member"))
ewan@12117 731 {
ewan@12117 732 if (cur->children == NULL || cur->last == cur->children)
ewan@12117 733 {
ewan@12117 734 server_error(s, "Malformed Struct");
ewan@12117 735 free(result);
ewan@12117 736 free(checklist);
ewan@12117 737 return;
ewan@12117 738 }
ewan@12117 739
ewan@12117 740 xmlChar *name = string_from_name(cur);
ewan@12117 741 if (name == NULL)
ewan@12117 742 {
ewan@12117 743 server_error(s, "Malformed Struct");
ewan@12117 744 free(result);
ewan@12117 745 free(checklist);
ewan@12117 746 return;
ewan@12117 747 }
ewan@12117 748
ewan@12117 749 for (size_t i = 0; i < member_count; i++)
ewan@12117 750 {
ewan@12117 751 const struct_member *mem = result_type->members + i;
ewan@12117 752
ewan@12117 753 if (0 == strcmp((char *)name, mem->key))
ewan@12117 754 {
ewan@12117 755 parse_structmap_value(s, cur, mem->type,
ewan@12117 756 result + mem->offset);
ewan@12117 757 checklist[seen_count] = mem;
ewan@12117 758 seen_count++;
ewan@12117 759 break;
ewan@12117 760 }
ewan@12117 761 }
ewan@12117 762
ewan@12117 763 /* Note that we're skipping unknown fields implicitly.
ewan@12117 764 This means that we'll be forward compatible with
ewan@12117 765 new servers. */
ewan@12117 766
ewan@12117 767 xmlFree(name);
ewan@12117 768
ewan@12117 769 if (!s->ok)
ewan@12117 770 {
ewan@12117 771 free(result);
ewan@12117 772 free(checklist);
ewan@12117 773 return;
ewan@12117 774 }
ewan@12117 775 }
ewan@12117 776 cur = cur->next;
ewan@12117 777 }
ewan@12117 778
ewan@12117 779 /* Check that we've filled all fields. */
ewan@12117 780 for (size_t i = 0; i < member_count; i++)
ewan@12117 781 {
ewan@12117 782 const struct_member *mem = result_type->members + i;
ewan@12117 783 int j;
ewan@12117 784
ewan@12117 785 for (j = 0; j < seen_count; j++)
ewan@12117 786 {
ewan@12117 787 if (checklist[j] == mem)
ewan@12117 788 {
ewan@12117 789 break;
ewan@12117 790 }
ewan@12117 791 }
ewan@12117 792
ewan@12117 793 if (j == seen_count)
ewan@12117 794 {
ewan@12783 795 #if PERMISSIVE
ewan@12783 796 fprintf(stderr,
ewan@12783 797 "Struct did not contain expected field %s.\n",
ewan@12783 798 mem->key);
ewan@12783 799 #else
ewan@12117 800 server_error_2(s,
ewan@12117 801 "Struct did not contain expected field",
ewan@12117 802 mem->key);
ewan@12117 803 free(result);
ewan@12117 804 free(checklist);
ewan@12117 805 return;
ewan@12783 806 #endif
ewan@12117 807 }
ewan@12117 808 }
ewan@12117 809
ewan@12117 810 free(checklist);
ewan@12117 811 ((void **)value)[slot] = result;
ewan@12117 812 }
ewan@12117 813 }
ewan@12117 814 break;
ewan@12117 815
ewan@12117 816 case REF:
ewan@12117 817 {
ewan@12117 818 arbitrary_record_opt *record_opt =
ewan@12117 819 calloc(1, sizeof(arbitrary_record_opt));
ewan@12117 820
ewan@12117 821 record_opt->is_record = false;
ewan@12117 822 parse_into(s, value_node, &abstract_type_string,
ewan@12117 823 &(record_opt->u.handle), 0);
ewan@12117 824
ewan@12117 825 ((arbitrary_record_opt **)value)[slot] = record_opt;
ewan@12117 826 }
ewan@12117 827 break;
ewan@12117 828
ewan@12117 829 default:
ewan@12117 830 assert(false);
ewan@12117 831 }
ewan@12117 832 }
ewan@12117 833
ewan@12117 834
ewan@12117 835 static size_t size_of_member(const abstract_type *type)
ewan@12117 836 {
ewan@12117 837 switch (type->typename)
ewan@12117 838 {
ewan@12117 839 case STRING:
ewan@12117 840 return sizeof(char *);
ewan@12117 841
ewan@12117 842 /*
ewan@12117 843 case INT:
ewan@12181 844 return sizeof(int64_t);
ewan@12117 845
ewan@12117 846 case FLOAT:
ewan@12117 847 return sizeof(double);
ewan@12117 848
ewan@12117 849 case BOOL:
ewan@12117 850 return sizeof(bool);
ewan@12117 851 */
ewan@12117 852 case ENUM:
ewan@12117 853 return sizeof(int);
ewan@12117 854
ewan@12117 855 case REF:
ewan@12177 856 return sizeof(arbitrary_record_opt *);
ewan@12117 857
ewan@12117 858 default:
ewan@12117 859 assert(false);
ewan@12117 860 }
ewan@12117 861 }
ewan@12117 862
ewan@12117 863
ewan@12117 864 static void parse_structmap_value(xen_session *s, xmlNode *n,
ewan@12117 865 const abstract_type *type, void *value)
ewan@12117 866 {
ewan@12117 867 xmlNode *cur = n->children;
ewan@12117 868
ewan@12117 869 while (cur != NULL)
ewan@12117 870 {
ewan@12117 871 if (0 == strcmp((char *)cur->name, "value"))
ewan@12117 872 {
ewan@12117 873 parse_into(s, cur, type, value, 0);
ewan@12117 874 return;
ewan@12117 875 }
ewan@12117 876 cur = cur->next;
ewan@12117 877 }
ewan@12117 878
ewan@12117 879 server_error(s, "Missing value in Map/Struct");
ewan@12117 880 }
ewan@12117 881
ewan@12117 882
ewan@12117 883 static void parse_fault(xen_session *session, xmlXPathContextPtr xpathCtx)
ewan@12117 884 {
ewan@12117 885 xmlXPathObjectPtr xpathObj = xmlXPathCompiledEval(faultPath, xpathCtx);
ewan@12117 886 if (xpathObj == NULL)
ewan@12117 887 {
ewan@12117 888 server_error(session, "Method response is neither result nor fault");
ewan@12117 889 return;
ewan@12117 890 }
ewan@12117 891
ewan@12117 892 if (xpathObj->type != XPATH_NODESET ||
ewan@12117 893 xpathObj->nodesetval->nodeNr != 2)
ewan@12117 894 {
ewan@12117 895 xmlXPathFreeObject(xpathObj);
ewan@12117 896 server_error(session, "Method response is neither result nor fault");
ewan@12117 897 return;
ewan@12117 898 }
ewan@12117 899
ewan@12117 900 xmlNode *fault_node0 = xpathObj->nodesetval->nodeTab[0];
ewan@12117 901 xmlNode *fault_node1 = xpathObj->nodesetval->nodeTab[1];
ewan@12117 902
ewan@12117 903 xmlChar *fault_code_str = string_from_value(fault_node0, "int");
ewan@12117 904 if (fault_code_str == NULL)
ewan@12117 905 {
ewan@12117 906 fault_code_str = string_from_value(fault_node0, "i4");
ewan@12117 907 }
ewan@12117 908 if (fault_code_str == NULL)
ewan@12117 909 {
ewan@12117 910 xmlXPathFreeObject(xpathObj);
ewan@12117 911 server_error(session, "Fault code is malformed");
ewan@12117 912 return;
ewan@12117 913 }
ewan@12117 914
ewan@12117 915 xmlChar *fault_string_str = string_from_value(fault_node1, "string");
ewan@12117 916 if (fault_string_str == NULL)
ewan@12117 917 {
ewan@12117 918 xmlFree(fault_code_str);
ewan@12117 919 xmlXPathFreeObject(xpathObj);
ewan@12117 920 server_error(session, "Fault string is malformed");
ewan@12117 921 return;
ewan@12117 922 }
ewan@12117 923
ewan@12117 924 char **strings = malloc(3 * sizeof(char *));
ewan@12117 925
ewan@12117 926 strings[0] = xen_strdup_("FAULT");
ewan@12117 927 strings[1] = xen_strdup_((char *)fault_code_str);
ewan@12117 928 strings[2] = xen_strdup_((char *)fault_string_str);
ewan@12117 929
ewan@12117 930 session->ok = false;
ewan@12117 931 session->error_description = strings;
ewan@12117 932 session->error_description_count = 3;
ewan@12117 933
ewan@12117 934 xmlFree(fault_code_str);
ewan@12117 935 xmlFree(fault_string_str);
ewan@12117 936 xmlXPathFreeObject(xpathObj);
ewan@12117 937 }
ewan@12117 938
ewan@12117 939
ewan@12117 940 static void parse_failure(xen_session *session, xmlNode *node)
ewan@12117 941 {
ewan@12117 942 abstract_type error_description_type =
ewan@12117 943 { .typename = SET,
ewan@12117 944 .child = &abstract_type_string };
ewan@12117 945 arbitrary_set *error_descriptions;
ewan@12117 946
ewan@12117 947 parse_into(session, node, &error_description_type, &error_descriptions,
ewan@12117 948 0);
ewan@12117 949
ewan@12117 950 if (session->ok)
ewan@12117 951 {
ewan@12117 952 session->ok = false;
ewan@12117 953
ewan@12117 954 char **c = (char **)error_descriptions->contents;
ewan@12117 955 int n = error_descriptions->size;
ewan@12117 956
ewan@12117 957 char **strings = malloc(3 * sizeof(char *));
ewan@12117 958 for (int i = 0; i < n; i++)
ewan@12117 959 {
ewan@12117 960 strings[i] = xen_strdup_(c[i]);
ewan@12117 961 }
ewan@12117 962
ewan@12117 963 session->error_description_count = n;
ewan@12117 964 session->error_description = strings;
ewan@12117 965 }
ewan@12117 966
ewan@12117 967 free(error_descriptions);
ewan@12117 968 }
ewan@12117 969
ewan@12117 970
ewan@12117 971 /**
ewan@12117 972 * Parameters as for xen_call_() above.
ewan@12117 973 */
ewan@12117 974 static void parse_result(xen_session *session, const char *result,
ewan@12117 975 const abstract_type *result_type, void *value)
ewan@12117 976 {
ewan@12117 977 xmlDocPtr doc =
ewan@12117 978 xmlReadMemory(result, strlen(result), "", NULL, XML_PARSE_NONET);
ewan@12117 979
ewan@12117 980 if (doc == NULL)
ewan@12117 981 {
ewan@12117 982 server_error(session, "Couldn't parse the server response");
ewan@12117 983 return;
ewan@12117 984 }
ewan@12117 985
ewan@12117 986 xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
ewan@12117 987 if (xpathCtx == NULL)
ewan@12117 988 {
ewan@12117 989 xmlFreeDoc(doc);
ewan@12117 990 server_error(session, "Couldn't create XPath context");
ewan@12117 991 return;
ewan@12117 992 }
ewan@12117 993
ewan@12117 994 xmlXPathObjectPtr xpathObj =
ewan@12117 995 xmlXPathCompiledEval(responsePath, xpathCtx);
ewan@12117 996 if (xpathObj == NULL)
ewan@12117 997 {
ewan@12117 998 parse_fault(session, xpathCtx);
ewan@12117 999
ewan@12117 1000 xmlXPathFreeContext(xpathCtx);
ewan@12117 1001 xmlFreeDoc(doc);
ewan@12117 1002 return;
ewan@12117 1003 }
ewan@12117 1004
ewan@12117 1005 if (xpathObj->type != XPATH_NODESET ||
ewan@12117 1006 xpathObj->nodesetval->nodeNr != 2)
ewan@12117 1007 {
ewan@12117 1008 parse_fault(session, xpathCtx);
ewan@12117 1009
ewan@12117 1010 xmlXPathFreeObject(xpathObj);
ewan@12117 1011 xmlXPathFreeContext(xpathCtx);
ewan@12117 1012 xmlFreeDoc(doc);
ewan@12117 1013 return;
ewan@12117 1014 }
ewan@12117 1015
ewan@12117 1016 xmlNode *node0 = xpathObj->nodesetval->nodeTab[0];
ewan@12117 1017 xmlNode *node1 = xpathObj->nodesetval->nodeTab[1];
ewan@12117 1018
ewan@12117 1019 xmlChar *status_code = string_from_value(node0, "string");
ewan@12117 1020 if (status_code == NULL)
ewan@12117 1021 {
ewan@12117 1022 xmlXPathFreeObject(xpathObj);
ewan@12117 1023 xmlXPathFreeContext(xpathCtx);
ewan@12117 1024 xmlFreeDoc(doc);
ewan@12117 1025 server_error(session, "Server response does not have a Status");
ewan@12117 1026 return;
ewan@12117 1027 }
ewan@12117 1028
ewan@12117 1029 if (strcmp((char *)status_code, "Success"))
ewan@12117 1030 {
ewan@12117 1031 parse_failure(session, node1);
ewan@12117 1032
ewan@12117 1033 xmlFree(status_code);
ewan@12117 1034 xmlXPathFreeObject(xpathObj);
ewan@12117 1035 xmlXPathFreeContext(xpathCtx);
ewan@12117 1036 xmlFreeDoc(doc);
ewan@12117 1037 return;
ewan@12117 1038 }
ewan@12117 1039
ewan@12117 1040 parse_into(session, node1, result_type, value, 0);
ewan@12117 1041
ewan@12117 1042 xmlFree(status_code);
ewan@12117 1043 xmlXPathFreeObject(xpathObj);
ewan@12117 1044 xmlXPathFreeContext(xpathCtx);
ewan@12117 1045 xmlFreeDoc(doc);
ewan@12117 1046 }
ewan@12117 1047
ewan@12117 1048
ewan@12117 1049 static char *
ewan@12117 1050 make_body(const char *method_name, abstract_value params[], int param_count)
ewan@12117 1051 {
ewan@12117 1052 char buf[20];
ewan@12117 1053
ewan@12117 1054 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
ewan@12117 1055 xmlNode *methodCall = xmlNewNode(NULL, BAD_CAST "methodCall");
ewan@12117 1056 xmlDocSetRootElement(doc, methodCall);
ewan@12117 1057
ewan@12117 1058 xmlNewChild(methodCall, NULL, BAD_CAST "methodName",
ewan@12117 1059 BAD_CAST method_name);
ewan@12117 1060
ewan@12117 1061 xmlNode *params_node =
ewan@12117 1062 xmlNewChild(methodCall, NULL, BAD_CAST "params", NULL);
ewan@12117 1063
ewan@12117 1064 for (int p = 0; p < param_count; p++)
ewan@12117 1065 {
ewan@12117 1066 abstract_value *v = params + p;
ewan@12117 1067 switch (v->type->typename)
ewan@12117 1068 {
ewan@12117 1069 case STRING:
ewan@12117 1070 add_param(params_node, "string", v->u.string_val);
ewan@12117 1071 break;
ewan@12117 1072
ewan@12117 1073 case INT:
ewan@12117 1074 snprintf(buf, sizeof(buf), "%"PRId64, v->u.int_val);
ewan@12117 1075 add_param(params_node, "string", buf);
ewan@12117 1076 break;
ewan@12117 1077
ewan@12117 1078 case FLOAT:
ewan@12357 1079 snprintf(buf, sizeof(buf), "%lf", v->u.float_val);
ewan@12117 1080 add_param(params_node, "double", buf);
ewan@12117 1081 break;
ewan@12117 1082
ewan@12117 1083 case BOOL:
ewan@12117 1084 add_param(params_node, "boolean", v->u.bool_val ? "1" : "0");
ewan@12117 1085 break;
ewan@12117 1086
ewan@12117 1087 case VOID:
ewan@12117 1088 add_param(params_node, "string", "");
ewan@12117 1089 break;
ewan@12117 1090
ewan@12117 1091 case ENUM:
ewan@12117 1092 add_param(params_node, "string",
ewan@12117 1093 v->type->enum_marshaller(v->u.enum_val));
ewan@12117 1094 break;
ewan@12117 1095
ewan@12117 1096 case STRUCT:
ewan@12117 1097 {
ewan@12117 1098 size_t member_count = v->type->member_count;
ewan@12117 1099
ewan@12117 1100 xmlNode *struct_node = add_param_struct(params_node);
ewan@12117 1101
ewan@12117 1102 for (size_t i = 0; i < member_count; i++)
ewan@12117 1103 {
ewan@12117 1104 const struct struct_member *mem = v->type->members + i;
ewan@12117 1105 const char *key = mem->key;
ewan@12117 1106 void *struct_value = v->u.struct_val;
ewan@12117 1107
ewan@12117 1108 add_struct_value(mem->type, struct_value + mem->offset,
ewan@12117 1109 add_struct_member, key, struct_node);
ewan@12117 1110 }
ewan@12117 1111 }
ewan@12117 1112 break;
ewan@12117 1113
ewan@12117 1114 default:
ewan@12117 1115 assert(false);
ewan@12117 1116 }
ewan@12117 1117 }
ewan@12117 1118
ewan@12117 1119 xmlBufferPtr buffer = xmlBufferCreate();
ewan@12117 1120 xmlSaveCtxtPtr save_ctxt =
ewan@12117 1121 xmlSaveToBuffer(buffer, NULL, XML_SAVE_NO_XHTML);
ewan@12117 1122
ewan@12117 1123 if (xmlSaveDoc(save_ctxt, doc) == -1)
ewan@12117 1124 {
ewan@12117 1125 return NULL;
ewan@12117 1126 }
ewan@12117 1127
ewan@12117 1128 xmlFreeDoc(doc);
ewan@12117 1129 xmlSaveClose(save_ctxt);
ewan@12117 1130 xmlChar *content = xmlStrdup(xmlBufferContent(buffer));
ewan@12117 1131 xmlBufferFree(buffer);
ewan@12117 1132 return (char *)content;
ewan@12117 1133 }
ewan@12117 1134
ewan@12117 1135
ewan@12117 1136 static void
ewan@12117 1137 add_struct_value(const struct abstract_type *type, void *value,
ewan@12117 1138 void (*adder)(xmlNode *node, const char *key,
ewan@12117 1139 const char *type, const char *val),
ewan@12117 1140 const char *key, xmlNode *node)
ewan@12117 1141 {
ewan@12117 1142 char buf[20];
ewan@12117 1143
ewan@12117 1144 switch (type->typename)
ewan@12117 1145 {
ewan@12117 1146 case REF:
ewan@12177 1147 {
ewan@12177 1148 arbitrary_record_opt *val = *(arbitrary_record_opt **)value;
ewan@12177 1149 if (val != NULL)
ewan@12177 1150 {
ewan@12177 1151 if (val->is_record)
ewan@12177 1152 {
ewan@12177 1153 adder(node, key, "string", val->u.record->handle);
ewan@12177 1154 }
ewan@12177 1155 else
ewan@12177 1156 {
ewan@12177 1157 adder(node, key, "string", val->u.handle);
ewan@12177 1158 }
ewan@12177 1159 }
ewan@12177 1160 }
ewan@12177 1161 break;
ewan@12177 1162
ewan@12117 1163 case STRING:
ewan@12117 1164 {
ewan@12117 1165 char *val = *(char **)value;
ewan@12117 1166 if (val != NULL)
ewan@12117 1167 {
ewan@12117 1168 adder(node, key, "string", val);
ewan@12117 1169 }
ewan@12117 1170 }
ewan@12117 1171 break;
ewan@12117 1172
ewan@12117 1173 case INT:
ewan@12117 1174 {
ewan@12181 1175 int64_t val = *(int64_t *)value;
ewan@12117 1176 snprintf(buf, sizeof(buf), "%"PRId64, val);
ewan@12117 1177 adder(node, key, "string", buf);
ewan@12117 1178 }
ewan@12117 1179 break;
ewan@12117 1180
ewan@12117 1181 case FLOAT:
ewan@12117 1182 {
ewan@12117 1183 double val = *(double *)value;
ewan@12117 1184 snprintf(buf, sizeof(buf), "%lf", val);
ewan@12117 1185 adder(node, key, "double", buf);
ewan@12117 1186 }
ewan@12117 1187 break;
ewan@12117 1188
ewan@12117 1189 case BOOL:
ewan@12117 1190 {
ewan@12117 1191 bool val = *(bool *)value;
ewan@12117 1192 adder(node, key, "boolean", val ? "1" : "0");
ewan@12117 1193 }
ewan@12117 1194 break;
ewan@12117 1195
ewan@12117 1196 case ENUM:
ewan@12117 1197 {
ewan@12117 1198 int val = *(int *)value;
ewan@12117 1199 adder(node, key, "string", type->enum_marshaller(val));
ewan@12117 1200 }
ewan@12117 1201 break;
ewan@12117 1202
ewan@12117 1203 case SET:
ewan@12117 1204 {
ewan@12117 1205 const struct abstract_type *member_type = type->child;
ewan@12117 1206 size_t member_size = size_of_member(member_type);
ewan@12117 1207 arbitrary_set *set_val = *(arbitrary_set **)value;
ewan@12117 1208
ewan@12117 1209 if (set_val != NULL)
ewan@12117 1210 {
ewan@12117 1211 xmlNode *data_node = add_struct_array(node, key);
ewan@12117 1212
ewan@12117 1213 for (size_t i = 0; i < set_val->size; i++)
ewan@12117 1214 {
ewan@12117 1215 void *member_value = set_val->contents + (i * member_size);
ewan@12117 1216 add_struct_value(member_type, member_value,
ewan@12117 1217 add_unnamed_value, NULL, data_node);
ewan@12117 1218 }
ewan@12117 1219 }
ewan@12117 1220 }
ewan@12117 1221 break;
ewan@12117 1222
ewan@12117 1223 case STRUCT:
ewan@12117 1224 case MAP:
ewan@12117 1225 {
ewan@12117 1226 /* XXX Nested structures aren't supported yet, but
ewan@12117 1227 fortunately we don't need them, because we don't have
ewan@12117 1228 any "deep create" calls. This will need to be
ewan@12117 1229 fixed. We don't need maps either. */
ewan@12117 1230 }
ewan@12117 1231 break;
ewan@12117 1232
ewan@12117 1233 default:
ewan@12117 1234 assert(false);
ewan@12117 1235 }
ewan@12117 1236 }
ewan@12117 1237
ewan@12117 1238
ewan@12117 1239 static xmlNode *
ewan@12117 1240 add_container(xmlNode *parent, const char *name)
ewan@12117 1241 {
ewan@12117 1242 return xmlNewChild(parent, NULL, BAD_CAST name, NULL);
ewan@12117 1243 }
ewan@12117 1244
ewan@12117 1245
ewan@12117 1246 static void
ewan@12117 1247 add_param(xmlNode *params_node, const char *type, const char *value)
ewan@12117 1248 {
ewan@12117 1249 xmlNode *param_node = add_container(params_node, "param");
ewan@12117 1250 add_value(param_node, type, value);
ewan@12117 1251 }
ewan@12117 1252
ewan@12117 1253
ewan@12117 1254 static void
ewan@12117 1255 add_value(xmlNode *parent, const char *type, const char *value)
ewan@12117 1256 {
ewan@12117 1257 xmlNode *value_node = add_container(parent, "value");
ewan@12117 1258 xmlNewChild(value_node, NULL, BAD_CAST type, BAD_CAST value);
ewan@12117 1259 }
ewan@12117 1260
ewan@12117 1261
ewan@12117 1262 static void
ewan@12117 1263 add_unnamed_value(xmlNode *parent, const char *name, const char *type,
ewan@12117 1264 const char *value)
ewan@12117 1265 {
ewan@12117 1266 (void)name;
ewan@12117 1267 add_value(parent, type, value);
ewan@12117 1268 }
ewan@12117 1269
ewan@12117 1270
ewan@12117 1271 static xmlNode *
ewan@12117 1272 add_param_struct(xmlNode *params_node)
ewan@12117 1273 {
ewan@12117 1274 xmlNode *param_node = add_container(params_node, "param");
ewan@12117 1275 xmlNode *value_node = add_container(param_node, "value");
ewan@12117 1276
ewan@12117 1277 return xmlNewChild(value_node, NULL, BAD_CAST "struct", NULL);
ewan@12117 1278 }
ewan@12117 1279
ewan@12117 1280
ewan@12117 1281 static void
ewan@12117 1282 add_struct_member(xmlNode *struct_node, const char *name, const char *type,
ewan@12117 1283 const char *value)
ewan@12117 1284 {
ewan@12117 1285 xmlNode *member_node = add_container(struct_node, "member");
ewan@12117 1286
ewan@12117 1287 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
ewan@12117 1288
ewan@12117 1289 add_value(member_node, type, value);
ewan@12117 1290 }
ewan@12117 1291
ewan@12117 1292
ewan@12117 1293 static xmlNode *
ewan@12117 1294 add_struct_array(xmlNode *struct_node, const char *name)
ewan@12117 1295 {
ewan@12117 1296 xmlNode *member_node = add_container(struct_node, "member");
ewan@12117 1297
ewan@12117 1298 xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
ewan@12117 1299
ewan@12117 1300 xmlNode *value_node = add_container(member_node, "value");
ewan@12117 1301 xmlNode *array_node = add_container(value_node, "array");
ewan@12117 1302
ewan@12117 1303 return add_container(array_node, "data");
ewan@12117 1304
ewan@12117 1305 }
ewan@12117 1306
ewan@12117 1307
ewan@12117 1308 int xen_enum_lookup_(xen_session *session, const char *str,
ewan@12117 1309 const char **lookup_table, int n)
ewan@12117 1310 {
ewan@12117 1311 if (str != NULL)
ewan@12117 1312 {
ewan@12117 1313 for (int i = 0; i < n; i++)
ewan@12117 1314 {
ewan@12117 1315 if (0 == strcmp(str, lookup_table[i]))
ewan@12117 1316 {
ewan@12117 1317 return i;
ewan@12117 1318 }
ewan@12117 1319 }
ewan@12117 1320 }
ewan@12117 1321
ewan@12117 1322 server_error_2(session, "Bad enum string", str);
ewan@12117 1323 return 0;
ewan@12117 1324 }
ewan@12117 1325
ewan@12117 1326
ewan@12117 1327 char *
ewan@12117 1328 xen_strdup_(const char *in)
ewan@12117 1329 {
ewan@12117 1330 char *result = malloc(strlen(in) + 1);
ewan@12117 1331 strcpy(result, in);
ewan@12117 1332 return result;
ewan@12117 1333 }
ewan@12117 1334
ewan@12117 1335
ewan@12117 1336 const abstract_type abstract_type_string = { .typename = STRING };
ewan@12117 1337 const abstract_type abstract_type_int = { .typename = INT };
ewan@12117 1338 const abstract_type abstract_type_float = { .typename = FLOAT };
ewan@12117 1339 const abstract_type abstract_type_bool = { .typename = BOOL };
ewan@12117 1340 const abstract_type abstract_type_datetime = { .typename = DATETIME };
ewan@12117 1341 const abstract_type abstract_type_ref = { .typename = REF };
ewan@12117 1342
ewan@12117 1343 const abstract_type abstract_type_string_set =
ewan@12117 1344 {
ewan@12117 1345 .typename = SET,
ewan@12117 1346 .child = &abstract_type_string
ewan@12117 1347 };
ewan@12117 1348
ewan@12117 1349 const abstract_type abstract_type_ref_set =
ewan@12117 1350 {
ewan@12117 1351 .typename = SET,
ewan@12117 1352 .child = &abstract_type_ref
ewan@12117 1353 };
ewan@12117 1354
ewan@12117 1355 static const struct struct_member string_string_members[] =
ewan@12117 1356 {
ewan@12117 1357 {
ewan@12117 1358 .type = &abstract_type_string,
ewan@12117 1359 .offset = offsetof(xen_string_string_map_contents, key)
ewan@12117 1360 },
ewan@12117 1361 {
ewan@12117 1362 .type = &abstract_type_string,
ewan@12117 1363 .offset = offsetof(xen_string_string_map_contents, val)
ewan@12117 1364 }
ewan@12117 1365 };
ewan@12117 1366 const abstract_type abstract_type_string_string_map =
ewan@12117 1367 {
ewan@12117 1368 .typename = MAP,
ewan@12117 1369 .struct_size = sizeof(xen_string_string_map_contents),
ewan@12117 1370 .members = string_string_members
ewan@12117 1371 };
ewan@12117 1372
ewan@12117 1373 static struct struct_member int_float_members[] =
ewan@12117 1374 {
ewan@12117 1375 {
ewan@12117 1376 .type = &abstract_type_int,
ewan@12117 1377 .offset = offsetof(xen_int_float_map_contents, key)
ewan@12117 1378 },
ewan@12117 1379 {
ewan@12117 1380 .type = &abstract_type_float,
ewan@12117 1381 .offset = offsetof(xen_int_float_map_contents, val)
ewan@12117 1382 }
ewan@12117 1383 };
ewan@12117 1384 const abstract_type abstract_type_int_float_map =
ewan@12117 1385 {
ewan@12117 1386 .typename = MAP,
ewan@12117 1387 .struct_size = sizeof(xen_int_float_map_contents),
ewan@12117 1388 .members = int_float_members
ewan@12117 1389 };