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 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

#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 已提交
36 37 38 39 40 41 42 43
static void xmlRpcError(virErrorNumber error, const char *info, int value)
{
    const char *errmsg;

    if (error == VIR_ERR_OK)
        return;

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

48 49 50
static xmlRpcValuePtr xmlRpcValueNew(xmlRpcValueType type)
{
    xmlRpcValuePtr ret = malloc(sizeof(*ret));
51

K
Karel Zak 已提交
52
    if (!ret)
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
    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
    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
    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 162
    elems = malloc(n_elements * sizeof(*elems));
    if (!elems) {
163
        xmlRpcError(VIR_ERR_NO_MEMORY, _("allocate value array"),
164
                    n_elements * sizeof(*elems));
165 166
        free(ret);
        return NULL;
K
Karel Zak 已提交
167
    }
168 169
    n_elements = 0;
    for (cur = xmlFirstElement(node); cur; cur = xmlNextElement(cur)) {
170 171
        elems[n_elements] = xmlRpcValueUnmarshal(cur);
        n_elements += 1;
172 173
    }

174
    ret->value.array.elements = elems;
175 176 177 178 179 180 181 182 183 184
    ret->value.array.n_elements = n_elements;

    return ret;
}

static xmlRpcValueDictElementPtr xmlRpcValueUnmarshalDictElement(xmlNodePtr node)
{
    xmlRpcValueDictElementPtr ret = malloc(sizeof(*ret));
    xmlNodePtr cur;

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

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

    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 已提交
217
    if (!ret)
218
        return NULL;
219

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

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

    return ret;
}

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

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

    return ret;
}

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

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

    switch (value->kind) {
    case XML_RPC_ARRAY:
284 285 286 287
        for (i = 0; i < value->value.array.n_elements; i++)
            xmlRpcValueFree(value->value.array.elements[i]);
        free(value->value.array.elements);
        break;
288
    case XML_RPC_STRUCT:
289 290 291 292 293 294 295 296 297
        next = value->value.dict.root;
        while (next) {
            cur = next;
            next = next->next;
            free(cur->name);
            xmlRpcValueFree(cur->value);
            free(cur);
        }
        break;
298
    case XML_RPC_STRING:
299 300
        free(value->value.string);
        break;
301
    default:
302
        break;
303 304 305 306 307 308 309 310 311 312 313 314 315
    }

    free(value);
}

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

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

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

K
Karel Zak 已提交
372 373 374
    buf = virBufferNew(1024);

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

xmlRpcValuePtr xmlRpcUnmarshalResponse(xmlNodePtr node, bool *is_fault)
{
K
Karel Zak 已提交
394
    if (!node)
395
        return NULL;
K
Karel Zak 已提交
396

397
    if (!xmlStrEqual(node->name, BAD_CAST "methodResponse"))
398
        return NULL;
399 400 401

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

404 405
        if (!xmlStrEqual(node->name, BAD_CAST "param"))
            return NULL;
406

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

static char *xmlRpcCallRaw(const char *url, const char *request)
{
418 419 420 421 422 423 424 425 426 427 428 429 430
        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) {
431
                xmlRpcError(VIR_ERR_POST_FAILED, _("send request"), 0);
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
                goto error;
        }

        if (contentType && strcmp(contentType, "text/xml") != 0) {
                errno = EINVAL;
                xmlRpcError(VIR_ERR_POST_FAILED, _("unexpected mime type"), 0);
                goto error;
        }

        len = xmlNanoHTTPContentLength(cxt);
        response = malloc(len + 1);
        if (response == NULL) {
                xmlRpcError(VIR_ERR_NO_MEMORY, _("allocate response"), len);
                goto error;
        }
        ret = xmlNanoHTTPRead(cxt, response, len);
        if (ret != len) {
                errno = EINVAL;
                free(response);
                response = NULL;
                xmlRpcError(VIR_ERR_POST_FAILED, _("read response"), 0);
        }

        response[len] = 0;
456 457

 error:
458 459 460 461 462 463 464 465
        serrno = errno;
        if (cxt) {
                xmlNanoHTTPClose(cxt);
                free(contentType);
        }
        errno = serrno;

        return response;
466 467 468 469 470 471 472 473 474
}

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

    if (value->kind != XML_RPC_ARRAY)
475
        return NULL;
476 477 478 479

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

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

K
Karel Zak 已提交
483
    if (!(ptr = malloc(size))) {
484 485
        xmlRpcError(VIR_ERR_NO_MEMORY, _("allocate string array"), size);
        return NULL;
K
Karel Zak 已提交
486
    }
487 488 489 490
    ret = (char **)ptr;
    ptr += sizeof(char *) * (value->value.array.n_elements + 1);

    for (i = 0; i < value->value.array.n_elements; i++) {
491 492 493 494 495 496 497
        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 *) "";
498 499 500 501 502 503 504
    }

    ret[i] = NULL;

    return ret;
}

K
Karel Zak 已提交
505 506
xmlRpcValuePtr *
xmlRpcArgvNew(const char *fmt, va_list ap, int *argc)
507 508
{
    xmlRpcValuePtr *argv;
K
Karel Zak 已提交
509
    const char *ptr;
510
    int i;
511

K
Karel Zak 已提交
512
    *argc = strlen(fmt);
K
Karel Zak 已提交
513
    if (!(argv = malloc(sizeof(*argv) * *argc))) {
514
        xmlRpcError(VIR_ERR_NO_MEMORY, _("read response"), sizeof(*argv) * *argc);
K
Karel Zak 已提交
515 516
        return NULL;
    }
517 518
    i = 0;
    for (ptr = fmt; *ptr; ptr++) {
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
        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++;
545
    }
K
Karel Zak 已提交
546 547
    return argv;
}
548

K
Karel Zak 已提交
549 550 551 552
void
xmlRpcArgvFree(int argc, xmlRpcValuePtr *argv)
{
    int i;
K
Karel Zak 已提交
553
    if (!argv)
554
        return;
555
    for (i = 0; i < argc; i++)
556
        xmlRpcValueFree(argv[i]);
557 558

    free(argv);
K
Karel Zak 已提交
559 560 561
}

int xmlRpcCall(xmlRpcContextPtr context, const char *method,
562
               const char *retfmt, const char *fmt, ...)
K
Karel Zak 已提交
563 564 565 566 567 568 569 570 571 572 573 574 575
{
    va_list ap;
    int argc;
    xmlRpcValuePtr *argv;
    virBufferPtr buf;
    char *ret;
    xmlDocPtr xml;
    xmlNodePtr node;
    bool fault;
    xmlRpcValuePtr value;
    void *retval = NULL;

    va_start(ap, fmt);
576

K
Karel Zak 已提交
577
    if (retfmt && *retfmt)
578
        retval = va_arg(ap, void *);
579

K
Karel Zak 已提交
580
    if (!(argv = xmlRpcArgvNew(fmt, ap, &argc)))
581
        return -1;
582

K
Karel Zak 已提交
583 584 585 586 587
    va_end(ap);

    buf = xmlRpcMarshalRequest(method, argc, argv);

    xmlRpcArgvFree(argc, argv);
588

K
Karel Zak 已提交
589
    if (!buf)
590
        return -1;
591

592 593
    ret = xmlRpcCallRaw(context->uri, buf->content);

K
Karel Zak 已提交
594
    virBufferFree(buf);
595

K
Karel Zak 已提交
596
    if (!ret)
597
        return -1;
K
Karel Zak 已提交
598

599
    xml = xmlReadDoc((const xmlChar *)ret, "response.xml", NULL,
600 601
                     XML_PARSE_NOENT | XML_PARSE_NONET |
                     XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
602 603 604
    free(ret);

    if (xml == NULL) {
605 606 607
        errno = EINVAL;
        xmlRpcError(VIR_ERR_XML_ERROR, _("parse server response failed"), 0);
        return -1;
608 609 610 611 612 613 614
    }

    node = xmlDocGetRootElement(xml);

    value = xmlRpcUnmarshalResponse(node, &fault);

    if (!fault) {
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
        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;
        }
643 644 645 646
    }

    xmlFreeDoc(xml);

647
    if (fault) {
648 649 650 651 652 653 654
        /* 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;
655 656 657 658 659 660 661 662 663 664 665 666
    }

    xmlRpcValueFree(value);

    return 0;
}

xmlRpcContextPtr xmlRpcContextNew(const char *uri)
{
    xmlRpcContextPtr ret = malloc(sizeof(*ret));

    if (ret) {
667 668
        ret->uri = strdup(uri);
        ret->faultMessage = NULL;
K
Karel Zak 已提交
669
    } else
670
        xmlRpcError(VIR_ERR_NO_MEMORY, _("allocate new context"), sizeof(*ret));
671 672 673 674 675 676 677

    return ret;
}

void xmlRpcContextFree(xmlRpcContextPtr context)
{
    if (context) {
678 679 680
        free(context->uri);
        free(context->faultMessage);
        free(context);
681 682 683 684 685 686 687 688 689 690 691 692
    }
}

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

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