source: trunk/packages/xen-3.1/xen-3.1/tools/libxen/src/xen_common.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 44.5 KB
Line 
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 */
18
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>
27
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>
33
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"
41
42
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
49
50
51static xmlXPathCompExprPtr responsePath = NULL;
52static xmlXPathCompExprPtr faultPath = NULL;
53
54
55typedef struct
56{
57    size_t size;
58    void *contents[];
59} arbitrary_map;
60
61
62typedef struct
63{
64    void *handle;
65} arbitrary_record;
66
67
68typedef struct
69{
70    bool is_record;
71    union
72    {
73        char *handle;
74        arbitrary_record *record;
75    } u;
76} arbitrary_record_opt;
77
78
79static char *
80make_body(const char *, abstract_value [], int);
81
82static void
83parse_result(xen_session *, const char *, const abstract_type *, void *);
84
85static void
86add_value(xmlNode *, const char *, const char *);
87static void
88add_param(xmlNode *, const char *, const char *);
89
90static xmlNode *
91add_param_struct(xmlNode *);
92static xmlNode *
93add_struct_array(xmlNode *, const char *);
94static xmlNode *
95add_nested_struct(xmlNode *, const char *);
96static void
97add_struct_member(xmlNode *, const char *, const char *, const char *);
98static void
99add_unnamed_value(xmlNode *, const char *, const char *, const char *);
100
101static void
102add_struct_value(const struct abstract_type *, void *,
103                 void (*)(xmlNode *, const char *, const char *,
104                          const char *),
105                 const char *, xmlNode *);
106
107static xmlNode *
108add_container(xmlNode *parent, const char *name);
109
110static void
111call_raw(xen_session *, const char *, abstract_value [], int,
112         const abstract_type *, void *);
113
114static void
115parse_structmap_value(xen_session *, xmlNode *, const abstract_type *,
116                      void *);
117
118static size_t size_of_member(const abstract_type *);
119
120static const char *
121get_val_as_string(const struct abstract_type *, void *, char *, size_t);
122
123
124void
125xen_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}
135
136
137void
138xen_fini(void)
139{
140    xmlXPathFreeCompExpr(responsePath);
141    xmlXPathFreeCompExpr(faultPath);
142    responsePath = NULL;
143    faultPath = NULL;
144}
145
146
147void
148xen_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}
159
160
161xen_session *
162xen_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        };
172
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;
180
181    call_raw(session, "session.login_with_password", params, 2,
182             &abstract_type_string, &session->session_id);
183
184    return session;
185}
186
187
188void
189xen_session_logout(xen_session *session)
190{
191    abstract_value params[] =
192        {
193        };
194    xen_call_(session, "session.logout", params, 0, NULL, NULL);
195
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    }
204
205    free((char *)session->session_id);
206    free(session);
207}
208
209
210void
211xen_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}
225
226
227bool
228xen_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        };
236
237    xen_call_(session, "session.get_uuid", params, 1,
238              &abstract_type_string, result);
239    return session->ok;
240}
241
242
243bool
244xen_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        };
252
253    xen_call_(session, "session.get_this_host", params, 1,
254              &abstract_type_string, result);
255    return session->ok;
256}
257
258
259bool
260xen_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        };
268
269    xen_call_(session, "session.get_this_user", params, 1,
270              &abstract_type_string, result);
271    return session->ok;
272}
273
274
275bool
276xen_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        };
284
285    xen_call_(session, "session.get_last_active", params, 1,
286              &abstract_type_datetime, result);
287    return session->ok;
288}
289
290
291static 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    };
306
307const 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    };
315
316
317bool
318xen_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        };
326
327    abstract_type result_type = xen_session_record_abstract_type_;
328
329    *result = NULL;
330    XEN_CALL_("session.get_record");
331
332    return session->ok;
333}
334
335
336#define X "%02x"
337#define UUID_FORMAT X X X X "-" X X "-" X X "-" X X "-" X X X X X X
338
339
340bool
341xen_uuid_string_to_bytes(char *uuid, char **bytes)
342{
343    unsigned int buf[16];
344
345    *bytes = NULL;
346   
347    if (strlen(uuid) != 36)
348        return false;
349
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    }
360
361    *bytes = malloc(16);
362    if (*bytes == NULL)
363        return false;
364
365    for (int i = 0; i < 16; i++) {
366        (*bytes)[i] = (char)buf[i];
367    }
368
369    return true;
370}
371
372
373bool
374xen_uuid_bytes_to_string(char *bytes, char **uuid)
375{
376    *uuid = malloc(37);
377    if (*uuid == NULL)
378        return false;
379
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]);
386
387    return true;
388}
389
390
391#undef UUID_FORMAT
392#undef X
393
394
395void
396xen_uuid_free(char *uuid)
397{
398    free(uuid);
399}
400
401
402void
403xen_uuid_bytes_free(char *bytes)
404{
405    free(bytes);
406}
407
408
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 */
414void
415xen_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    if (!s->ok)
420    {
421        return;
422    }
423
424    abstract_value *full_params =
425        malloc(sizeof(abstract_value) * (param_count + 1));
426
427    full_params[0].type = &abstract_type_string;
428    full_params[0].u.string_val = s->session_id;
429
430    memcpy(full_params + 1, params, param_count * sizeof(abstract_value));
431
432    call_raw(s, method_name, full_params, param_count + 1, result_type,
433             value);
434
435    free(full_params);
436}
437
438
439static bool
440bufferAdd(const void *data, size_t len, void *buffer)
441{
442    return 0 == xmlBufferAdd((xmlBufferPtr)buffer, data, len);
443}
444
445
446static void
447call_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 *));
459
460        strings[0] = xen_strdup_("TRANSPORT_FAULT");
461        strings[1] = malloc(20);
462        snprintf(strings[1], 20, "%d", error_code);
463
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}
474
475
476static void server_error(xen_session *session, const char *error_string)
477{
478    if (!session->ok)
479    {
480        /* Don't wipe out the earlier error message with this one. */
481        return;
482    }
483
484    char **strings = malloc(2 * sizeof(char *));
485
486    strings[0] = xen_strdup_("SERVER_FAULT");
487    strings[1] = xen_strdup_(error_string);
488
489    session->ok = false;
490    session->error_description = strings;
491    session->error_description_count = 2;
492}
493
494
495static void server_error_2(xen_session *session, const char *error_string,
496                           const char *param)
497{
498    if (!session->ok)
499    {
500        /* Don't wipe out the earlier error message with this one. */
501        return;
502    }
503
504    char **strings = malloc(3 * sizeof(char *));
505
506    strings[0] = xen_strdup_("SERVER_FAULT_2");
507    strings[1] = xen_strdup_(error_string);
508    strings[2] = xen_strdup_(param);
509
510    session->ok = false;
511    session->error_description = strings;
512    session->error_description_count = 3;
513}
514
515
516static bool is_node(xmlNode *n, char *type)
517{
518    return
519        n->type == XML_ELEMENT_NODE &&
520        0 == strcmp((char *)n->name, type);
521}
522
523
524static bool is_container_node(xmlNode *n, char *type)
525{
526    return
527        is_node(n, type) &&
528        n->children != NULL &&
529        n->children == n->last &&
530        n->children->type == XML_ELEMENT_NODE;
531}
532
533
534/**
535 * @return The contents of the given value, or NULL if this is not a node with
536 * the given type.  If not NULL, the result must be freed with xmlFree().
537 */
538static xmlChar *string_from_value(xmlNode *n, char *type)
539{
540    /*
541      <value><type>XYZ</type></value> is normal, but the XML-RPC spec also
542      allows <value>XYZ</value> where XYZ is to be interpreted as a string.
543    */
544
545    if (is_container_node(n, "value") &&
546        0 == strcmp((char *)n->children->name, type))
547    {
548        return
549            n->children->children == NULL ?
550                xmlStrdup(BAD_CAST("")) :
551                xmlNodeGetContent(n->children->children);
552    }
553    else if (0 == strcmp(type, "string") && is_node(n, "value"))
554    {
555        return
556            n->children == NULL ?
557                xmlStrdup(BAD_CAST("")) :
558                xmlNodeGetContent(n->children);
559    }
560    else
561    {
562        return NULL;
563    }
564}
565
566
567/**
568 * Find the name node that is a child of the given one, and return its
569 * contents, or NULL if this has no such node.  If not NULL, the result must
570 * be freed with xmlFree().
571 */
572static xmlChar *string_from_name(xmlNode *n)
573{
574    xmlNode *cur = n->children;
575
576    while (cur != NULL)
577    {
578        if (0 == strcmp((char *)cur->name, "name"))
579        {
580            return xmlNodeGetContent(cur);
581        }
582        cur = cur->next;
583    }
584
585    return NULL;
586}
587
588
589static int count_children(xmlNode *n, const char *name)
590{
591    int result = 0;
592    xmlNode *cur = n->children;
593
594    while (cur != NULL)
595    {
596        if (0 == strcmp((char *)cur->name, name))
597        {
598            result++;
599        }
600        cur = cur->next;
601    }
602
603    return result;
604}
605
606
607static void destring(xen_session *s, xmlChar *name, const abstract_type *type,
608                     void *value)
609{
610    switch (type->typename)
611    {
612    case STRING:
613        *((char **)value) = xen_strdup_((const char *)name);
614        break;
615
616    case INT:
617        *((int64_t *)value) = atoll((const char *)name);
618        break;
619
620    case FLOAT:
621        *((double *)value) = atof((const char *)name);
622        break;
623
624    default:
625        server_error(s, "Invalid Map key type");
626    }
627}
628
629
630/**
631 * result_type : STRING   => value : char **, the char * is yours.
632 * result_type : ENUM     => value : int *
633 * result_type : INT      => value : int64_t *
634 * result_type : FLOAT    => value : double *
635 * result_type : BOOL     => value : bool *
636 * result_type : DATETIME => value : time_t *
637 * result_type : SET      => value : arbitrary_set **, the set is yours.
638 * result_type : MAP      => value : arbitrary_map **, the map is yours.
639 * result_type : OPT      => value : arbitrary_record_opt **,
640 *                                   the record is yours, the handle is
641 *                                   filled.
642 * result_type : STRUCT   => value : void **, the void * is yours.
643 */
644static void parse_into(xen_session *s, xmlNode *value_node,
645                       const abstract_type *result_type, void *value,
646                       int slot)
647{
648    if (result_type == NULL)
649    {
650        xmlChar *string = string_from_value(value_node, "string");
651        if (string == NULL || strcmp((char *)string, ""))
652        {
653            server_error(s,
654                         "Expected Void from the server, but didn't get it");
655        }
656        else
657        {
658            free(string);
659        }
660
661        return;
662    }
663
664    switch (result_type->typename)
665    {
666    case STRING:
667    {
668        xmlChar *string = string_from_value(value_node, "string");
669        if (string == NULL)
670        {
671            server_error(
672                s, "Expected a String from the server, but didn't get one");
673        }
674        else
675        {
676            ((char **)value)[slot] = xen_strdup_((const char *)string);
677            free(string);
678        }
679    }
680    break;
681
682    case ENUM:
683    {
684        xmlChar *string = string_from_value(value_node, "string");
685        if (string == NULL)
686        {
687#if PERMISSIVE
688            fprintf(stderr,
689                    "Expected an Enum from the server, but didn't get one\n");
690            ((int *)value)[slot] = 0;
691#else
692            server_error(
693                s, "Expected an Enum from the server, but didn't get one");
694#endif
695        }
696        else
697        {
698            ((int *)value)[slot] =
699                result_type->enum_demarshaller(s, (const char *)string);
700            free(string);
701        }
702    }
703    break;
704
705    case INT:
706    {
707        xmlChar *string = string_from_value(value_node, "string");
708        if (string == NULL)
709        {
710            server_error(
711                s, "Expected an Int from the server, but didn't get one");
712        }
713        else
714        {
715            ((int64_t *)value)[slot] = (int64_t)atoll((char *)string);
716            free(string);
717        }
718    }
719    break;
720
721    case FLOAT:
722    {
723        xmlChar *string = string_from_value(value_node, "double");
724        if (string == NULL)
725        {
726#if PERMISSIVE
727            fprintf(stderr,
728                    "Expected a Float from the server, but didn't get one\n");
729            ((double *)value)[slot] = 0.0;
730#else
731            server_error(
732                s, "Expected a Float from the server, but didn't get one");
733#endif
734        }
735        else
736        {
737            ((double *)value)[slot] = atof((char *)string);
738            free(string);
739        }
740    }
741    break;
742
743    case BOOL:
744    {
745        xmlChar *string = string_from_value(value_node, "boolean");
746        if (string == NULL)
747        {
748#if PERMISSIVE
749            fprintf(stderr,
750                    "Expected a Bool from the server, but didn't get one\n");
751            ((bool *)value)[slot] = false;
752#else
753            server_error(
754                s, "Expected a Bool from the server, but didn't get one");
755#endif
756        }
757        else
758        {
759            ((bool *)value)[slot] = (0 == strcmp((char *)string, "1"));
760            free(string);
761        }
762    }
763    break;
764
765    case DATETIME:
766    {
767        xmlChar *string = string_from_value(value_node, "dateTime.iso8601");
768        if (string == NULL)
769        {
770            server_error(
771                s, "Expected an DateTime from the server but didn't get one");
772        }
773        else
774        {
775            struct tm tm;
776            memset(&tm, 0, sizeof(tm));
777            strptime((char *)string, "%Y%m%dT%H:%M:%S", &tm);
778            ((time_t *)value)[slot] = (time_t)mktime(&tm);
779            free(string);
780        }
781    }
782    break;
783
784    case SET:
785    {
786        if (!is_container_node(value_node, "value") ||
787            !is_container_node(value_node->children, "array"))
788        {
789            server_error(s,
790                         "Expected Set from the server, but didn't get it");
791        }
792        else
793        {
794            xmlNode *data_node = value_node->children->children;
795            int n = count_children(data_node, "value");
796
797            const abstract_type *member_type = result_type->child;
798            size_t member_size = size_of_member(member_type);
799
800            arbitrary_set *set =
801                calloc(1, sizeof(arbitrary_set) + member_size * n);
802            set->size = n;
803            int i = 0;
804            xmlNode *cur = data_node->children;
805
806            while (cur != NULL)
807            {
808                if (0 == strcmp((char *)cur->name, "value"))
809                {
810                    parse_into(s, cur, member_type, set->contents, i);
811                    i++;
812                }
813                cur = cur->next;
814            }
815
816            ((arbitrary_set **)value)[slot] = set;
817        }
818    }
819    break;
820
821    case MAP:
822    {
823        if (!is_container_node(value_node, "value") ||
824            value_node->children->type != XML_ELEMENT_NODE ||
825            0 != strcmp((char *)value_node->children->name, "struct"))
826        {
827            server_error(s,
828                         "Expected Map from the server, but didn't get it");
829        }
830        else
831        {
832            xmlNode *struct_node = value_node->children;
833            int n = count_children(struct_node, "member");
834
835            size_t struct_size = result_type->struct_size;
836
837            const struct struct_member *key_member = result_type->members;
838            const struct struct_member *val_member = result_type->members + 1;
839
840            arbitrary_map *map =
841                calloc(1, sizeof(arbitrary_map) + struct_size * n);
842            map->size = n;
843            int i = 0;
844            xmlNode *cur = struct_node->children;
845
846            while (cur != NULL)
847            {
848                if (0 == strcmp((char *)cur->name, "member"))
849                {
850                    if (cur->children == NULL || cur->last == cur->children)
851                    {
852                        server_error(s, "Malformed Map");
853                        free(map);
854                        return;
855                    }
856
857                    xmlChar *name = string_from_name(cur);
858                    if (name == NULL)
859                    {
860                        server_error(s, "Malformed Map");
861                        free(map);
862                        return;
863                    }
864
865                    destring(s, name, key_member->type,
866                             ((void *)(map + 1)) +
867                             (i * struct_size) +
868                             key_member->offset);
869                    xmlFree(name);
870                    if (!s->ok)
871                    {
872                        free(map);
873                        return;
874                    }
875
876                    parse_structmap_value(s, cur, val_member->type,
877                                          ((void *)(map + 1)) +
878                                          (i * struct_size) +
879                                          val_member->offset);
880                    if (!s->ok)
881                    {
882                        free(map);
883                        return;
884                    }
885                    i++;
886                }
887                cur = cur->next;
888            }
889
890            ((arbitrary_map **)value)[slot] = map;
891        }
892    }
893    break;
894
895    case STRUCT:
896    {
897        if (!is_container_node(value_node, "value") ||
898            value_node->children->type != XML_ELEMENT_NODE ||
899            0 != strcmp((char *)value_node->children->name, "struct") ||
900            value_node->children->children == NULL)
901        {
902            server_error(s,
903                         "Expected Map from the server, but didn't get it");
904        }
905        else
906        {
907            xmlNode *struct_node = value_node->children;
908
909            void *result = calloc(1, result_type->struct_size);
910            xmlNode *cur = struct_node->children;
911
912            size_t member_count = result_type->member_count;
913
914            const struct_member **checklist =
915                malloc(sizeof(const struct_member *) * member_count);
916            int seen_count = 0;
917
918            while (cur != NULL)
919            {
920                if (0 == strcmp((char *)cur->name, "member"))
921                {
922                    if (cur->children == NULL || cur->last == cur->children)
923                    {
924                        server_error(s, "Malformed Struct");
925                        free(result);
926                        free(checklist);
927                        return;
928                    }
929
930                    xmlChar *name = string_from_name(cur);
931                    if (name == NULL)
932                    {
933                        server_error(s, "Malformed Struct");
934                        free(result);
935                        free(checklist);
936                        return;
937                    }
938
939                    for (size_t i = 0; i < member_count; i++)
940                    {
941                        const struct_member *mem = result_type->members + i;
942
943                        if (0 == strcmp((char *)name, mem->key))
944                        {
945                            parse_structmap_value(s, cur, mem->type,
946                                                  result + mem->offset);
947                            checklist[seen_count] = mem;
948                            seen_count++;
949                            break;
950                        }
951                    }
952
953                    /* Note that we're skipping unknown fields implicitly.
954                       This means that we'll be forward compatible with
955                       new servers. */
956
957                    xmlFree(name);
958
959                    if (!s->ok)
960                    {
961                        free(result);
962                        free(checklist);
963                        return;
964                    }
965                }
966                cur = cur->next;
967            }
968
969            /* Check that we've filled all fields. */
970            for (size_t i = 0; i < member_count; i++)
971            {
972                const struct_member *mem = result_type->members + i;
973                int j;
974
975                for (j = 0; j < seen_count; j++)
976                {
977                    if (checklist[j] == mem)
978                    {
979                        break;
980                    }
981                }
982
983                if (j == seen_count)
984                {
985#if PERMISSIVE
986                    fprintf(stderr,
987                            "Struct did not contain expected field %s.\n",
988                            mem->key);
989#else
990                    server_error_2(s,
991                                   "Struct did not contain expected field",
992                                   mem->key);
993                    free(result);
994                    free(checklist);
995                    return;
996#endif
997                }
998            }
999
1000            free(checklist);
1001            ((void **)value)[slot] = result;
1002        }
1003    }
1004    break;
1005
1006    case REF:
1007    {
1008        arbitrary_record_opt *record_opt =
1009            calloc(1, sizeof(arbitrary_record_opt));
1010
1011        record_opt->is_record = false;
1012        parse_into(s, value_node, &abstract_type_string,
1013                   &(record_opt->u.handle), 0);
1014
1015        ((arbitrary_record_opt **)value)[slot] = record_opt;
1016    }
1017    break;
1018
1019    default:
1020        assert(false);
1021    }
1022}
1023
1024
1025static size_t size_of_member(const abstract_type *type)
1026{
1027    switch (type->typename)
1028    {
1029    case STRING:
1030        return sizeof(char *);
1031
1032/*
1033    case INT:
1034        return sizeof(int64_t);
1035
1036    case FLOAT:
1037        return sizeof(double);
1038
1039    case BOOL:
1040        return sizeof(bool);
1041*/
1042    case ENUM:
1043        return sizeof(int);
1044
1045    case REF:
1046        return sizeof(arbitrary_record_opt *);
1047
1048    case STRUCT:
1049        return type->struct_size;
1050
1051    default:
1052        assert(false);
1053    }
1054}
1055
1056
1057static void parse_structmap_value(xen_session *s, xmlNode *n,
1058                                  const abstract_type *type, void *value)
1059{
1060    xmlNode *cur = n->children;
1061
1062    while (cur != NULL)
1063    {
1064        if (0 == strcmp((char *)cur->name, "value"))
1065        {
1066            parse_into(s, cur, type, value, 0);
1067            return;
1068        }
1069        cur = cur->next;
1070    }
1071
1072    server_error(s, "Missing value in Map/Struct");
1073}
1074
1075
1076static void parse_fault(xen_session *session, xmlXPathContextPtr xpathCtx)
1077{
1078    xmlXPathObjectPtr xpathObj = xmlXPathCompiledEval(faultPath, xpathCtx);
1079    if (xpathObj == NULL)
1080    {
1081        server_error(session, "Method response is neither result nor fault");
1082        return;
1083    }
1084
1085    if (xpathObj->type != XPATH_NODESET ||
1086        xpathObj->nodesetval->nodeNr != 2)
1087    {
1088        xmlXPathFreeObject(xpathObj);
1089        server_error(session, "Method response is neither result nor fault");
1090        return;
1091    }
1092
1093    xmlNode *fault_node0 = xpathObj->nodesetval->nodeTab[0];
1094    xmlNode *fault_node1 = xpathObj->nodesetval->nodeTab[1];
1095
1096    xmlChar *fault_code_str = string_from_value(fault_node0, "int");
1097    if (fault_code_str == NULL)
1098    {
1099        fault_code_str = string_from_value(fault_node0, "i4");
1100    }
1101    if (fault_code_str == NULL)
1102    {
1103        xmlXPathFreeObject(xpathObj);
1104        server_error(session, "Fault code is malformed");
1105        return;
1106    }
1107
1108    xmlChar *fault_string_str = string_from_value(fault_node1, "string");
1109    if (fault_string_str == NULL)
1110    {
1111        xmlFree(fault_code_str);
1112        xmlXPathFreeObject(xpathObj);
1113        server_error(session, "Fault string is malformed");
1114        return;
1115    }
1116
1117    char **strings = malloc(3 * sizeof(char *));
1118
1119    strings[0] = xen_strdup_("FAULT");
1120    strings[1] = xen_strdup_((char *)fault_code_str);
1121    strings[2] = xen_strdup_((char *)fault_string_str);
1122
1123    session->ok = false;
1124    session->error_description = strings;
1125    session->error_description_count = 3;
1126
1127    xmlFree(fault_code_str);
1128    xmlFree(fault_string_str);
1129    xmlXPathFreeObject(xpathObj);
1130}
1131
1132
1133static void parse_failure(xen_session *session, xmlNode *node)
1134{
1135    abstract_type error_description_type =
1136        { .typename = SET,
1137          .child = &abstract_type_string };
1138    arbitrary_set *error_descriptions;
1139
1140    parse_into(session, node, &error_description_type, &error_descriptions,
1141               0);
1142
1143    if (session->ok)
1144    {
1145        session->ok = false;
1146
1147        char **c = (char **)error_descriptions->contents;
1148        int n = error_descriptions->size;
1149
1150        char **strings = malloc(n * sizeof(char *));
1151        for (int i = 0; i < n; i++)
1152        {
1153            strings[i] = c[i];
1154        }
1155
1156        session->error_description_count = n;
1157        session->error_description = strings;
1158    }
1159
1160    free(error_descriptions);
1161}
1162
1163
1164/**
1165 * Parameters as for xen_call_() above.
1166 */
1167static void parse_result(xen_session *session, const char *result,
1168                         const abstract_type *result_type, void *value)
1169{
1170    xmlDocPtr doc =
1171        xmlReadMemory(result, strlen(result), "", NULL, XML_PARSE_NONET);
1172
1173    if (doc == NULL)
1174    {
1175        server_error(session, "Couldn't parse the server response");
1176        return;
1177    }
1178
1179    xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
1180    if (xpathCtx == NULL)
1181    {
1182        xmlFreeDoc(doc);
1183        server_error(session, "Couldn't create XPath context");
1184        return;
1185    }
1186
1187    xmlXPathObjectPtr xpathObj =
1188        xmlXPathCompiledEval(responsePath, xpathCtx);
1189    if (xpathObj == NULL)
1190    {
1191        parse_fault(session, xpathCtx);
1192
1193        xmlXPathFreeContext(xpathCtx); 
1194        xmlFreeDoc(doc);
1195        return;
1196    }
1197
1198    if  (xpathObj->type != XPATH_NODESET ||
1199         xpathObj->nodesetval->nodeNr != 2)
1200    {
1201        parse_fault(session, xpathCtx);
1202
1203        xmlXPathFreeObject(xpathObj);
1204        xmlXPathFreeContext(xpathCtx); 
1205        xmlFreeDoc(doc);
1206        return;
1207    }
1208
1209    xmlNode *node0 = xpathObj->nodesetval->nodeTab[0];
1210    xmlNode *node1 = xpathObj->nodesetval->nodeTab[1];
1211
1212    xmlChar *status_code = string_from_value(node0, "string");
1213    if (status_code == NULL)
1214    {
1215        xmlXPathFreeObject(xpathObj);
1216        xmlXPathFreeContext(xpathCtx); 
1217        xmlFreeDoc(doc);
1218        server_error(session, "Server response does not have a Status");
1219        return;
1220    }
1221
1222    if (strcmp((char *)status_code, "Success"))
1223    {
1224        parse_failure(session, node1);
1225
1226        xmlFree(status_code);
1227        xmlXPathFreeObject(xpathObj);
1228        xmlXPathFreeContext(xpathCtx); 
1229        xmlFreeDoc(doc); 
1230        return;
1231    }
1232
1233    parse_into(session, node1, result_type, value, 0);
1234
1235    xmlFree(status_code);
1236    xmlXPathFreeObject(xpathObj);
1237    xmlXPathFreeContext(xpathCtx);
1238    xmlFreeDoc(doc);
1239}
1240
1241
1242static void
1243make_body_add_type(enum abstract_typename typename, abstract_value *v,
1244                   xmlNode *params_node)
1245{
1246    char buf[20];
1247    switch (typename)
1248    {
1249    case STRING:
1250        add_param(params_node, "string", v->u.string_val);
1251        break;
1252
1253    case INT:
1254        snprintf(buf, sizeof(buf), "%"PRId64, v->u.int_val);
1255        add_param(params_node, "string", buf);
1256        break;
1257
1258    case FLOAT:
1259        snprintf(buf, sizeof(buf), "%lf", v->u.float_val);
1260        add_param(params_node, "double", buf);
1261        break;
1262
1263    case BOOL:
1264        add_param(params_node, "boolean", v->u.bool_val ? "1" : "0");
1265        break;
1266       
1267    case VOID:
1268        add_param(params_node, "string", "");
1269        break;
1270
1271    case ENUM:
1272        add_param(params_node, "string",
1273                  v->type->enum_marshaller(v->u.enum_val));
1274        break;
1275
1276    case SET:
1277    {
1278        const struct abstract_type *member_type = v->type->child;
1279        arbitrary_set *set_val = v->u.struct_val;
1280        abstract_value v;
1281        xmlNode *data_node = add_param_struct(params_node);
1282
1283        for (size_t i = 0; i < set_val->size; i++)
1284        {
1285            switch (member_type->typename) {
1286                case STRING:
1287                    v.u.string_val = (char *)set_val->contents[i];
1288                    make_body_add_type(member_type->typename, &v, data_node);
1289                    break;
1290                default:
1291                    assert(false);
1292            }
1293        }
1294    }
1295    break;
1296
1297    case STRUCT:
1298    {
1299        size_t member_count = v->type->member_count;
1300
1301        xmlNode *struct_node = add_param_struct(params_node);
1302
1303        for (size_t i = 0; i < member_count; i++)
1304        {
1305            const struct struct_member *mem = v->type->members + i;
1306            const char *key = mem->key;
1307            void *struct_value = v->u.struct_val;
1308
1309            add_struct_value(mem->type, struct_value + mem->offset,
1310                             add_struct_member, key, struct_node);
1311        }
1312    }
1313    break;
1314
1315    case MAP:
1316    {
1317        const struct struct_member *member = v->type->members;
1318        arbitrary_map *map_val = v->u.struct_val;
1319        xmlNode *param_node = add_param_struct(params_node);
1320        for (size_t i = 0; i < map_val->size; i++) {
1321            enum abstract_typename typename_key = member[0].type->typename;
1322            enum abstract_typename typename_val = member[1].type->typename;
1323            int offset_key = member[0].offset;
1324            int offset_val = member[1].offset;
1325            int struct_size = v->type->struct_size;
1326
1327            switch (typename_key) {
1328            case STRING: {
1329                char **addr = (void *)(map_val + 1) +
1330                             (i * struct_size) +
1331                             offset_key;
1332                char *key = *addr;
1333
1334                switch (typename_val) {
1335                case STRING: {
1336                    char *val;
1337                    addr = (void *)(map_val + 1) +
1338                           (i * struct_size) +
1339                           offset_val;
1340                    val = *addr;
1341                    add_struct_member(param_node, key, "string", val);
1342                    break;
1343                }
1344                default:
1345                    assert(false);
1346                }
1347                break;
1348            }
1349            default:
1350                assert(false);
1351            }
1352        }
1353    }
1354    break;
1355
1356
1357    default:
1358        assert(false);
1359    }
1360}
1361
1362
1363static char *
1364make_body(const char *method_name, abstract_value params[], int param_count)
1365{
1366    xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
1367    xmlNode *methodCall = xmlNewNode(NULL, BAD_CAST "methodCall");
1368    xmlDocSetRootElement(doc, methodCall);
1369
1370    xmlNewChild(methodCall, NULL, BAD_CAST "methodName",
1371                BAD_CAST method_name);
1372
1373    xmlNode *params_node =
1374        xmlNewChild(methodCall, NULL, BAD_CAST "params", NULL);
1375
1376    for (int p = 0; p < param_count; p++)
1377    {
1378        abstract_value *v = params + p;
1379        make_body_add_type(v->type->typename, v, params_node);
1380    }
1381
1382    xmlBufferPtr buffer = xmlBufferCreate();
1383    xmlSaveCtxtPtr save_ctxt =
1384        xmlSaveToBuffer(buffer, NULL, XML_SAVE_NO_XHTML);
1385
1386    if (xmlSaveDoc(save_ctxt, doc) == -1)
1387    {
1388        return NULL;
1389    }
1390
1391    xmlFreeDoc(doc);
1392    xmlSaveClose(save_ctxt);
1393    xmlChar *content = xmlStrdup(xmlBufferContent(buffer));
1394    xmlBufferFree(buffer);
1395    return (char *)content;
1396}
1397
1398
1399static void
1400add_struct_value(const struct abstract_type *type, void *value,
1401                 void (*adder)(xmlNode *node, const char *key,
1402                               const char *type, const char *val),
1403                 const char *key, xmlNode *node)
1404{
1405    char buf[20];
1406
1407    switch (type->typename)
1408    {
1409    case REF:
1410    case STRING:
1411    case INT:
1412    case ENUM:
1413    {
1414        const char *val_as_string =
1415            get_val_as_string(type, value, buf, sizeof(buf));
1416        adder(node, key, "string", val_as_string);
1417    }
1418    break;
1419
1420    case FLOAT:
1421    {
1422        double val = *(double *)value;
1423        snprintf(buf, sizeof(buf), "%lf", val);
1424        adder(node, key, "double", buf);
1425    }
1426    break;
1427
1428    case BOOL:
1429    {
1430        bool val = *(bool *)value;
1431        adder(node, key, "boolean", val ? "1" : "0");
1432    }
1433    break;
1434
1435    case SET:
1436    {
1437        const struct abstract_type *member_type = type->child;
1438        size_t member_size = size_of_member(member_type);
1439        arbitrary_set *set_val = *(arbitrary_set **)value;
1440
1441        if (set_val != NULL)
1442        {
1443            xmlNode *data_node = add_struct_array(node, key);
1444
1445            for (size_t i = 0; i < set_val->size; i++)
1446            {
1447                void *member_value = (char *)set_val->contents +
1448                                     (i * member_size);
1449                add_struct_value(member_type, member_value,
1450                                 add_unnamed_value, NULL, data_node);
1451            }
1452        }
1453    }
1454    break;
1455
1456    case STRUCT:
1457    {
1458        assert(false);
1459        /* XXX Nested structures aren't supported yet, but
1460           fortunately we don't need them, because we don't have
1461           any "deep create" calls.  This will need to be
1462           fixed. */
1463    }
1464    break;
1465
1466    case MAP:
1467    {
1468        size_t member_size = type->struct_size;
1469        const struct abstract_type *l_type = type->members[0].type;
1470        const struct abstract_type *r_type = type->members[1].type;
1471        int l_offset = type->members[0].offset;
1472        int r_offset = type->members[1].offset;
1473
1474        arbitrary_map *map_val = *(arbitrary_map **)value;
1475
1476        if (map_val != NULL)
1477        {
1478            xmlNode *struct_node = add_nested_struct(node, key);
1479
1480            for (size_t i = 0; i < map_val->size; i++)
1481            {
1482                void *contents = (void *)map_val->contents;
1483                void *l_value = contents + (i * member_size) + l_offset;
1484                void *r_value = contents + (i * member_size) + r_offset;
1485
1486                const char *l_value_as_string =
1487                    get_val_as_string(l_type, l_value, buf, sizeof(buf));
1488
1489                add_struct_value(r_type, r_value, add_struct_member,
1490                                 l_value_as_string, struct_node);
1491            }
1492        }
1493    }
1494    break;
1495
1496    default:
1497        assert(false);
1498    }
1499}
1500
1501
1502static const char *
1503get_val_as_string(const struct abstract_type *type, void *value, char *buf,
1504                  size_t bufsize)
1505{
1506    switch (type->typename)
1507    {
1508    case REF:
1509    {
1510        arbitrary_record_opt *val = *(arbitrary_record_opt **)value;
1511        if (val != NULL)
1512        {
1513            if (val->is_record)
1514            {
1515                return val->u.record->handle;
1516            }
1517            else
1518            {
1519                return val->u.handle;
1520            }
1521        }
1522        else
1523        {
1524            return NULL;
1525        }
1526    }
1527    break;
1528
1529    case STRING:
1530    {
1531        return *(char **)value;
1532    }
1533    break;
1534
1535    case INT:
1536    {
1537        int64_t val = *(int64_t *)value;
1538        snprintf(buf, bufsize, "%"PRId64, val);
1539        return buf;
1540    }
1541    break;
1542
1543    case ENUM:
1544    {
1545        int val = *(int *)value;
1546        return type->enum_marshaller(val);
1547    }
1548    break;
1549
1550    default:
1551        assert(false);
1552    }
1553}
1554
1555
1556static xmlNode *
1557add_container(xmlNode *parent, const char *name)
1558{
1559    return xmlNewChild(parent, NULL, BAD_CAST name, NULL);
1560}
1561
1562
1563static void
1564add_param(xmlNode *params_node, const char *type, const char *value)
1565{
1566    xmlNode *param_node = add_container(params_node, "param");
1567    add_value(param_node, type, value);
1568}
1569
1570
1571static void
1572add_value(xmlNode *parent, const char *type, const char *value)
1573{
1574    xmlNode *value_node = add_container(parent, "value");
1575    xmlNewChild(value_node, NULL, BAD_CAST type, BAD_CAST value);
1576}
1577
1578
1579static void
1580add_unnamed_value(xmlNode *parent, const char *name, const char *type,
1581                  const char *value)
1582{
1583    (void)name;
1584    add_value(parent, type, value);
1585}
1586
1587
1588static xmlNode *
1589add_param_struct(xmlNode *params_node)
1590{
1591    xmlNode *param_node = add_container(params_node, "param");
1592    xmlNode *value_node = add_container(param_node,  "value");
1593
1594    return xmlNewChild(value_node, NULL, BAD_CAST "struct", NULL);
1595}
1596
1597
1598static void
1599add_struct_member(xmlNode *struct_node, const char *name, const char *type,
1600                  const char *value)
1601{
1602    xmlNode *member_node = add_container(struct_node, "member");
1603
1604    xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1605
1606    add_value(member_node, type, value);
1607}
1608
1609
1610static xmlNode *
1611add_struct_array(xmlNode *struct_node, const char *name)
1612{
1613    xmlNode *member_node = add_container(struct_node, "member");
1614
1615    xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1616
1617    xmlNode *value_node = add_container(member_node, "value");
1618    xmlNode *array_node = add_container(value_node,  "array");
1619
1620    return add_container(array_node,  "data");
1621}
1622
1623
1624static xmlNode *
1625add_nested_struct(xmlNode *struct_node, const char *name)
1626{
1627    xmlNode *member_node = add_container(struct_node, "member");
1628
1629    xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
1630
1631    xmlNode *value_node = add_container(member_node, "value");
1632
1633    return add_container(value_node, "struct");
1634}
1635
1636
1637int xen_enum_lookup_(xen_session *session, const char *str,
1638                     const char **lookup_table, int n)
1639{
1640    if (str != NULL)
1641    {
1642        for (int i = 0; i < n; i++)
1643        {
1644            if (0 == strcmp(str, lookup_table[i]))
1645            {
1646                return i;
1647            }
1648        }
1649    }
1650
1651    server_error_2(session, "Bad enum string", str);
1652    return 0;
1653}
1654
1655
1656char *
1657xen_strdup_(const char *in)
1658{
1659    char *result = malloc(strlen(in) + 1);
1660    strcpy(result, in);
1661    return result;
1662}
1663
1664
1665const abstract_type abstract_type_string = { .typename = STRING };
1666const abstract_type abstract_type_int = { .typename = INT };
1667const abstract_type abstract_type_float = { .typename = FLOAT };
1668const abstract_type abstract_type_bool = { .typename = BOOL };
1669const abstract_type abstract_type_datetime = { .typename = DATETIME };
1670const abstract_type abstract_type_ref = { .typename = REF };
1671
1672const abstract_type abstract_type_string_set =
1673    {
1674        .typename = SET,
1675        .child = &abstract_type_string
1676    };
1677
1678const abstract_type abstract_type_ref_set =
1679    {
1680        .typename = SET,
1681        .child = &abstract_type_ref
1682    };
1683
1684static const struct struct_member string_string_members[] =
1685{
1686    {
1687        .type = &abstract_type_string,
1688        .offset = offsetof(xen_string_string_map_contents, key)
1689    },
1690    {
1691        .type = &abstract_type_string,
1692        .offset = offsetof(xen_string_string_map_contents, val)
1693    }
1694};
1695const abstract_type abstract_type_string_string_map =
1696    {
1697        .typename = MAP,
1698        .struct_size = sizeof(xen_string_string_map_contents),
1699        .members = string_string_members
1700    };
1701
1702static struct struct_member int_float_members[] =
1703{
1704    {
1705        .type = &abstract_type_int,
1706        .offset = offsetof(xen_int_float_map_contents, key)
1707    },
1708    {
1709        .type = &abstract_type_float,
1710        .offset = offsetof(xen_int_float_map_contents, val)
1711    }
1712};
1713const abstract_type abstract_type_int_float_map =
1714    {
1715        .typename = MAP,
1716        .struct_size = sizeof(xen_int_float_map_contents),
1717        .members = int_float_members
1718    };
1719
1720static struct struct_member int_int_members[] =
1721{
1722    {
1723        .type = &abstract_type_int,
1724        .offset = offsetof(xen_int_int_map_contents, key)
1725    },
1726    {
1727        .type = &abstract_type_int,
1728        .offset = offsetof(xen_int_int_map_contents, val)
1729    }
1730};
1731const abstract_type abstract_type_int_int_map =
1732    {
1733        .typename = MAP,
1734        .struct_size = sizeof(xen_int_int_map_contents),
1735        .members = int_int_members
1736    };
1737
1738static struct struct_member int_string_set_members[] =
1739{
1740    {
1741        .type = &abstract_type_int,
1742        .offset = offsetof(xen_int_string_set_map_contents, key)
1743    },
1744    {
1745        .type = &abstract_type_string_set,
1746        .offset = offsetof(xen_int_string_set_map_contents, val)
1747    }
1748};
1749const abstract_type abstract_type_int_string_set_map =
1750    {
1751        .typename = MAP,
1752        .struct_size = sizeof(xen_int_string_set_map_contents),
1753        .members = int_string_set_members
1754    };
Note: See TracBrowser for help on using the repository browser.