xmlrpc.c 18.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/*
 * xmlrpc.c: XML-RPC protocol handler for libvir library
 *
 * Copyright (C) 2006  IBM, Corp.
 *
 * See COPYING.LIB for the License of this software
 *
 * Anthony Liguori <aliguori@us.ibm.com>
 */

11
#include <config.h>
J
Jim Meyering 已提交
12

13
#include "xmlrpc.h"
K
Karel Zak 已提交
14
#include "internal.h"
15
#include "memory.h"
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36

#include <libxml/nanohttp.h>

#include <string.h>
#include <errno.h>

/* TODO
   1) Lots of error checking
   2) xmlRpcValueToSexpr
*/

static xmlNodePtr xmlFirstElement(xmlNodePtr node);
static xmlNodePtr xmlNextElement(xmlNodePtr node);

struct _xmlRpcContext
{
    char *uri;
    int faultCode;
    char *faultMessage;
};

K
Karel Zak 已提交
37 38 39 40 41 42 43 44
static void xmlRpcError(virErrorNumber error, const char *info, int value)
{
    const char *errmsg;

    if (error == VIR_ERR_OK)
        return;

    errmsg = __virErrorMsg(error, info);
45
    __virRaiseError(NULL, NULL, NULL, VIR_FROM_RPC, error, VIR_ERR_ERROR,
K
Karel Zak 已提交
46 47 48
                    errmsg, info, NULL, value, 0, errmsg, info, value);
}

49 50
static xmlRpcValuePtr xmlRpcValueNew(xmlRpcValueType type)
{
51 52
    xmlRpcValuePtr ret = NULL;
    if (VIR_ALLOC(ret) < 0)
53
        xmlRpcError(VIR_ERR_NO_MEMORY, _("allocate value"), sizeof(*ret));
K
Karel Zak 已提交
54
    else
55
        ret->kind = type;
56 57 58 59 60 61
    return ret;
}

static char *xmlGetText(xmlNodePtr node)
{
    for (node = node->children; node; node = node->next)
62 63 64
        if (node->type == XML_TEXT_NODE) {
            char *x = strdup((const char *)node->content);
            if (!x)
65 66
                xmlRpcError(VIR_ERR_NO_MEMORY, _("copying node content"),
                            strlen((const char *)node->content));
67 68
            return x;
        }
69 70 71 72 73 74
    return NULL;
}

static xmlNodePtr xmlFirstElement(xmlNodePtr node)
{
    for (node = node->children; node; node = node->next)
75 76
        if (node->type == XML_ELEMENT_NODE)
            break;
77 78 79 80 81 82
    return node;
}

static xmlNodePtr xmlNextElement(xmlNodePtr node)
{
    for (node = node->next; node; node = node->next)
83 84
        if (node->type == XML_ELEMENT_NODE)
            break;
85 86 87
    return node;
}

K
Karel Zak 已提交
88
static xmlRpcValuePtr xmlRpcValueUnmarshalDateTime(xmlNodePtr node ATTRIBUTE_UNUSED)
89 90
{
    /* we don't need this */
K
Karel Zak 已提交
91
    TODO
92 93 94 95 96 97
    return NULL;
}

static xmlRpcValuePtr xmlRpcValueUnmarshalString(xmlNodePtr node)
{
    xmlRpcValuePtr ret = xmlRpcValueNew(XML_RPC_STRING);
98

K
Karel Zak 已提交
99 100
    if (ret)
        ret->value.string = xmlGetText(node);
101 102 103
    return ret;
}

K
Karel Zak 已提交
104
static xmlRpcValuePtr xmlRpcValueUnmarshalBase64(xmlNodePtr node ATTRIBUTE_UNUSED)
105 106
{
    /* we don't need this */
K
Karel Zak 已提交
107
    TODO
108 109 110 111 112 113 114
    return NULL;
}

static xmlRpcValuePtr xmlRpcValueUnmarshalInteger(xmlNodePtr node)
{
    xmlRpcValuePtr ret = xmlRpcValueNew(XML_RPC_INTEGER);
    char *value = xmlGetText(node);
115

K
Karel Zak 已提交
116 117
    if (ret && value)
        ret->value.integer = atoi(value);
118
    VIR_FREE(value);
119 120 121 122 123 124 125 126
    return ret;
}

static xmlRpcValuePtr xmlRpcValueUnmarshalBoolean(xmlNodePtr node)
{
    xmlRpcValuePtr ret = xmlRpcValueNew(XML_RPC_BOOLEAN);
    char *value = xmlGetText(node);

K
Karel Zak 已提交
127 128 129
    if (!ret)
        return NULL;
    if (value && atoi(value))
130
        ret->value.boolean = true;
131
    else
132
        ret->value.boolean = false;
133
    VIR_FREE(value);
134 135 136 137 138 139 140 141
    return ret;
}

static xmlRpcValuePtr xmlRpcValueUnmarshalDouble(xmlNodePtr node)
{
    xmlRpcValuePtr ret = xmlRpcValueNew(XML_RPC_DOUBLE);
    char *value = xmlGetText(node);

K
Karel Zak 已提交
142 143
    if (ret && value)
        ret->value.real = atof(value);
144
    VIR_FREE(value);
145 146 147 148 149 150 151 152
    return ret;
}

static xmlRpcValuePtr xmlRpcValueUnmarshalArray(xmlNodePtr node)
{
    xmlRpcValuePtr ret = xmlRpcValueNew(XML_RPC_ARRAY);
    xmlNodePtr cur;
    int n_elements = 0;
153
    xmlRpcValuePtr *elems;
154

K
Karel Zak 已提交
155 156
    if (!ret)
        return NULL;
157

158
    for (cur = xmlFirstElement(node); cur; cur = xmlNextElement(cur))
159
        n_elements += 1;
160

161
    if (VIR_ALLOC_N(elems, n_elements) < 0) {
162
        xmlRpcError(VIR_ERR_NO_MEMORY, _("allocate value array"),
163
                    n_elements * sizeof(*elems));
164
        VIR_FREE(ret);
165
        return NULL;
K
Karel Zak 已提交
166
    }
167 168
    n_elements = 0;
    for (cur = xmlFirstElement(node); cur; cur = xmlNextElement(cur)) {
169 170
        elems[n_elements] = xmlRpcValueUnmarshal(cur);
        n_elements += 1;
171 172
    }

173
    ret->value.array.elements = elems;
174 175 176 177 178 179 180
    ret->value.array.n_elements = n_elements;

    return ret;
}

static xmlRpcValueDictElementPtr xmlRpcValueUnmarshalDictElement(xmlNodePtr node)
{
181
    xmlRpcValueDictElementPtr ret;
182 183
    xmlNodePtr cur;

184
    if (VIR_ALLOC(ret) < 0) {
185 186
        xmlRpcError(VIR_ERR_NO_MEMORY, _("allocate dict"), sizeof(*ret));
        return NULL;
K
Karel Zak 已提交
187
    }
188 189 190
    memset(ret, 0, sizeof(*ret));

    for (cur = xmlFirstElement(node); cur; cur = xmlNextElement(cur)) {
191 192 193 194 195
        if (xmlStrEqual(cur->name, BAD_CAST "name")) {
            ret->name = xmlGetText(cur);
        } else if (xmlStrEqual(cur->name, BAD_CAST "value")) {
            ret->value = xmlRpcValueUnmarshal(cur);
        } else {
196
            xmlRpcError(VIR_ERR_XML_ERROR, _("unexpected dict node"), 0);
197
            VIR_FREE(ret->name);
198 199
            if (ret->value)
                xmlRpcValueFree(ret->value);
200
            VIR_FREE(ret);
201 202
            return NULL;
        }
203 204 205 206 207 208 209 210 211 212 213 214 215
    }

    ret->next = NULL;

    return ret;
}

static xmlRpcValuePtr xmlRpcValueUnmarshalDict(xmlNodePtr node)
{
    xmlRpcValueDictElementPtr root = NULL, *elem = &root;
    xmlRpcValuePtr ret = xmlRpcValueNew(XML_RPC_STRUCT);
    xmlNodePtr cur;

K
Karel Zak 已提交
216
    if (!ret)
217
        return NULL;
218

K
Karel Zak 已提交
219
    ret->value.dict.root = root;
220

221
    for (cur = xmlFirstElement(node); cur; cur = xmlNextElement(cur)) {
222 223 224 225 226 227
        *elem = xmlRpcValueUnmarshalDictElement(cur);
        if (*elem==NULL) {
            xmlRpcValueFree(ret);
            return NULL;
        }
        elem = &(*elem)->next;
228 229 230 231 232 233 234 235
    }

    return ret;
}

xmlRpcValuePtr xmlRpcValueUnmarshal(xmlNodePtr node)
{
    xmlNodePtr n;
K
Karel Zak 已提交
236
    xmlRpcValuePtr ret = NULL;
237 238

    if (xmlStrEqual(node->name, BAD_CAST "value")) {
239 240 241 242 243 244
        n = xmlFirstElement(node);
        if (n == NULL) {
            ret = xmlRpcValueUnmarshalString(node);
        } else {
            ret = xmlRpcValueUnmarshal(n);
        }
245
    } else if (xmlStrEqual(node->name, BAD_CAST "dateTime.iso8601")) {
246
        ret = xmlRpcValueUnmarshalDateTime(node);
247
    } else if (xmlStrEqual(node->name, BAD_CAST "string")) {
248
        ret = xmlRpcValueUnmarshalString(node);
249
    } else if (xmlStrEqual(node->name, BAD_CAST "base64")) {
250
        ret = xmlRpcValueUnmarshalBase64(node);
251
    } else if (xmlStrEqual(node->name, BAD_CAST "i4") ||
252 253
               xmlStrEqual(node->name, BAD_CAST "int")) {
        ret = xmlRpcValueUnmarshalInteger(node);
254
    } else if (xmlStrEqual(node->name, BAD_CAST "boolean")) {
255
        ret = xmlRpcValueUnmarshalBoolean(node);
256
    } else if (xmlStrEqual(node->name, BAD_CAST "double")) {
257
        ret = xmlRpcValueUnmarshalDouble(node);
258
    } else if (xmlStrEqual(node->name, BAD_CAST "array")) {
259
        ret = xmlRpcValueUnmarshal(xmlFirstElement(node));
260
    } else if (xmlStrEqual(node->name, BAD_CAST "data")) {
261
        ret = xmlRpcValueUnmarshalArray(node);
262
    } else if (xmlStrEqual(node->name, BAD_CAST "struct")) {
263
        ret = xmlRpcValueUnmarshalDict(node);
264
    } else if (xmlStrEqual(node->name, BAD_CAST "nil")) {
265
        ret = xmlRpcValueNew(XML_RPC_NIL);
266
    } else {
267
        xmlRpcError(VIR_ERR_XML_ERROR, _("unexpected value node"), 0);
268 269 270 271 272 273 274 275 276 277 278
    }

    return ret;
}

void xmlRpcValueFree(xmlRpcValuePtr value)
{
    int i;
    xmlRpcValueDictElementPtr cur, next;

    if (value == NULL)
279
        return;
280 281 282

    switch (value->kind) {
    case XML_RPC_ARRAY:
283 284
        for (i = 0; i < value->value.array.n_elements; i++)
            xmlRpcValueFree(value->value.array.elements[i]);
285
        VIR_FREE(value->value.array.elements);
286
        break;
287
    case XML_RPC_STRUCT:
288 289 290 291
        next = value->value.dict.root;
        while (next) {
            cur = next;
            next = next->next;
292
            VIR_FREE(cur->name);
293
            xmlRpcValueFree(cur->value);
294
            VIR_FREE(cur);
295 296
        }
        break;
297
    case XML_RPC_STRING:
298
        VIR_FREE(value->value.string);
299
        break;
300
    default:
301
        break;
302 303
    }

304
    VIR_FREE(value);
305 306 307 308 309 310 311 312 313 314
}

void xmlRpcValueMarshal(xmlRpcValuePtr value, virBufferPtr buf, int indent)
{
    int i;
    xmlRpcValueDictElement *elem;

    virBufferVSprintf(buf, "%*s<value>", indent, "");
    switch (value->kind) {
    case XML_RPC_ARRAY:
315 316 317 318 319
        virBufferStrcat(buf, "<array><data>\n", NULL);
        for (i = 0; i < value->value.array.n_elements; i++)
            xmlRpcValueMarshal(value->value.array.elements[i], buf, indent+2);
        virBufferVSprintf(buf, "%*s</data></array>", indent, "");
        break;
320
    case XML_RPC_STRUCT:
321 322 323 324 325 326 327 328 329 330 331 332
        virBufferStrcat(buf, "<struct>\n", NULL);
        indent += 2;
        for (elem = value->value.dict.root; elem; elem = elem->next) {
            virBufferVSprintf(buf, "%*s<member>\n", indent, "");
            virBufferVSprintf(buf, "%*s<name>%s</name>\n",
                              indent + 2, "", elem->name);
            xmlRpcValueMarshal(elem->value, buf, indent + 2);
            virBufferVSprintf(buf, "%*s</member>\n", indent, "");
        }
        indent -= 2;
        virBufferVSprintf(buf, "%*s</struct>", indent, "");
        break;
333
    case XML_RPC_INTEGER:
334 335
        virBufferVSprintf(buf, "<int>%d</int>", value->value.integer);
        break;
336
    case XML_RPC_DOUBLE:
337 338
        virBufferVSprintf(buf, "<double>%f</double>", value->value.real);
        break;
339
    case XML_RPC_BOOLEAN:
340 341 342 343 344 345
        if (value->value.boolean)
            i = 1;
        else
            i = 0;
        virBufferVSprintf(buf, "<boolean>%d</boolean>", i);
        break;
346
    case XML_RPC_DATE_TIME:
347 348 349
        /* FIXME */
        TODO
        break;
350
    case XML_RPC_BASE64:
351 352 353
        /* FIXME */
        TODO
        break;
354
    case XML_RPC_STRING:
355 356 357
        virBufferStrcat(buf,
                "<string>", value->value.string, "</string>", NULL);
        break;
358
    case XML_RPC_NIL:
359 360
        virBufferStrcat(buf, "<nil> </nil>", NULL);
        break;
361
    }
K
Karel Zak 已提交
362
    virBufferStrcat(buf, "</value>\n", NULL);
363 364
}

365 366 367
void xmlRpcMarshalRequest(const char *request,
                          virBufferPtr buf,
                          int argc, xmlRpcValuePtr *argv)
368 369 370
{
    int i;

K
Karel Zak 已提交
371
    virBufferStrcat(buf,
372 373 374 375
                    "<?xml version=\"1.0\"?>\n"
                    "<methodCall>\n"
                    "  <methodName>", request, "</methodName>\n"
                    "  <params>\n", NULL);
376
    for (i = 0; i < argc; i++) {
377
        virBufferStrcat(buf,
K
Karel Zak 已提交
378
                    "    <param>\n", NULL);
379 380
        xmlRpcValueMarshal(argv[i], buf, 6);
        virBufferStrcat(buf,
K
Karel Zak 已提交
381
                    "    </param>\n", NULL);
382
    }
K
Karel Zak 已提交
383 384
    virBufferStrcat(buf,
                    "  </params>\n"
385
                    "</methodCall>\n", NULL);
386 387 388 389
}

xmlRpcValuePtr xmlRpcUnmarshalResponse(xmlNodePtr node, bool *is_fault)
{
K
Karel Zak 已提交
390
    if (!node)
391
        return NULL;
K
Karel Zak 已提交
392

393
    if (!xmlStrEqual(node->name, BAD_CAST "methodResponse"))
394
        return NULL;
395 396 397

    node = xmlFirstElement(node);
    if (xmlStrEqual(node->name, BAD_CAST "params")) {
398
        node = xmlFirstElement(node);
399

400 401
        if (!xmlStrEqual(node->name, BAD_CAST "param"))
            return NULL;
402

403 404
        *is_fault = false;
        return xmlRpcValueUnmarshal(xmlFirstElement(node));
405
    } else if (xmlStrEqual(node->name, BAD_CAST "fault")) {
406 407
        *is_fault = true;
        return xmlRpcValueUnmarshal(xmlFirstElement(node));
408
    } else
409
        return NULL;
410 411 412 413
}

static char *xmlRpcCallRaw(const char *url, const char *request)
{
414 415 416 417 418 419 420 421 422 423 424 425 426
        void *cxt;
        char *contentType = (char *) "text/xml";
        int len, ret, serrno;
        char *response = NULL;

        cxt = xmlNanoHTTPMethod(url,
                                "POST",
                                request,
                                &contentType,
                                NULL,
                                strlen(request));

        if (cxt == NULL) {
427
                xmlRpcError(VIR_ERR_POST_FAILED, _("send request"), 0);
428 429 430
                goto error;
        }

431
        if (contentType && STRNEQ(contentType, "text/xml")) {
432 433 434 435 436 437
                errno = EINVAL;
                xmlRpcError(VIR_ERR_POST_FAILED, _("unexpected mime type"), 0);
                goto error;
        }

        len = xmlNanoHTTPContentLength(cxt);
438
        if (VIR_ALLOC_N(response, len + 1) < 0) {
439 440 441 442 443 444
                xmlRpcError(VIR_ERR_NO_MEMORY, _("allocate response"), len);
                goto error;
        }
        ret = xmlNanoHTTPRead(cxt, response, len);
        if (ret != len) {
                errno = EINVAL;
445
                VIR_FREE(response);
446 447 448 449
                xmlRpcError(VIR_ERR_POST_FAILED, _("read response"), 0);
        }

        response[len] = 0;
450 451

 error:
452 453 454
        serrno = errno;
        if (cxt) {
                xmlNanoHTTPClose(cxt);
455
                VIR_FREE(contentType);
456 457 458 459
        }
        errno = serrno;

        return response;
460 461 462 463 464 465 466 467 468
}

static char **xmlRpcStringArray(xmlRpcValuePtr value)
{
    char **ret, *ptr;
    int i;
    size_t size = 0;

    if (value->kind != XML_RPC_ARRAY)
469
        return NULL;
470 471 472 473

    size = sizeof(char *) * (value->value.array.n_elements + 1);

    for (i = 0; i < value->value.array.n_elements; i++)
474 475
        if (value->value.array.elements[i]->kind == XML_RPC_STRING)
            size += strlen(value->value.array.elements[i]->value.string) + 1;
476

477
    if (VIR_ALLOC_N(ptr, size) < 0) {
478 479
        xmlRpcError(VIR_ERR_NO_MEMORY, _("allocate string array"), size);
        return NULL;
K
Karel Zak 已提交
480
    }
481 482 483 484
    ret = (char **)ptr;
    ptr += sizeof(char *) * (value->value.array.n_elements + 1);

    for (i = 0; i < value->value.array.n_elements; i++) {
485 486 487 488 489 490 491
        if (value->value.array.elements[i]->kind == XML_RPC_STRING) {
            char *s = value->value.array.elements[i]->value.string;
            strcpy(ptr, s);
            ret[i] = ptr;
            ptr += strlen(s) + 1;
        } else
            ret[i] = (char *) "";
492 493 494 495 496 497 498
    }

    ret[i] = NULL;

    return ret;
}

K
Karel Zak 已提交
499 500
xmlRpcValuePtr *
xmlRpcArgvNew(const char *fmt, va_list ap, int *argc)
501 502
{
    xmlRpcValuePtr *argv;
K
Karel Zak 已提交
503
    const char *ptr;
504
    int i;
505

K
Karel Zak 已提交
506
    *argc = strlen(fmt);
507
    if (VIR_ALLOC_N(argv, *argc) < 0) {
508
        xmlRpcError(VIR_ERR_NO_MEMORY, _("read response"), sizeof(*argv) * *argc);
K
Karel Zak 已提交
509 510
        return NULL;
    }
511 512
    i = 0;
    for (ptr = fmt; *ptr; ptr++) {
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
        switch (*ptr) {
        case 'i':
            if ((argv[i] = xmlRpcValueNew(XML_RPC_INTEGER)))
                argv[i]->value.integer = va_arg(ap, int32_t);
            break;
        case 'f':
            if ((argv[i] = xmlRpcValueNew(XML_RPC_DOUBLE)))
                argv[i]->value.real = va_arg(ap, double);
            break;
        case 'b':
            if ((argv[i] = xmlRpcValueNew(XML_RPC_BOOLEAN)))
                argv[i]->value.boolean = va_arg(ap, int);
            break;
        case 's':
            if ((argv[i] = xmlRpcValueNew(XML_RPC_STRING)))
                argv[i]->value.string = strdup(va_arg(ap, const char *));
            break;
        default:
            argv[i] = NULL;
            break;
        }
        if (argv[i]==NULL) {
            xmlRpcArgvFree(i, argv);
            return NULL;
        }
        i++;
539
    }
K
Karel Zak 已提交
540 541
    return argv;
}
542

K
Karel Zak 已提交
543 544 545 546
void
xmlRpcArgvFree(int argc, xmlRpcValuePtr *argv)
{
    int i;
K
Karel Zak 已提交
547
    if (!argv)
548
        return;
549
    for (i = 0; i < argc; i++)
550
        xmlRpcValueFree(argv[i]);
551

552
    VIR_FREE(argv);
K
Karel Zak 已提交
553 554 555
}

int xmlRpcCall(xmlRpcContextPtr context, const char *method,
556
               const char *retfmt, const char *fmt, ...)
K
Karel Zak 已提交
557 558 559 560
{
    va_list ap;
    int argc;
    xmlRpcValuePtr *argv;
561
    virBuffer buf = VIR_BUFFER_INITIALIZER;
K
Karel Zak 已提交
562 563 564 565 566 567
    char *ret;
    xmlDocPtr xml;
    xmlNodePtr node;
    bool fault;
    xmlRpcValuePtr value;
    void *retval = NULL;
568
    char *content;
K
Karel Zak 已提交
569 570

    va_start(ap, fmt);
571

K
Karel Zak 已提交
572
    if (retfmt && *retfmt)
573
        retval = va_arg(ap, void *);
574

K
Karel Zak 已提交
575
    if (!(argv = xmlRpcArgvNew(fmt, ap, &argc)))
576
        return -1;
577

K
Karel Zak 已提交
578 579
    va_end(ap);

580
    xmlRpcMarshalRequest(method, &buf, argc, argv);
K
Karel Zak 已提交
581 582

    xmlRpcArgvFree(argc, argv);
583

584
    if (virBufferError(&buf))
585
        return -1;
586

587 588
    content = virBufferContentAndReset(&buf);
    ret = xmlRpcCallRaw(context->uri, content);
589
    VIR_FREE(content);
590

K
Karel Zak 已提交
591
    if (!ret)
592
        return -1;
K
Karel Zak 已提交
593

594
    xml = xmlReadDoc((const xmlChar *)ret, "response.xml", NULL,
595 596
                     XML_PARSE_NOENT | XML_PARSE_NONET |
                     XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
597
    VIR_FREE(ret);
598 599

    if (xml == NULL) {
600 601 602
        errno = EINVAL;
        xmlRpcError(VIR_ERR_XML_ERROR, _("parse server response failed"), 0);
        return -1;
603 604 605 606 607 608 609
    }

    node = xmlDocGetRootElement(xml);

    value = xmlRpcUnmarshalResponse(node, &fault);

    if (!fault) {
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
        switch (*retfmt) {
        case 'i':
            if (value->kind == XML_RPC_INTEGER)
                *(int32_t *)retval = value->value.integer;
            break;
        case 'b':
            if (value->kind == XML_RPC_BOOLEAN)
                *(bool *)retval = value->value.boolean;
            break;
        case 'f':
            if (value->kind == XML_RPC_DOUBLE)
                *(double *)retval = value->value.real;
            break;
        case 's':
            if (value->kind == XML_RPC_STRING)
                *(char **)retval = strdup(value->value.string);
            break;
        case 'S':
            *(char ***)retval = xmlRpcStringArray(value);
            break;
        case 'V':
            *(xmlRpcValuePtr *)retval = value;
            value = NULL;
            break;
        default:
            printf("not supported yet\n");
            break;
        }
638 639 640 641
    }

    xmlFreeDoc(xml);

642
    if (fault) {
643 644 645 646 647 648 649
        /* FIXME we need generic dict routines */
        /* FIXME we need faultMessage propagate to libvirt error API */
        context->faultCode = value->value.dict.root->value->value.integer;
        context->faultMessage = strdup(value->value.dict.root->next->value->value.string);
        xmlRpcValueFree(value);
        errno = EFAULT;
        return -1;
650 651 652 653 654 655 656 657 658
    }

    xmlRpcValueFree(value);

    return 0;
}

xmlRpcContextPtr xmlRpcContextNew(const char *uri)
{
659
    xmlRpcContextPtr ret;
660

661 662 663
    if (VIR_ALLOC(ret) < 0) {
        xmlRpcError(VIR_ERR_NO_MEMORY, _("allocate new context"), sizeof(*ret));
    } else {
664 665
        ret->uri = strdup(uri);
        ret->faultMessage = NULL;
666
    }
667 668 669 670 671 672 673

    return ret;
}

void xmlRpcContextFree(xmlRpcContextPtr context)
{
    if (context) {
674 675 676
        VIR_FREE(context->uri);
        VIR_FREE(context->faultMessage);
        VIR_FREE(context);
677 678 679 680 681 682 683 684 685 686 687 688
    }
}

int xmlRpcContextFaultCode(xmlRpcContextPtr context)
{
    return context->faultCode;
}

const char *xmlRpcContextFaultMessage(xmlRpcContextPtr context)
{
    return context->faultMessage;
}