remote_internal.c 223.2 KB
Newer Older
D
Daniel Veillard 已提交
1

2 3 4 5
/*
 * remote_internal.c: driver to provide access to libvirtd running
 *   on a remote machine
 *
6
 * Copyright (C) 2007-2009 Red Hat, Inc.
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * Author: Richard Jones <rjones@redhat.com>
 */

25
#include <config.h>
26

27
/* Windows socket compatibility functions. */
28 29
#include <errno.h>
#include <sys/socket.h>
30

31 32 33
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
34
#include <string.h>
35 36 37
#include <assert.h>
#include <signal.h>
#include <sys/types.h>
38 39
#include <sys/stat.h>
#include <fcntl.h>
40

41 42 43 44 45 46 47
#ifndef HAVE_WINSOCK2_H		/* Unix & Cygwin. */
# include <sys/un.h>
# include <net/if.h>
# include <netinet/in.h>
# include <netinet/tcp.h>
#endif

48 49 50 51 52 53 54 55 56
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif

#ifdef HAVE_PWD_H
#include <pwd.h>
#endif

#ifdef HAVE_PATHS_H
57
#include <paths.h>
58 59
#endif

60
#include <rpc/types.h>
61 62 63
#include <rpc/xdr.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
64
#include "gnutls_1_0_compat.h"
65 66 67
#if HAVE_SASL
#include <sasl/sasl.h>
#endif
68 69
#include <libxml/uri.h>

J
Jim Meyering 已提交
70
#include <netdb.h>
71

72 73
#include <poll.h>

74 75 76 77 78
/* AI_ADDRCONFIG is missing on some systems. */
#ifndef AI_ADDRCONFIG
# define AI_ADDRCONFIG 0
#endif

79
#include "virterror_internal.h"
80
#include "logging.h"
81
#include "datatypes.h"
82
#include "domain_event.h"
83
#include "driver.h"
84 85
#include "buf.h"
#include "qparams.h"
86 87
#include "remote_internal.h"
#include "remote_protocol.h"
88
#include "memory.h"
89
#include "util.h"
90
#include "event.h"
91

92 93
#define VIR_FROM_THIS VIR_FROM_REMOTE

94 95 96 97 98
#ifdef WIN32
#define pipe(fds) _pipe(fds,4096, _O_BINARY)
#endif


99 100
static int inside_daemon = 0;

101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
struct remote_thread_call;


enum {
    REMOTE_MODE_WAIT_TX,
    REMOTE_MODE_WAIT_RX,
    REMOTE_MODE_COMPLETE,
    REMOTE_MODE_ERROR,
};

struct remote_thread_call {
    int mode;

    /* 4 byte length, followed by RPC message header+body */
    char buffer[4 + REMOTE_MESSAGE_MAX];
    unsigned int bufferLength;
    unsigned int bufferOffset;

    unsigned int serial;
    unsigned int proc_nr;

    virCond cond;

    xdrproc_t ret_filter;
    char *ret;

    remote_error err;

    struct remote_thread_call *next;
};

132
struct private_data {
133 134
    virMutex lock;

135
    int sock;                   /* Socket. */
136
    int watch;                  /* File handle watch */
137
    pid_t pid;                  /* PID of tunnel process */
138 139 140 141
    int uses_tls;               /* TLS enabled on socket? */
    gnutls_session_t session;   /* GnuTLS session (if uses_tls != 0). */
    char *type;                 /* Cached return from remoteType. */
    int counter;                /* Generates serial numbers for RPC. */
142
    int localUses;              /* Ref count for private data */
143 144
    char *hostname;             /* Original hostname */
    FILE *debugLog;             /* Debug remote protocol */
145

146 147
#if HAVE_SASL
    sasl_conn_t *saslconn;      /* SASL context */
148

149 150 151
    const char *saslDecoded;
    unsigned int saslDecodedLength;
    unsigned int saslDecodedOffset;
152 153 154 155

    const char *saslEncoded;
    unsigned int saslEncodedLength;
    unsigned int saslEncodedOffset;
156
#endif
157 158 159 160 161 162

    /* 4 byte length, followed by RPC message header+body */
    char buffer[4 + REMOTE_MESSAGE_MAX];
    unsigned int bufferLength;
    unsigned int bufferOffset;

163 164 165 166 167 168 169
    /* The list of domain event callbacks */
    virDomainEventCallbackListPtr callbackList;
    /* The queue of domain events generated
       during a call / response rpc          */
    virDomainEventQueuePtr domainEvents;
    /* Timer for flushing domainEvents queue */
    int eventFlushTimer;
170 171 172 173 174 175 176

    /* Self-pipe to wakeup threads waiting in poll() */
    int wakeupSendFD;
    int wakeupReadFD;

    /* List of threads currently waiting for dispatch */
    struct remote_thread_call *waitDispatch;
177 178
};

179 180 181 182 183 184
enum {
    REMOTE_CALL_IN_OPEN = 1,
    REMOTE_CALL_QUIET_MISSING_RPC = 2,
};


185 186 187 188 189 190 191 192 193 194
static void remoteDriverLock(struct private_data *driver)
{
    virMutexLock(&driver->lock);
}

static void remoteDriverUnlock(struct private_data *driver)
{
    virMutexUnlock(&driver->lock);
}

195 196 197 198
static int call (virConnectPtr conn, struct private_data *priv,
                 int flags, int proc_nr,
                 xdrproc_t args_filter, char *args,
                 xdrproc_t ret_filter, char *ret);
199 200
static int remoteAuthenticate (virConnectPtr conn, struct private_data *priv, int in_open,
                               virConnectAuthPtr auth, const char *authtype);
201
#if HAVE_SASL
202 203
static int remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
                           virConnectAuthPtr auth, const char *mech);
204
#endif
205
#if HAVE_POLKIT
206 207
static int remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open,
                             virConnectAuthPtr auth);
208
#endif /* HAVE_POLKIT */
209
static void error (virConnectPtr conn, virErrorNumber code, const char *info);
210 211
static void errorf (virConnectPtr conn, virErrorNumber code,
                     const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 3, 4);
212 213 214
static void server_error (virConnectPtr conn, remote_error *err);
static virDomainPtr get_nonnull_domain (virConnectPtr conn, remote_nonnull_domain domain);
static virNetworkPtr get_nonnull_network (virConnectPtr conn, remote_nonnull_network network);
215
static virInterfacePtr get_nonnull_interface (virConnectPtr conn, remote_nonnull_interface iface);
216 217
static virStoragePoolPtr get_nonnull_storage_pool (virConnectPtr conn, remote_nonnull_storage_pool pool);
static virStorageVolPtr get_nonnull_storage_vol (virConnectPtr conn, remote_nonnull_storage_vol vol);
218
static virNodeDevicePtr get_nonnull_node_device (virConnectPtr conn, remote_nonnull_node_device dev);
219 220
static void make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src);
static void make_nonnull_network (remote_nonnull_network *net_dst, virNetworkPtr net_src);
D
Daniel Veillard 已提交
221
static void make_nonnull_interface (remote_nonnull_interface *interface_dst, virInterfacePtr interface_src);
222 223
static void make_nonnull_storage_pool (remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr vol_src);
static void make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src);
224
void remoteDomainEventFired(int watch, int fd, int event, void *data);
225 226
static void remoteDomainQueueEvent(virConnectPtr conn, XDR *xdr);
void remoteDomainEventQueueFlush(int timer, void *opaque);
227 228 229 230 231 232 233
/*----------------------------------------------------------------------*/

/* Helper functions for remoteOpen. */
static char *get_transport_from_scheme (char *scheme);

/* GnuTLS functions used by remoteOpen. */
static int initialise_gnutls (virConnectPtr conn);
234
static gnutls_session_t negotiate_gnutls_on_connection (virConnectPtr conn, struct private_data *priv, int no_verify);
235

A
Atsushi SAKAI 已提交
236
#ifdef WITH_LIBVIRTD
237
static int
238
remoteStartup(int privileged ATTRIBUTE_UNUSED)
239 240 241 242 243 244 245
{
    /* Mark that we're inside the daemon so we can avoid
     * re-entering ourselves
     */
    inside_daemon = 1;
    return 0;
}
A
Atsushi SAKAI 已提交
246
#endif
247

248
#ifndef WIN32
249 250 251 252
/**
 * remoteFindServerPath:
 *
 * Tries to find the path to the libvirtd binary.
253
 *
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
 * Returns path on success or NULL in case of error.
 */
static const char *
remoteFindDaemonPath(void)
{
    static const char *serverPaths[] = {
        SBINDIR "/libvirtd",
        SBINDIR "/libvirtd_dbg",
        NULL
    };
    int i;
    const char *customDaemon = getenv("LIBVIRTD_PATH");

    if (customDaemon)
        return(customDaemon);

    for (i = 0; serverPaths[i]; i++) {
        if (access(serverPaths[i], X_OK | R_OK) == 0) {
            return serverPaths[i];
        }
    }
    return NULL;
}

/**
 * qemuForkDaemon:
 *
 * Forks and try to launch the libvirtd daemon
 *
 * Returns 0 in case of success or -1 in case of detected error.
 */
285
static int
286 287 288
remoteForkDaemon(virConnectPtr conn)
{
    const char *daemonPath = remoteFindDaemonPath();
289
    const char *const daemonargs[] = { daemonPath, "--timeout=30", NULL };
290
    pid_t pid;
291 292

    if (!daemonPath) {
293
        error(conn, VIR_ERR_INTERNAL_ERROR, _("failed to find libvirtd binary"));
294
        return -1;
295 296
    }

297
    if (virExecDaemonize(NULL, daemonargs, NULL, NULL,
298 299
                         &pid, -1, NULL, NULL,
                         VIR_EXEC_CLEAR_CAPS,
300
                         NULL, NULL, NULL) < 0)
301
        return -1;
302

303
    return 0;
304
}
305
#endif
306

307
enum virDrvOpenRemoteFlags {
308
    VIR_DRV_OPEN_REMOTE_RO = (1 << 0),
309 310
    VIR_DRV_OPEN_REMOTE_USER      = (1 << 1), /* Use the per-user socket path */
    VIR_DRV_OPEN_REMOTE_AUTOSTART = (1 << 2), /* Autostart a per-user daemon */
311
};
312

313

314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
/*
 * URIs that this driver needs to handle:
 *
 * The easy answer:
 *   - Everything that no one else has yet claimed, but nothing if
 *     we're inside the libvirtd daemon
 *
 * The hard answer:
 *   - Plain paths (///var/lib/xen/xend-socket)  -> UNIX domain socket
 *   - xxx://servername/      -> TLS connection
 *   - xxx+tls://servername/  -> TLS connection
 *   - xxx+tls:///            -> TLS connection to localhost
 *   - xxx+tcp://servername/  -> TCP connection
 *   - xxx+tcp:///            -> TCP connection to localhost
 *   - xxx+unix:///           -> UNIX domain socket
 *   - xxx:///                -> UNIX domain socket
 */
331
static int
332 333 334 335
doRemoteOpen (virConnectPtr conn,
              struct private_data *priv,
              virConnectAuthPtr auth ATTRIBUTE_UNUSED,
              int flags)
336
{
337
    int wakeupFD[2] = { -1, -1 };
338
    char *transport_str = NULL;
339 340 341 342 343 344 345
    enum {
        trans_tls,
        trans_unix,
        trans_ssh,
        trans_ext,
        trans_tcp,
    } transport;
346

347 348
    /* We handle *ALL*  URIs here. The caller has rejected any
     * URIs we don't care about */
349

350 351 352
    if (conn->uri) {
        if (!conn->uri->scheme) {
            /* This is the ///var/lib/xen/xend-socket local path style */
353
            transport = trans_unix;
354 355
        } else {
            transport_str = get_transport_from_scheme (conn->uri->scheme);
356

357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
            if (!transport_str) {
                if (conn->uri->server)
                    transport = trans_tls;
                else
                    transport = trans_unix;
            } else {
                if (STRCASEEQ (transport_str, "tls"))
                    transport = trans_tls;
                else if (STRCASEEQ (transport_str, "unix"))
                    transport = trans_unix;
                else if (STRCASEEQ (transport_str, "ssh"))
                    transport = trans_ssh;
                else if (STRCASEEQ (transport_str, "ext"))
                    transport = trans_ext;
                else if (STRCASEEQ (transport_str, "tcp"))
                    transport = trans_tcp;
                else {
                    error (conn, VIR_ERR_INVALID_ARG,
                           _("remote_open: transport in URL not recognised "
                             "(should be tls|unix|ssh|ext|tcp)"));
                    return VIR_DRV_OPEN_ERROR;
                }
            }
        }
    } else {
        /* No URI, then must be probing so use UNIX socket */
        transport = trans_unix;
384
    }
385

386 387 388
    /* Local variables which we will initialise. These can
     * get freed in the failed: path.
     */
389 390
    char *name = NULL, *command = NULL, *sockname = NULL, *netcat = NULL;
    char *port = NULL, *authtype = NULL, *username = NULL;
391
    int no_verify = 0, no_tty = 0;
392
    char **cmd_argv = NULL;
393

394 395 396
    /* Return code from this function, and the private data. */
    int retcode = VIR_DRV_OPEN_ERROR;

397
    /* Remote server defaults to "localhost" if not specified. */
398
    if (conn->uri && conn->uri->port != 0) {
399
        if (virAsprintf(&port, "%d", conn->uri->port) == -1) goto out_of_memory;
400 401 402 403 404 405 406
    } else if (transport == trans_tls) {
        port = strdup (LIBVIRTD_TLS_PORT);
        if (!port) goto out_of_memory;
    } else if (transport == trans_tcp) {
        port = strdup (LIBVIRTD_TCP_PORT);
        if (!port) goto out_of_memory;
    } else
407
        port = NULL; /* Port not used for unix, ext., default for ssh */
408

409

410 411
    priv->hostname = strdup (conn->uri && conn->uri->server ?
                             conn->uri->server : "localhost");
412 413
    if (!priv->hostname)
        goto out_of_memory;
414 415
    if (conn->uri && conn->uri->user) {
        username = strdup (conn->uri->user);
416 417
        if (!username)
            goto out_of_memory;
418 419
    }

420 421 422 423 424
    /* Get the variables from the query string.
     * Then we need to reconstruct the query string (because
     * feasibly it might contain variables needed by the real driver,
     * although that won't be the case for now).
     */
425 426 427
    struct qparam_set *vars;
    struct qparam *var;
    int i;
428 429
    char *query;

430
    if (conn->uri) {
431
#ifdef HAVE_XMLURI_QUERY_RAW
432
        query = conn->uri->query_raw;
433
#else
434
        query = conn->uri->query;
435
#endif
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
        vars = qparam_query_parse (query);
        if (vars == NULL) goto failed;

        for (i = 0; i < vars->n; i++) {
            var = &vars->p[i];
            if (STRCASEEQ (var->name, "name")) {
                name = strdup (var->value);
                if (!name) goto out_of_memory;
                var->ignore = 1;
            } else if (STRCASEEQ (var->name, "command")) {
                command = strdup (var->value);
                if (!command) goto out_of_memory;
                var->ignore = 1;
            } else if (STRCASEEQ (var->name, "socket")) {
                sockname = strdup (var->value);
                if (!sockname) goto out_of_memory;
                var->ignore = 1;
            } else if (STRCASEEQ (var->name, "auth")) {
                authtype = strdup (var->value);
                if (!authtype) goto out_of_memory;
                var->ignore = 1;
            } else if (STRCASEEQ (var->name, "netcat")) {
                netcat = strdup (var->value);
                if (!netcat) goto out_of_memory;
                var->ignore = 1;
            } else if (STRCASEEQ (var->name, "no_verify")) {
                no_verify = atoi (var->value);
                var->ignore = 1;
            } else if (STRCASEEQ (var->name, "no_tty")) {
                no_tty = atoi (var->value);
                var->ignore = 1;
            } else if (STRCASEEQ (var->name, "debug")) {
                if (var->value &&
                    STRCASEEQ (var->value, "stdout"))
                    priv->debugLog = stdout;
                else
                    priv->debugLog = stderr;
            } else
                DEBUG("passing through variable '%s' ('%s') to remote end",
                      var->name, var->value);
        }
477

478 479
        /* Construct the original name. */
        if (!name) {
480 481 482
            if (conn->uri->scheme &&
                (STREQ(conn->uri->scheme, "remote") ||
                 STRPREFIX(conn->uri->scheme, "remote+"))) {
483 484 485 486 487
                /* Allow remote serve to probe */
                name = strdup("");
            } else {
                xmlURI tmpuri = {
                    .scheme = conn->uri->scheme,
488
#ifdef HAVE_XMLURI_QUERY_RAW
489
                    .query_raw = qparam_get_query (vars),
490
#else
491
                    .query = qparam_get_query (vars),
492
#endif
493 494 495 496 497 498 499 500 501
                    .path = conn->uri->path,
                    .fragment = conn->uri->fragment,
                };

                /* Evil, blank out transport scheme temporarily */
                if (transport_str) {
                    assert (transport_str[-1] == '+');
                    transport_str[-1] = '\0';
                }
502

503
                name = (char *) xmlSaveUri (&tmpuri);
504

505 506 507 508 509 510 511 512 513 514
#ifdef HAVE_XMLURI_QUERY_RAW
                VIR_FREE(tmpuri.query_raw);
#else
                VIR_FREE(tmpuri.query);
#endif

                /* Restore transport scheme */
                if (transport_str)
                    transport_str[-1] = '+';
            }
515 516
        }

517 518 519 520 521
        free_qparam_set (vars);
    } else {
        /* Probe URI server side */
        name = strdup("");
    }
522

523
    if (!name) {
524
        virReportOOMError(conn);
525
        goto failed;
526 527
    }

528
    DEBUG("proceeding with name = %s", name);
529

530 531 532 533 534 535 536
    /* For ext transport, command is required. */
    if (transport == trans_ext && !command) {
        error (conn, VIR_ERR_INVALID_ARG,
               _("remote_open: for 'ext' transport, command is required"));
        goto failed;
    }

537 538 539 540
    /* Connect to the remote service. */
    switch (transport) {
    case trans_tls:
        if (initialise_gnutls (conn) == -1) goto failed;
541
        priv->uses_tls = 1;
542 543 544 545 546 547

        /*FALLTHROUGH*/
    case trans_tcp: {
        // http://people.redhat.com/drepper/userapi-ipv6.html
        struct addrinfo *res, *r;
        struct addrinfo hints;
548
        int saved_errno = EINVAL;
549 550 551
        memset (&hints, 0, sizeof hints);
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_flags = AI_ADDRCONFIG;
552
        int e = getaddrinfo (priv->hostname, port, &hints, &res);
553
        if (e != 0) {
554 555 556
            errorf (conn, VIR_ERR_SYSTEM_ERROR,
                    _("unable to resolve hostname '%s': %s"),
                    priv->hostname, gai_strerror (e));
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
            goto failed;
        }

        /* Try to connect to each returned address in turn. */
        /* XXX This loop contains a subtle problem.  In the case
         * where a host is accessible over IPv4 and IPv6, it will
         * try the IPv4 and IPv6 addresses in turn.  However it
         * should be able to present different client certificates
         * (because the commonName field in a client cert contains
         * the client IP address, which is different for IPv4 and
         * IPv6).  At the moment we only have a single client
         * certificate, and no way to specify what address family
         * that certificate belongs to.
         */
        for (r = res; r; r = r->ai_next) {
            int no_slow_start = 1;

574 575
            priv->sock = socket (r->ai_family, SOCK_STREAM, 0);
            if (priv->sock == -1) {
J
Jim Meyering 已提交
576
                saved_errno = errno;
577 578 579 580
                continue;
            }

            /* Disable Nagle - Dan Berrange. */
581
            setsockopt (priv->sock,
582 583 584
                        IPPROTO_TCP, TCP_NODELAY, (void *)&no_slow_start,
                        sizeof no_slow_start);

585
            if (connect (priv->sock, r->ai_addr, r->ai_addrlen) == -1) {
J
Jim Meyering 已提交
586
                saved_errno = errno;
587
                close (priv->sock);
588 589 590
                continue;
            }

591 592
            if (priv->uses_tls) {
                priv->session =
593
                    negotiate_gnutls_on_connection
594
                      (conn, priv, no_verify);
595 596 597
                if (!priv->session) {
                    close (priv->sock);
                    priv->sock = -1;
598 599 600 601 602 603 604
                    continue;
                }
            }
            goto tcp_connected;
        }

        freeaddrinfo (res);
605
        virReportSystemError(conn, saved_errno,
606
                             _("unable to connect to libvirtd at '%s'"),
607
                             priv->hostname);
608 609 610 611 612 613 614 615 616 617
        goto failed;

       tcp_connected:
        freeaddrinfo (res);

        // NB. All versioning is done by the RPC headers, so we don't
        // need to worry (at this point anyway) about versioning.
        break;
    }

618
#ifndef WIN32
619 620
    case trans_unix: {
        if (!sockname) {
621
            if (flags & VIR_DRV_OPEN_REMOTE_USER) {
622
                char *userdir = virGetUserDirectory(conn, getuid());
623

624
                if (!userdir)
625
                    goto failed;
626

627 628
                if (virAsprintf(&sockname, "@%s" LIBVIRTD_USER_UNIX_SOCKET, userdir) < 0) {
                    VIR_FREE(userdir);
629
                    goto out_of_memory;
630 631
                }
                VIR_FREE(userdir);
632
            } else {
633
                if (flags & VIR_DRV_OPEN_REMOTE_RO)
634 635 636
                    sockname = strdup (LIBVIRTD_PRIV_UNIX_SOCKET_RO);
                else
                    sockname = strdup (LIBVIRTD_PRIV_UNIX_SOCKET);
637 638
                if (sockname == NULL)
                    goto out_of_memory;
639
            }
640 641 642 643 644 645
        }

#ifndef UNIX_PATH_MAX
#define UNIX_PATH_MAX(addr) (sizeof (addr).sun_path)
#endif
        struct sockaddr_un addr;
646 647
        int trials = 0;

648 649 650
        memset (&addr, 0, sizeof addr);
        addr.sun_family = AF_UNIX;
        strncpy (addr.sun_path, sockname, UNIX_PATH_MAX (addr));
651 652
        if (addr.sun_path[0] == '@')
            addr.sun_path[0] = '\0';
653

654 655 656
      autostart_retry:
        priv->sock = socket (AF_UNIX, SOCK_STREAM, 0);
        if (priv->sock == -1) {
657 658
            virReportSystemError(conn, errno, "%s",
                                 _("unable to create socket"));
659 660
            goto failed;
        }
661 662 663 664 665 666 667 668 669 670
        if (connect (priv->sock, (struct sockaddr *) &addr, sizeof addr) == -1) {
            /* We might have to autostart the daemon in some cases....
             * It takes a short while for the daemon to startup, hence we
             * have a number of retries, with a small sleep. This will
             * sometimes cause multiple daemons to be started - this is
             * ok because the duplicates will fail to bind to the socket
             * and immediately exit, leaving just one daemon.
             */
            if (errno == ECONNREFUSED &&
                flags & VIR_DRV_OPEN_REMOTE_AUTOSTART &&
671
                trials < 20) {
672 673
                close(priv->sock);
                priv->sock = -1;
674 675
                if (trials > 0 ||
                    remoteForkDaemon(conn) == 0) {
676
                    trials++;
677
                    usleep(1000 * 100 * trials);
678 679 680
                    goto autostart_retry;
                }
            }
681 682 683
            virReportSystemError(conn, errno,
                                 _("unable to connect to '%s'"),
                                 sockname);
684 685 686 687 688 689 690
            goto failed;
        }

        break;
    }

    case trans_ssh: {
691
        int j, nr_args = 6;
692 693 694

        if (username) nr_args += 2; /* For -l username */
        if (no_tty) nr_args += 5;   /* For -T -o BatchMode=yes -e none */
695
        if (port) nr_args += 2;     /* For -p port */
696

697
        command = command ? command : strdup ("ssh");
698 699
        if (command == NULL)
            goto out_of_memory;
700 701

        // Generate the final command argv[] array.
702
        //   ssh [-p $port] [-l $username] $hostname $netcat -U $sockname [NULL]
703 704
        if (VIR_ALLOC_N(cmd_argv, nr_args) < 0)
            goto out_of_memory;
J
Jim Meyering 已提交
705

706 707
        j = 0;
        cmd_argv[j++] = strdup (command);
708 709 710 711
        if (port) {
            cmd_argv[j++] = strdup ("-p");
            cmd_argv[j++] = strdup (port);
        }
712 713 714 715
        if (username) {
            cmd_argv[j++] = strdup ("-l");
            cmd_argv[j++] = strdup (username);
        }
716 717 718 719 720 721 722
        if (no_tty) {
            cmd_argv[j++] = strdup ("-T");
            cmd_argv[j++] = strdup ("-o");
            cmd_argv[j++] = strdup ("BatchMode=yes");
            cmd_argv[j++] = strdup ("-e");
            cmd_argv[j++] = strdup ("none");
        }
723
        cmd_argv[j++] = strdup (priv->hostname);
724 725
        cmd_argv[j++] = strdup (netcat ? netcat : "nc");
        cmd_argv[j++] = strdup ("-U");
726 727 728 729
        cmd_argv[j++] = strdup (sockname ? sockname :
                                (flags & VIR_CONNECT_RO
                                 ? LIBVIRTD_PRIV_UNIX_SOCKET_RO
                                 : LIBVIRTD_PRIV_UNIX_SOCKET));
730 731
        cmd_argv[j++] = 0;
        assert (j == nr_args);
732 733 734
        for (j = 0; j < (nr_args-1); j++)
            if (cmd_argv[j] == NULL)
                goto out_of_memory;
735 736 737 738
    }

        /*FALLTHROUGH*/
    case trans_ext: {
739
        pid_t pid;
740 741 742 743 744 745 746
        int sv[2];

        /* Fork off the external process.  Use socketpair to create a private
         * (unnamed) Unix domain socket to the child process so we don't have
         * to faff around with two file descriptors (a la 'pipe(2)').
         */
        if (socketpair (PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
747 748
            virReportSystemError(conn, errno, "%s",
                                 _("unable to create socket pair"));
749 750 751
            goto failed;
        }

752
        if (virExec(conn, (const char**)cmd_argv, NULL, NULL,
753 754
                    &pid, sv[1], &(sv[1]), NULL,
                    VIR_EXEC_CLEAR_CAPS) < 0)
755 756 757 758
            goto failed;

        /* Parent continues here. */
        close (sv[1]);
759
        priv->sock = sv[0];
760
        priv->pid = pid;
761
    }
762 763 764 765 766 767 768
#else /* WIN32 */

    case trans_unix:
    case trans_ssh:
    case trans_ext:
        error (conn, VIR_ERR_INVALID_ARG,
               _("transport methods unix, ssh and ext are not supported under Windows"));
769
        goto failed;
770 771 772

#endif /* WIN32 */

773 774
    } /* switch (transport) */

775
    if (virSetNonBlock(priv->sock) < 0) {
776 777
        virReportSystemError(conn, errno, "%s",
                             _("unable to make socket non-blocking"));
778 779 780 781
        goto failed;
    }

    if (pipe(wakeupFD) < 0) {
782 783
        virReportSystemError(conn, errno, "%s",
                             _("unable to make pipe"));
784 785 786 787
        goto failed;
    }
    priv->wakeupReadFD = wakeupFD[0];
    priv->wakeupSendFD = wakeupFD[1];
788 789

    /* Try and authenticate with server */
790
    if (remoteAuthenticate(conn, priv, 1, auth, authtype) == -1)
791 792
        goto failed;

793 794 795
    /* Finally we can call the remote side's open function. */
    remote_open_args args = { &name, flags };

796
    if (call (conn, priv, REMOTE_CALL_IN_OPEN, REMOTE_PROC_OPEN,
797 798 799 800
              (xdrproc_t) xdr_remote_open_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
        goto failed;

801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
    /* Now try and find out what URI the daemon used */
    if (conn->uri == NULL) {
        remote_get_uri_ret uriret;
        int urierr;

        memset (&uriret, 0, sizeof uriret);
        urierr = call (conn, priv,
                       REMOTE_CALL_IN_OPEN | REMOTE_CALL_QUIET_MISSING_RPC,
                       REMOTE_PROC_GET_URI,
                       (xdrproc_t) xdr_void, (char *) NULL,
                       (xdrproc_t) xdr_remote_get_uri_ret, (char *) &uriret);
        if (urierr == -2) {
            /* Should not really happen, since we only probe local libvirtd's,
               & the library should always match the daemon. Only case is post
               RPM upgrade where an old daemon instance is still running with
               new client. Too bad. It is not worth the hassle to fix this */
            error (conn, VIR_ERR_INTERNAL_ERROR, _("unable to auto-detect URI"));
            goto failed;
        }
        if (urierr == -1) {
            goto failed;
        }

        DEBUG("Auto-probed URI is %s", uriret.uri);
        conn->uri = xmlParseURI(uriret.uri);
        VIR_FREE(uriret.uri);
        if (!conn->uri) {
828
            virReportOOMError (conn);
829 830 831 832
            goto failed;
        }
    }

833 834 835 836 837 838 839 840 841 842 843 844
    if(VIR_ALLOC(priv->callbackList)<0) {
        error(conn, VIR_ERR_INVALID_ARG, _("Error allocating callbacks list"));
        goto failed;
    }

    if(VIR_ALLOC(priv->domainEvents)<0) {
        error(conn, VIR_ERR_INVALID_ARG, _("Error allocating domainEvents"));
        goto failed;
    }

    DEBUG0("Adding Handler for remote events");
    /* Set up a callback to listen on the socket data */
845
    if ((priv->watch = virEventAddHandle(priv->sock,
846
                                         VIR_EVENT_HANDLE_READABLE,
847
                                         remoteDomainEventFired,
848
                                         conn, NULL)) < 0) {
849 850 851 852 853 854
        DEBUG0("virEventAddHandle failed: No addHandleImpl defined."
               " continuing without events.");
    } else {

        DEBUG0("Adding Timeout for remote event queue flushing");
        if ( (priv->eventFlushTimer = virEventAddTimeout(-1,
855 856
                                                         remoteDomainEventQueueFlush,
                                                         conn, NULL)) < 0) {
857 858
            DEBUG0("virEventAddTimeout failed: No addTimeoutImpl defined. "
                    "continuing without events.");
859
            virEventRemoveHandle(priv->watch);
860
            priv->watch = -1;
861 862
        }
    }
863 864 865
    /* Successful. */
    retcode = VIR_DRV_OPEN_SUCCESS;

866
 cleanup:
867
    /* Free up the URL and strings. */
868 869 870 871 872 873 874
    VIR_FREE(name);
    VIR_FREE(command);
    VIR_FREE(sockname);
    VIR_FREE(authtype);
    VIR_FREE(netcat);
    VIR_FREE(username);
    VIR_FREE(port);
875 876 877
    if (cmd_argv) {
        char **cmd_argv_ptr = cmd_argv;
        while (*cmd_argv_ptr) {
878
            VIR_FREE(*cmd_argv_ptr);
879 880
            cmd_argv_ptr++;
        }
881
        VIR_FREE(cmd_argv);
882 883 884
    }

    return retcode;
885 886

 out_of_memory:
887
    virReportOOMError (conn);
888 889 890 891 892 893 894 895 896

 failed:
    /* Close the socket if we failed. */
    if (priv->sock >= 0) {
        if (priv->uses_tls && priv->session) {
            gnutls_bye (priv->session, GNUTLS_SHUT_RDWR);
            gnutls_deinit (priv->session);
        }
        close (priv->sock);
897
#ifndef WIN32
898 899 900 901 902 903 904 905
        if (priv->pid > 0) {
            pid_t reap;
            do {
                reap = waitpid(priv->pid, NULL, 0);
                if (reap == -1 && errno == EINTR)
                    continue;
            } while (reap != -1 && reap != priv->pid);
        }
906
#endif
907 908
    }

909 910 911 912 913
    if (wakeupFD[0] >= 0) {
        close(wakeupFD[0]);
        close(wakeupFD[1]);
    }

914
    VIR_FREE(priv->hostname);
915
    goto cleanup;
916 917
}

918 919
static struct private_data *
remoteAllocPrivateData(virConnectPtr conn)
920
{
921
    struct private_data *priv;
922
    if (VIR_ALLOC(priv) < 0) {
923 924
        virReportOOMError(conn);
        return NULL;
925 926
    }

927 928 929 930
    if (virMutexInit(&priv->lock) < 0) {
        error(conn, VIR_ERR_INTERNAL_ERROR,
              _("cannot initialize mutex"));
        VIR_FREE(priv);
931
        return NULL;
932 933 934
    }
    remoteDriverLock(priv);
    priv->localUses = 1;
935
    priv->watch = -1;
936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980
    priv->sock = -1;

    return priv;
}

static int
remoteOpenSecondaryDriver(virConnectPtr conn,
                          virConnectAuthPtr auth,
                          int flags,
                          struct private_data **priv)
{
    int ret;
    int rflags = 0;

    if (!((*priv) = remoteAllocPrivateData(conn)))
        return VIR_DRV_OPEN_ERROR;

    if (flags & VIR_CONNECT_RO)
        rflags |= VIR_DRV_OPEN_REMOTE_RO;

    ret = doRemoteOpen(conn, *priv, auth, rflags);
    if (ret != VIR_DRV_OPEN_SUCCESS) {
        remoteDriverUnlock(*priv);
        VIR_FREE(*priv);
    } else {
        (*priv)->localUses = 1;
        remoteDriverUnlock(*priv);
    }

    return ret;
}

static virDrvOpenStatus
remoteOpen (virConnectPtr conn,
            virConnectAuthPtr auth,
            int flags)
{
    struct private_data *priv;
    int ret, rflags = 0;

    if (inside_daemon)
        return VIR_DRV_OPEN_DECLINED;

    if (!(priv = remoteAllocPrivateData(conn)))
        return VIR_DRV_OPEN_ERROR;
981

982
    if (flags & VIR_CONNECT_RO)
983 984
        rflags |= VIR_DRV_OPEN_REMOTE_RO;

985 986 987 988 989 990 991 992 993
    /*
     * If no servername is given, and no +XXX
     * transport is listed, or transport is unix,
     * and path is /session, and uid is unprivileged
     * then auto-spawn a daemon.
     */
    if (conn->uri &&
        !conn->uri->server &&
        conn->uri->path &&
D
Daniel P. Berrange 已提交
994
        conn->uri->scheme &&
995 996
        ((strchr(conn->uri->scheme, '+') == 0)||
         (strstr(conn->uri->scheme, "+unix") != NULL)) &&
997 998
        (STREQ(conn->uri->path, "/session") ||
         STRPREFIX(conn->uri->scheme, "test+")) &&
999 1000 1001 1002 1003 1004 1005
        getuid() > 0) {
        DEBUG0("Auto-spawn user daemon instance");
        rflags |= VIR_DRV_OPEN_REMOTE_USER;
        rflags |= VIR_DRV_OPEN_REMOTE_AUTOSTART;
    }

    /*
J
John Levon 已提交
1006 1007 1008 1009
     * If URI is NULL, then do a UNIX connection possibly auto-spawning
     * unprivileged server and probe remote server for URI. On Solaris,
     * this isn't supported, but we may be privileged enough to connect
     * to the UNIX socket anyway.
1010 1011 1012
     */
    if (!conn->uri) {
        DEBUG0("Auto-probe remote URI");
J
John Levon 已提交
1013
#ifndef __sun
1014 1015 1016 1017 1018
        if (getuid() > 0) {
            DEBUG0("Auto-spawn user daemon instance");
            rflags |= VIR_DRV_OPEN_REMOTE_USER;
            rflags |= VIR_DRV_OPEN_REMOTE_AUTOSTART;
        }
J
John Levon 已提交
1019
#endif
1020
    }
1021

1022
    ret = doRemoteOpen(conn, priv, auth, rflags);
1023 1024
    if (ret != VIR_DRV_OPEN_SUCCESS) {
        conn->privateData = NULL;
1025
        remoteDriverUnlock(priv);
1026
        VIR_FREE(priv);
1027 1028
    } else {
        conn->privateData = priv;
1029
        remoteDriverUnlock(priv);
1030 1031 1032 1033 1034
    }
    return ret;
}


1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
/* In a string "driver+transport" return a pointer to "transport". */
static char *
get_transport_from_scheme (char *scheme)
{
    char *p = strchr (scheme, '+');
    return p ? p+1 : 0;
}

/* GnuTLS functions used by remoteOpen. */
static gnutls_certificate_credentials_t x509_cred;

1046 1047

static int
1048
check_cert_file (virConnectPtr conn, const char *type, const char *file)
1049 1050 1051
{
    struct stat sb;
    if (stat(file, &sb) < 0) {
1052 1053 1054
        virReportSystemError(conn, errno,
                             _("Cannot access %s '%s'"),
                             type, file);
1055 1056 1057 1058 1059 1060
        return -1;
    }
    return 0;
}


1061
static int
1062
initialise_gnutls (virConnectPtr conn)
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
{
    static int initialised = 0;
    int err;

    if (initialised) return 0;

    gnutls_global_init ();

    /* X509 stuff */
    err = gnutls_certificate_allocate_credentials (&x509_cred);
    if (err) {
1074 1075 1076
        errorf (conn, VIR_ERR_GNUTLS_ERROR,
                _("unable to allocate TLS credentials: %s"),
                gnutls_strerror (err));
1077 1078 1079
        return -1;
    }

1080

1081
    if (check_cert_file(conn, "CA certificate", LIBVIRT_CACERT) < 0)
1082
        return -1;
1083
    if (check_cert_file(conn, "client key", LIBVIRT_CLIENTKEY) < 0)
1084
        return -1;
1085
    if (check_cert_file(conn, "client certificate", LIBVIRT_CLIENTCERT) < 0)
1086 1087
        return -1;

1088
    /* Set the trusted CA cert. */
1089
    DEBUG("loading CA file %s", LIBVIRT_CACERT);
1090 1091 1092 1093
    err =
        gnutls_certificate_set_x509_trust_file (x509_cred, LIBVIRT_CACERT,
                                                GNUTLS_X509_FMT_PEM);
    if (err < 0) {
1094 1095 1096
        errorf (conn, VIR_ERR_GNUTLS_ERROR,
                _("unable to load CA certificate: %s"),
                gnutls_strerror (err));
1097 1098 1099 1100
        return -1;
    }

    /* Set the client certificate and private key. */
1101 1102
    DEBUG("loading client cert and key from files %s and %s",
          LIBVIRT_CLIENTCERT, LIBVIRT_CLIENTKEY);
1103 1104 1105 1106 1107 1108
    err =
        gnutls_certificate_set_x509_key_file (x509_cred,
                                              LIBVIRT_CLIENTCERT,
                                              LIBVIRT_CLIENTKEY,
                                              GNUTLS_X509_FMT_PEM);
    if (err < 0) {
1109 1110 1111
        errorf (conn, VIR_ERR_GNUTLS_ERROR,
                _("unable to load private key/certificate: %s"),
                gnutls_strerror (err));
1112 1113 1114 1115 1116 1117 1118
        return -1;
    }

    initialised = 1;
    return 0;
}

1119
static int verify_certificate (virConnectPtr conn, struct private_data *priv, gnutls_session_t session);
1120 1121 1122

static gnutls_session_t
negotiate_gnutls_on_connection (virConnectPtr conn,
1123 1124
                                struct private_data *priv,
                                int no_verify)
1125 1126 1127 1128 1129 1130 1131 1132 1133
{
    const int cert_type_priority[3] = {
        GNUTLS_CRT_X509,
        GNUTLS_CRT_OPENPGP,
        0
    };
    int err;
    gnutls_session_t session;

1134
    /* Initialize TLS session
1135 1136 1137
     */
    err = gnutls_init (&session, GNUTLS_CLIENT);
    if (err) {
1138 1139 1140
        errorf (conn, VIR_ERR_GNUTLS_ERROR,
                _("unable to initialize TLS client: %s"),
                gnutls_strerror (err));
1141 1142 1143 1144 1145 1146
        return NULL;
    }

    /* Use default priorities */
    err = gnutls_set_default_priority (session);
    if (err) {
1147 1148 1149
        errorf (conn, VIR_ERR_GNUTLS_ERROR,
                _("unable to set TLS algorithm priority: %s"),
                gnutls_strerror (err));
1150 1151 1152 1153 1154 1155
        return NULL;
    }
    err =
        gnutls_certificate_type_set_priority (session,
                                              cert_type_priority);
    if (err) {
1156 1157 1158
        errorf (conn, VIR_ERR_GNUTLS_ERROR,
                _("unable to set certificate priority: %s"),
                gnutls_strerror (err));
1159 1160 1161 1162 1163 1164 1165
        return NULL;
    }

    /* put the x509 credentials to the current session
     */
    err = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
    if (err) {
1166 1167 1168
        errorf (conn, VIR_ERR_GNUTLS_ERROR,
                _("unable to set session credentials: %s"),
                gnutls_strerror (err));
1169 1170 1171 1172
        return NULL;
    }

    gnutls_transport_set_ptr (session,
1173
                              (gnutls_transport_ptr_t) (long) priv->sock);
1174 1175 1176 1177 1178 1179 1180

    /* Perform the TLS handshake. */
 again:
    err = gnutls_handshake (session);
    if (err < 0) {
        if (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED)
            goto again;
1181 1182 1183
        errorf (conn, VIR_ERR_GNUTLS_ERROR,
                _("unable to complete TLS handshake: %s"),
                gnutls_strerror (err));
1184 1185 1186 1187
        return NULL;
    }

    /* Verify certificate. */
1188
    if (verify_certificate (conn, priv, session) == -1) {
1189 1190 1191
        DEBUG0("failed to verify peer's certificate");
        if (!no_verify) return NULL;
    }
1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202

    /* At this point, the server is verifying _our_ certificate, IP address,
     * etc.  If we make the grade, it will send us a '\1' byte.
     */
    char buf[1];
    int len;
 again_2:
    len = gnutls_record_recv (session, buf, 1);
    if (len < 0 && len != GNUTLS_E_UNEXPECTED_PACKET_LENGTH) {
        if (len == GNUTLS_E_AGAIN || len == GNUTLS_E_INTERRUPTED)
            goto again_2;
1203 1204 1205
        errorf (conn, VIR_ERR_GNUTLS_ERROR,
                _("unable to complete TLS initialization: %s"),
                gnutls_strerror (len));
1206 1207 1208
        return NULL;
    }
    if (len != 1 || buf[0] != '\1') {
1209
        error (conn, VIR_ERR_RPC,
1210
               _("server verification (of our certificate or IP address) failed\n"));
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
        return NULL;
    }

#if 0
    /* Print session info. */
    print_info (session);
#endif

    return session;
}

static int
verify_certificate (virConnectPtr conn ATTRIBUTE_UNUSED,
1224 1225
                    struct private_data *priv,
                    gnutls_session_t session)
1226 1227 1228 1229 1230 1231 1232 1233
{
    int ret;
    unsigned int status;
    const gnutls_datum_t *certs;
    unsigned int nCerts, i;
    time_t now;

    if ((ret = gnutls_certificate_verify_peers2 (session, &status)) < 0) {
1234 1235 1236
        errorf (conn, VIR_ERR_GNUTLS_ERROR,
                _("unable to verify server certificate: %s"),
                gnutls_strerror (ret));
1237 1238
        return -1;
    }
1239

1240
    if ((now = time(NULL)) == ((time_t)-1)) {
1241 1242
        virReportSystemError(conn, errno, "%s",
                             _("cannot get current time"));
1243 1244 1245 1246
        return -1;
    }

    if (status != 0) {
1247
        const char *reason = _("Invalid certificate");
1248 1249

        if (status & GNUTLS_CERT_INVALID)
1250
            reason = _("The certificate is not trusted.");
1251

1252
        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
1253
            reason = _("The certificate hasn't got a known issuer.");
1254

1255
        if (status & GNUTLS_CERT_REVOKED)
1256
            reason = _("The certificate has been revoked.");
1257 1258

#ifndef GNUTLS_1_0_COMPAT
1259
        if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
1260
            reason = _("The certificate uses an insecure algorithm");
1261
#endif
1262

1263 1264 1265
        errorf (conn, VIR_ERR_RPC,
                _("server certificate failed validation: %s"),
                reason);
1266 1267 1268 1269
        return -1;
    }

    if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) {
1270
        error (conn, VIR_ERR_RPC, _("Certificate type is not X.509"));
1271 1272
        return -1;
    }
1273

1274
    if (!(certs = gnutls_certificate_get_peers(session, &nCerts))) {
1275
        error (conn, VIR_ERR_RPC, _("gnutls_certificate_get_peers failed"));
1276 1277
        return -1;
    }
1278

1279 1280 1281 1282 1283
    for (i = 0 ; i < nCerts ; i++) {
        gnutls_x509_crt_t cert;

        ret = gnutls_x509_crt_init (&cert);
        if (ret < 0) {
1284 1285 1286
            errorf (conn, VIR_ERR_GNUTLS_ERROR,
                    _("unable to initialize certificate: %s"),
                    gnutls_strerror (ret));
1287 1288
            return -1;
        }
1289

1290 1291
        ret = gnutls_x509_crt_import (cert, &certs[i], GNUTLS_X509_FMT_DER);
        if (ret < 0) {
1292 1293 1294
            errorf (conn, VIR_ERR_GNUTLS_ERROR,
                    _("unable to import certificate: %s"),
                    gnutls_strerror (ret));
1295 1296 1297
            gnutls_x509_crt_deinit (cert);
            return -1;
        }
1298

1299
        if (gnutls_x509_crt_get_expiration_time (cert) < now) {
1300
            error (conn, VIR_ERR_RPC, _("The certificate has expired"));
1301 1302 1303
            gnutls_x509_crt_deinit (cert);
            return -1;
        }
1304

1305
        if (gnutls_x509_crt_get_activation_time (cert) > now) {
1306
            error (conn, VIR_ERR_RPC, _("The certificate is not yet activated"));
1307 1308 1309
            gnutls_x509_crt_deinit (cert);
            return -1;
        }
1310

1311
        if (i == 0) {
1312
            if (!gnutls_x509_crt_check_hostname (cert, priv->hostname)) {
1313 1314 1315
                errorf(conn, VIR_ERR_RPC,
                       _("Certificate's owner does not match the hostname (%s)"),
                       priv->hostname);
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326
                gnutls_x509_crt_deinit (cert);
                return -1;
            }
        }
    }

    return 0;
}

/*----------------------------------------------------------------------*/

1327

1328
static int
1329
doRemoteClose (virConnectPtr conn, struct private_data *priv)
1330 1331 1332 1333 1334 1335
{
    if (call (conn, priv, 0, REMOTE_PROC_CLOSE,
              (xdrproc_t) xdr_void, (char *) NULL,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
        return -1;

1336 1337 1338 1339 1340
    if (priv->eventFlushTimer >= 0) {
        /* Remove timeout */
        virEventRemoveTimeout(priv->eventFlushTimer);
        /* Remove handle for remote events */
        virEventRemoveHandle(priv->watch);
1341
        priv->watch = -1;
1342
    }
1343

1344
    /* Close socket. */
1345
    if (priv->uses_tls && priv->session) {
1346
        gnutls_bye (priv->session, GNUTLS_SHUT_RDWR);
1347 1348 1349 1350 1351 1352
        gnutls_deinit (priv->session);
    }
#if HAVE_SASL
    if (priv->saslconn)
        sasl_dispose (&priv->saslconn);
#endif
1353 1354
    close (priv->sock);

1355
#ifndef WIN32
1356 1357 1358 1359 1360 1361 1362 1363
    if (priv->pid > 0) {
        pid_t reap;
        do {
            reap = waitpid(priv->pid, NULL, 0);
            if (reap == -1 && errno == EINTR)
                continue;
        } while (reap != -1 && reap != priv->pid);
    }
1364
#endif
1365 1366 1367 1368 1369
    if (priv->wakeupReadFD >= 0) {
        close(priv->wakeupReadFD);
        close(priv->wakeupSendFD);
    }

1370

1371
    /* Free hostname copy */
1372
    free (priv->hostname);
1373

1374
    /* See comment for remoteType. */
1375
    free (priv->type);
1376

1377 1378 1379 1380 1381 1382
    /* Free callback list */
    virDomainEventCallbackListFree(priv->callbackList);

    /* Free queued events */
    virDomainEventQueueFree(priv->domainEvents);

1383 1384 1385
    return 0;
}

1386 1387 1388
static int
remoteClose (virConnectPtr conn)
{
1389
    int ret = 0;
1390
    struct private_data *priv = conn->privateData;
1391

1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402
    remoteDriverLock(priv);
    priv->localUses--;
    if (!priv->localUses) {
        ret = doRemoteClose(conn, priv);
        conn->privateData = NULL;
        remoteDriverUnlock(priv);
        virMutexDestroy(&priv->lock);
        VIR_FREE (priv);
    }
    if (priv)
        remoteDriverUnlock(priv);
1403 1404 1405 1406

    return ret;
}

1407 1408 1409
static int
remoteSupportsFeature (virConnectPtr conn, int feature)
{
1410
    int rv = -1;
1411 1412
    remote_supports_feature_args args;
    remote_supports_feature_ret ret;
1413
    struct private_data *priv = conn->privateData;
1414

1415 1416
    remoteDriverLock(priv);

1417
    /* VIR_DRV_FEATURE_REMOTE* features are handled directly. */
1418 1419 1420 1421
    if (feature == VIR_DRV_FEATURE_REMOTE) {
        rv = 1;
        goto done;
    }
1422 1423 1424 1425 1426 1427 1428

    args.feature = feature;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_SUPPORTS_FEATURE,
              (xdrproc_t) xdr_remote_supports_feature_args, (char *) &args,
              (xdrproc_t) xdr_remote_supports_feature_ret, (char *) &ret) == -1)
1429 1430 1431
        goto done;

    rv = ret.supported;
1432

1433
done:
1434
    remoteDriverUnlock(priv);
1435
    return rv;
1436 1437
}

1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448
/* Unfortunately this function is defined to return a static string.
 * Since the remote end always answers with the same type (for a
 * single connection anyway) we cache the type in the connection's
 * private data, and free it when we close the connection.
 *
 * See also:
 * http://www.redhat.com/archives/libvir-list/2007-February/msg00096.html
 */
static const char *
remoteType (virConnectPtr conn)
{
1449
    char *rv = NULL;
1450
    remote_get_type_ret ret;
1451
    struct private_data *priv = conn->privateData;
1452

1453 1454
    remoteDriverLock(priv);

1455
    /* Cached? */
1456 1457 1458 1459
    if (priv->type) {
        rv = priv->type;
        goto done;
    }
1460 1461 1462 1463 1464

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_GET_TYPE,
              (xdrproc_t) xdr_void, (char *) NULL,
              (xdrproc_t) xdr_remote_get_type_ret, (char *) &ret) == -1)
1465
        goto done;
1466 1467

    /* Stash. */
1468 1469 1470
    rv = priv->type = ret.type;

done:
1471
    remoteDriverUnlock(priv);
1472
    return rv;
1473 1474 1475
}

static int
1476
remoteGetVersion (virConnectPtr conn, unsigned long *hvVer)
1477
{
1478
    int rv = -1;
1479
    remote_get_version_ret ret;
1480
    struct private_data *priv = conn->privateData;
1481

1482 1483
    remoteDriverLock(priv);

1484 1485 1486 1487
    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_GET_VERSION,
              (xdrproc_t) xdr_void, (char *) NULL,
              (xdrproc_t) xdr_remote_get_version_ret, (char *) &ret) == -1)
1488
        goto done;
1489 1490

    if (hvVer) *hvVer = ret.hv_ver;
1491 1492 1493
    rv = 0;

done:
1494
    remoteDriverUnlock(priv);
1495
    return rv;
1496 1497
}

1498 1499 1500
static char *
remoteGetHostname (virConnectPtr conn)
{
1501
    char *rv = NULL;
1502
    remote_get_hostname_ret ret;
1503
    struct private_data *priv = conn->privateData;
1504

1505 1506
    remoteDriverLock(priv);

1507 1508 1509 1510
    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_GET_HOSTNAME,
              (xdrproc_t) xdr_void, (char *) NULL,
              (xdrproc_t) xdr_remote_get_hostname_ret, (char *) &ret) == -1)
1511
        goto done;
1512 1513

    /* Caller frees this. */
1514 1515 1516
    rv = ret.hostname;

done:
1517
    remoteDriverUnlock(priv);
1518
    return rv;
1519 1520
}

1521 1522 1523
static int
remoteGetMaxVcpus (virConnectPtr conn, const char *type)
{
1524
    int rv = -1;
1525 1526
    remote_get_max_vcpus_args args;
    remote_get_max_vcpus_ret ret;
1527
    struct private_data *priv = conn->privateData;
1528

1529 1530
    remoteDriverLock(priv);

1531
    memset (&ret, 0, sizeof ret);
1532
    args.type = type == NULL ? NULL : (char **) &type;
1533 1534 1535
    if (call (conn, priv, 0, REMOTE_PROC_GET_MAX_VCPUS,
              (xdrproc_t) xdr_remote_get_max_vcpus_args, (char *) &args,
              (xdrproc_t) xdr_remote_get_max_vcpus_ret, (char *) &ret) == -1)
1536 1537 1538
        goto done;

    rv = ret.max_vcpus;
1539

1540
done:
1541
    remoteDriverUnlock(priv);
1542
    return rv;
1543 1544 1545 1546 1547
}

static int
remoteNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info)
{
1548
    int rv = -1;
1549
    remote_node_get_info_ret ret;
1550
    struct private_data *priv = conn->privateData;
1551

1552 1553
    remoteDriverLock(priv);

1554 1555 1556 1557
    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NODE_GET_INFO,
              (xdrproc_t) xdr_void, (char *) NULL,
              (xdrproc_t) xdr_remote_node_get_info_ret, (char *) &ret) == -1)
1558
        goto done;
1559 1560 1561 1562 1563 1564 1565 1566 1567 1568

    strncpy (info->model, ret.model, 32);
    info->model[31] = '\0';
    info->memory = ret.memory;
    info->cpus = ret.cpus;
    info->mhz = ret.mhz;
    info->nodes = ret.nodes;
    info->sockets = ret.sockets;
    info->cores = ret.cores;
    info->threads = ret.threads;
1569 1570 1571
    rv = 0;

done:
1572
    remoteDriverUnlock(priv);
1573
    return rv;
1574 1575 1576 1577 1578
}

static char *
remoteGetCapabilities (virConnectPtr conn)
{
1579
    char *rv = NULL;
1580
    remote_get_capabilities_ret ret;
1581
    struct private_data *priv = conn->privateData;
1582

1583 1584
    remoteDriverLock(priv);

1585 1586 1587 1588
    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_GET_CAPABILITIES,
              (xdrproc_t) xdr_void, (char *) NULL,
              (xdrproc_t) xdr_remote_get_capabilities_ret, (char *)&ret) == -1)
1589
        goto done;
1590 1591

    /* Caller frees this. */
1592 1593 1594
    rv = ret.capabilities;

done:
1595
    remoteDriverUnlock(priv);
1596
    return rv;
1597 1598
}

1599 1600 1601 1602 1603 1604
static int
remoteNodeGetCellsFreeMemory(virConnectPtr conn,
                            unsigned long long *freeMems,
                            int startCell,
                            int maxCells)
{
1605
    int rv = -1;
1606 1607 1608
    remote_node_get_cells_free_memory_args args;
    remote_node_get_cells_free_memory_ret ret;
    int i;
1609
    struct private_data *priv = conn->privateData;
1610

1611 1612
    remoteDriverLock(priv);

1613 1614 1615 1616 1617
    if (maxCells > REMOTE_NODE_MAX_CELLS) {
        errorf (conn, VIR_ERR_RPC,
                _("too many NUMA cells: %d > %d"),
                maxCells,
                REMOTE_NODE_MAX_CELLS);
1618
        goto done;
1619 1620 1621 1622 1623 1624 1625 1626 1627
    }

    args.startCell = startCell;
    args.maxCells = maxCells;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY,
              (xdrproc_t) xdr_remote_node_get_cells_free_memory_args, (char *)&args,
              (xdrproc_t) xdr_remote_node_get_cells_free_memory_ret, (char *)&ret) == -1)
1628
        goto done;
1629 1630 1631 1632 1633 1634

    for (i = 0 ; i < ret.freeMems.freeMems_len ; i++)
        freeMems[i] = ret.freeMems.freeMems_val[i];

    xdr_free((xdrproc_t) xdr_remote_node_get_cells_free_memory_ret, (char *) &ret);

1635 1636 1637
    rv = ret.freeMems.freeMems_len;

done:
1638
    remoteDriverUnlock(priv);
1639
    return rv;
1640 1641 1642 1643 1644
}

static unsigned long long
remoteNodeGetFreeMemory (virConnectPtr conn)
{
1645
    unsigned long long rv = 0; /* 0 is error value this special function*/
1646
    remote_node_get_free_memory_ret ret;
1647
    struct private_data *priv = conn->privateData;
1648

1649 1650
    remoteDriverLock(priv);

1651 1652 1653 1654
    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NODE_GET_FREE_MEMORY,
              (xdrproc_t) xdr_void, NULL,
              (xdrproc_t) xdr_remote_node_get_free_memory_ret, (char *)&ret) == -1)
1655 1656 1657
        goto done;

    rv = ret.freeMem;
1658

1659
done:
1660
    remoteDriverUnlock(priv);
1661
    return rv;
1662 1663 1664
}


1665 1666 1667
static int
remoteListDomains (virConnectPtr conn, int *ids, int maxids)
{
1668
    int rv = -1;
1669 1670 1671
    int i;
    remote_list_domains_args args;
    remote_list_domains_ret ret;
1672
    struct private_data *priv = conn->privateData;
1673

1674 1675
    remoteDriverLock(priv);

1676
    if (maxids > REMOTE_DOMAIN_ID_LIST_MAX) {
1677 1678 1679
        errorf (conn, VIR_ERR_RPC,
                _("too many remote domain IDs: %d > %d"),
                maxids, REMOTE_DOMAIN_ID_LIST_MAX);
1680
        goto done;
1681 1682 1683 1684 1685 1686 1687
    }
    args.maxids = maxids;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_LIST_DOMAINS,
              (xdrproc_t) xdr_remote_list_domains_args, (char *) &args,
              (xdrproc_t) xdr_remote_list_domains_ret, (char *) &ret) == -1)
1688
        goto done;
1689 1690

    if (ret.ids.ids_len > maxids) {
1691 1692 1693
        errorf (conn, VIR_ERR_RPC,
                _("too many remote domain IDs: %d > %d"),
                ret.ids.ids_len, maxids);
1694
        goto cleanup;
1695 1696 1697 1698 1699
    }

    for (i = 0; i < ret.ids.ids_len; ++i)
        ids[i] = ret.ids.ids_val[i];

1700 1701 1702
    rv = ret.ids.ids_len;

cleanup:
1703 1704
    xdr_free ((xdrproc_t) xdr_remote_list_domains_ret, (char *) &ret);

1705
done:
1706
    remoteDriverUnlock(priv);
1707
    return rv;
1708 1709 1710 1711 1712
}

static int
remoteNumOfDomains (virConnectPtr conn)
{
1713
    int rv = -1;
1714
    remote_num_of_domains_ret ret;
1715
    struct private_data *priv = conn->privateData;
1716

1717 1718
    remoteDriverLock(priv);

1719 1720 1721 1722
    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NUM_OF_DOMAINS,
              (xdrproc_t) xdr_void, (char *) NULL,
              (xdrproc_t) xdr_remote_num_of_domains_ret, (char *) &ret) == -1)
1723 1724 1725
        goto done;

    rv = ret.num;
1726

1727
done:
1728
    remoteDriverUnlock(priv);
1729
    return rv;
1730 1731 1732
}

static virDomainPtr
1733
remoteDomainCreateXML (virConnectPtr conn,
1734 1735 1736
                         const char *xmlDesc,
                         unsigned int flags)
{
1737
    virDomainPtr dom = NULL;
1738 1739
    remote_domain_create_xml_args args;
    remote_domain_create_xml_ret ret;
1740
    struct private_data *priv = conn->privateData;
1741

1742 1743
    remoteDriverLock(priv);

1744 1745 1746 1747
    args.xml_desc = (char *) xmlDesc;
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
1748 1749 1750
    if (call (conn, priv, 0, REMOTE_PROC_DOMAIN_CREATE_XML,
              (xdrproc_t) xdr_remote_domain_create_xml_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_create_xml_ret, (char *) &ret) == -1)
1751
        goto done;
1752 1753

    dom = get_nonnull_domain (conn, ret.dom);
1754
    xdr_free ((xdrproc_t) &xdr_remote_domain_create_xml_ret, (char *) &ret);
1755

1756
done:
1757
    remoteDriverUnlock(priv);
1758 1759 1760 1761 1762 1763
    return dom;
}

static virDomainPtr
remoteDomainLookupByID (virConnectPtr conn, int id)
{
1764
    virDomainPtr dom = NULL;
1765 1766
    remote_domain_lookup_by_id_args args;
    remote_domain_lookup_by_id_ret ret;
1767
    struct private_data *priv = conn->privateData;
1768

1769 1770
    remoteDriverLock(priv);

1771 1772 1773 1774 1775 1776
    args.id = id;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_DOMAIN_LOOKUP_BY_ID,
              (xdrproc_t) xdr_remote_domain_lookup_by_id_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_lookup_by_id_ret, (char *) &ret) == -1)
1777
        goto done;
1778 1779 1780 1781

    dom = get_nonnull_domain (conn, ret.dom);
    xdr_free ((xdrproc_t) &xdr_remote_domain_lookup_by_id_ret, (char *) &ret);

1782
done:
1783
    remoteDriverUnlock(priv);
1784 1785 1786 1787 1788 1789
    return dom;
}

static virDomainPtr
remoteDomainLookupByUUID (virConnectPtr conn, const unsigned char *uuid)
{
1790
    virDomainPtr dom = NULL;
1791 1792
    remote_domain_lookup_by_uuid_args args;
    remote_domain_lookup_by_uuid_ret ret;
1793
    struct private_data *priv = conn->privateData;
1794

1795 1796
    remoteDriverLock(priv);

1797 1798 1799 1800 1801 1802
    memcpy (args.uuid, uuid, VIR_UUID_BUFLEN);

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_DOMAIN_LOOKUP_BY_UUID,
              (xdrproc_t) xdr_remote_domain_lookup_by_uuid_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_lookup_by_uuid_ret, (char *) &ret) == -1)
1803
        goto done;
1804 1805 1806

    dom = get_nonnull_domain (conn, ret.dom);
    xdr_free ((xdrproc_t) &xdr_remote_domain_lookup_by_uuid_ret, (char *) &ret);
1807 1808

done:
1809
    remoteDriverUnlock(priv);
1810 1811 1812 1813 1814 1815
    return dom;
}

static virDomainPtr
remoteDomainLookupByName (virConnectPtr conn, const char *name)
{
1816
    virDomainPtr dom = NULL;
1817 1818
    remote_domain_lookup_by_name_args args;
    remote_domain_lookup_by_name_ret ret;
1819
    struct private_data *priv = conn->privateData;
1820

1821 1822
    remoteDriverLock(priv);

1823 1824 1825 1826 1827 1828
    args.name = (char *) name;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_DOMAIN_LOOKUP_BY_NAME,
              (xdrproc_t) xdr_remote_domain_lookup_by_name_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_lookup_by_name_ret, (char *) &ret) == -1)
1829
        goto done;
1830 1831 1832 1833

    dom = get_nonnull_domain (conn, ret.dom);
    xdr_free ((xdrproc_t) &xdr_remote_domain_lookup_by_name_ret, (char *) &ret);

1834
done:
1835
    remoteDriverUnlock(priv);
1836 1837 1838 1839 1840 1841
    return dom;
}

static int
remoteDomainSuspend (virDomainPtr domain)
{
1842
    int rv = -1;
1843
    remote_domain_suspend_args args;
1844
    struct private_data *priv = domain->conn->privateData;
1845

1846 1847
    remoteDriverLock(priv);

1848 1849 1850 1851 1852
    make_nonnull_domain (&args.dom, domain);

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SUSPEND,
              (xdrproc_t) xdr_remote_domain_suspend_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
1853
        goto done;
1854

1855 1856 1857
    rv = 0;

done:
1858
    remoteDriverUnlock(priv);
1859
    return rv;
1860 1861 1862 1863 1864
}

static int
remoteDomainResume (virDomainPtr domain)
{
1865
    int rv = -1;
1866
    remote_domain_resume_args args;
1867
    struct private_data *priv = domain->conn->privateData;
1868

1869 1870
    remoteDriverLock(priv);

1871 1872 1873 1874 1875
    make_nonnull_domain (&args.dom, domain);

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_RESUME,
              (xdrproc_t) xdr_remote_domain_resume_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
1876
        goto done;
1877

1878 1879 1880
    rv = 0;

done:
1881
    remoteDriverUnlock(priv);
1882
    return rv;
1883 1884 1885 1886 1887
}

static int
remoteDomainShutdown (virDomainPtr domain)
{
1888
    int rv = -1;
1889
    remote_domain_shutdown_args args;
1890
    struct private_data *priv = domain->conn->privateData;
1891

1892 1893
    remoteDriverLock(priv);

1894 1895 1896 1897 1898
    make_nonnull_domain (&args.dom, domain);

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SHUTDOWN,
              (xdrproc_t) xdr_remote_domain_shutdown_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
1899
        goto done;
1900

1901 1902 1903
    rv = 0;

done:
1904
    remoteDriverUnlock(priv);
1905
    return rv;
1906 1907 1908 1909 1910
}

static int
remoteDomainReboot (virDomainPtr domain, unsigned int flags)
{
1911
    int rv = -1;
1912
    remote_domain_reboot_args args;
1913
    struct private_data *priv = domain->conn->privateData;
1914

1915 1916
    remoteDriverLock(priv);

1917 1918 1919 1920 1921 1922
    make_nonnull_domain (&args.dom, domain);
    args.flags = flags;

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_REBOOT,
              (xdrproc_t) xdr_remote_domain_reboot_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
1923
        goto done;
1924

1925 1926 1927
    rv = 0;

done:
1928
    remoteDriverUnlock(priv);
1929
    return rv;
1930 1931 1932 1933 1934
}

static int
remoteDomainDestroy (virDomainPtr domain)
{
1935
    int rv = -1;
1936
    remote_domain_destroy_args args;
1937
    struct private_data *priv = domain->conn->privateData;
1938

1939 1940
    remoteDriverLock(priv);

1941 1942 1943 1944 1945
    make_nonnull_domain (&args.dom, domain);

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_DESTROY,
              (xdrproc_t) xdr_remote_domain_destroy_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
1946
        goto done;
1947

1948
    rv = 0;
1949
    domain->id = -1;
1950 1951

done:
1952
    remoteDriverUnlock(priv);
1953
    return rv;
1954 1955 1956 1957 1958
}

static char *
remoteDomainGetOSType (virDomainPtr domain)
{
1959
    char *rv = NULL;
1960 1961
    remote_domain_get_os_type_args args;
    remote_domain_get_os_type_ret ret;
1962
    struct private_data *priv = domain->conn->privateData;
1963

1964 1965
    remoteDriverLock(priv);

1966 1967 1968 1969 1970 1971
    make_nonnull_domain (&args.dom, domain);

    memset (&ret, 0, sizeof ret);
    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_OS_TYPE,
              (xdrproc_t) xdr_remote_domain_get_os_type_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_get_os_type_ret, (char *) &ret) == -1)
1972
        goto done;
1973 1974

    /* Caller frees. */
1975 1976 1977
    rv = ret.type;

done:
1978
    remoteDriverUnlock(priv);
1979
    return rv;
1980 1981 1982 1983 1984
}

static unsigned long
remoteDomainGetMaxMemory (virDomainPtr domain)
{
1985
    unsigned long rv = 0;
1986 1987
    remote_domain_get_max_memory_args args;
    remote_domain_get_max_memory_ret ret;
1988
    struct private_data *priv = domain->conn->privateData;
1989

1990 1991
    remoteDriverLock(priv);

1992 1993 1994 1995 1996 1997
    make_nonnull_domain (&args.dom, domain);

    memset (&ret, 0, sizeof ret);
    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_MAX_MEMORY,
              (xdrproc_t) xdr_remote_domain_get_max_memory_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_get_max_memory_ret, (char *) &ret) == -1)
1998 1999 2000
        goto done;

    rv = ret.memory;
2001

2002
done:
2003
    remoteDriverUnlock(priv);
2004
    return rv;
2005 2006 2007 2008 2009
}

static int
remoteDomainSetMaxMemory (virDomainPtr domain, unsigned long memory)
{
2010
    int rv = -1;
2011
    remote_domain_set_max_memory_args args;
2012
    struct private_data *priv = domain->conn->privateData;
2013

2014 2015
    remoteDriverLock(priv);

2016 2017 2018 2019 2020 2021
    make_nonnull_domain (&args.dom, domain);
    args.memory = memory;

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SET_MAX_MEMORY,
              (xdrproc_t) xdr_remote_domain_set_max_memory_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
2022
        goto done;
2023

2024 2025 2026
    rv = 0;

done:
2027
    remoteDriverUnlock(priv);
2028
    return rv;
2029 2030 2031 2032 2033
}

static int
remoteDomainSetMemory (virDomainPtr domain, unsigned long memory)
{
2034
    int rv = -1;
2035
    remote_domain_set_memory_args args;
2036
    struct private_data *priv = domain->conn->privateData;
2037

2038 2039
    remoteDriverLock(priv);

2040 2041 2042 2043 2044 2045
    make_nonnull_domain (&args.dom, domain);
    args.memory = memory;

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SET_MEMORY,
              (xdrproc_t) xdr_remote_domain_set_memory_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
2046
        goto done;
2047

2048 2049 2050
    rv = 0;

done:
2051
    remoteDriverUnlock(priv);
2052
    return rv;
2053 2054 2055 2056 2057
}

static int
remoteDomainGetInfo (virDomainPtr domain, virDomainInfoPtr info)
{
2058
    int rv = -1;
2059 2060
    remote_domain_get_info_args args;
    remote_domain_get_info_ret ret;
2061
    struct private_data *priv = domain->conn->privateData;
2062

2063 2064
    remoteDriverLock(priv);

2065 2066 2067 2068 2069 2070
    make_nonnull_domain (&args.dom, domain);

    memset (&ret, 0, sizeof ret);
    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_INFO,
              (xdrproc_t) xdr_remote_domain_get_info_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_get_info_ret, (char *) &ret) == -1)
2071
        goto done;
2072 2073 2074 2075 2076 2077

    info->state = ret.state;
    info->maxMem = ret.max_mem;
    info->memory = ret.memory;
    info->nrVirtCpu = ret.nr_virt_cpu;
    info->cpuTime = ret.cpu_time;
2078

2079 2080 2081
    rv = 0;

done:
2082
    remoteDriverUnlock(priv);
2083
    return rv;
2084 2085 2086 2087 2088
}

static int
remoteDomainSave (virDomainPtr domain, const char *to)
{
2089
    int rv = -1;
2090
    remote_domain_save_args args;
2091
    struct private_data *priv = domain->conn->privateData;
2092

2093 2094
    remoteDriverLock(priv);

2095 2096 2097 2098 2099 2100
    make_nonnull_domain (&args.dom, domain);
    args.to = (char *) to;

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SAVE,
              (xdrproc_t) xdr_remote_domain_save_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
2101
        goto done;
2102

2103 2104 2105
    rv = 0;

done:
2106
    remoteDriverUnlock(priv);
2107
    return rv;
2108 2109 2110 2111 2112
}

static int
remoteDomainRestore (virConnectPtr conn, const char *from)
{
2113
    int rv = -1;
2114
    remote_domain_restore_args args;
2115
    struct private_data *priv = conn->privateData;
2116

2117 2118
    remoteDriverLock(priv);

2119 2120 2121 2122 2123
    args.from = (char *) from;

    if (call (conn, priv, 0, REMOTE_PROC_DOMAIN_RESTORE,
              (xdrproc_t) xdr_remote_domain_restore_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
2124
        goto done;
2125

2126 2127 2128
    rv = 0;

done:
2129
    remoteDriverUnlock(priv);
2130
    return rv;
2131 2132 2133 2134 2135
}

static int
remoteDomainCoreDump (virDomainPtr domain, const char *to, int flags)
{
2136
    int rv = -1;
2137
    remote_domain_core_dump_args args;
2138
    struct private_data *priv = domain->conn->privateData;
2139

2140 2141
    remoteDriverLock(priv);

2142 2143 2144 2145 2146 2147 2148
    make_nonnull_domain (&args.dom, domain);
    args.to = (char *) to;
    args.flags = flags;

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_CORE_DUMP,
              (xdrproc_t) xdr_remote_domain_core_dump_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
2149
        goto done;
2150

2151 2152 2153
    rv = 0;

done:
2154
    remoteDriverUnlock(priv);
2155
    return rv;
2156 2157 2158 2159 2160
}

static int
remoteDomainSetVcpus (virDomainPtr domain, unsigned int nvcpus)
{
2161
    int rv = -1;
2162
    remote_domain_set_vcpus_args args;
2163
    struct private_data *priv = domain->conn->privateData;
2164

2165 2166
    remoteDriverLock(priv);

2167 2168 2169 2170 2171 2172
    make_nonnull_domain (&args.dom, domain);
    args.nvcpus = nvcpus;

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SET_VCPUS,
              (xdrproc_t) xdr_remote_domain_set_vcpus_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
2173
        goto done;
2174

2175 2176 2177
    rv = 0;

done:
2178
    remoteDriverUnlock(priv);
2179
    return rv;
2180 2181 2182 2183 2184 2185 2186 2187
}

static int
remoteDomainPinVcpu (virDomainPtr domain,
                     unsigned int vcpu,
                     unsigned char *cpumap,
                     int maplen)
{
2188
    int rv = -1;
2189
    remote_domain_pin_vcpu_args args;
2190
    struct private_data *priv = domain->conn->privateData;
2191

2192 2193
    remoteDriverLock(priv);

2194
    if (maplen > REMOTE_CPUMAP_MAX) {
2195 2196 2197
        errorf (domain->conn, VIR_ERR_RPC,
                _("map length greater than maximum: %d > %d"),
                maplen, REMOTE_CPUMAP_MAX);
2198
        goto done;
2199 2200 2201 2202 2203 2204 2205 2206 2207 2208
    }

    make_nonnull_domain (&args.dom, domain);
    args.vcpu = vcpu;
    args.cpumap.cpumap_len = maplen;
    args.cpumap.cpumap_val = (char *) cpumap;

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_PIN_VCPU,
              (xdrproc_t) xdr_remote_domain_pin_vcpu_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
2209
        goto done;
2210

2211 2212 2213
    rv = 0;

done:
2214
    remoteDriverUnlock(priv);
2215
    return rv;
2216 2217 2218 2219 2220 2221 2222 2223 2224
}

static int
remoteDomainGetVcpus (virDomainPtr domain,
                      virVcpuInfoPtr info,
                      int maxinfo,
                      unsigned char *cpumaps,
                      int maplen)
{
2225
    int rv = -1;
2226 2227 2228
    int i;
    remote_domain_get_vcpus_args args;
    remote_domain_get_vcpus_ret ret;
2229
    struct private_data *priv = domain->conn->privateData;
2230

2231 2232
    remoteDriverLock(priv);

2233
    if (maxinfo > REMOTE_VCPUINFO_MAX) {
2234 2235 2236
        errorf (domain->conn, VIR_ERR_RPC,
                _("vCPU count exceeds maximum: %d > %d"),
                maxinfo, REMOTE_VCPUINFO_MAX);
2237
        goto done;
2238
    }
2239
    if (maxinfo * maplen > REMOTE_CPUMAPS_MAX) {
2240 2241 2242
        errorf (domain->conn, VIR_ERR_RPC,
                _("vCPU map buffer length exceeds maximum: %d > %d"),
                maxinfo * maplen, REMOTE_CPUMAPS_MAX);
2243
        goto done;
2244 2245 2246 2247 2248 2249 2250 2251 2252 2253
    }

    make_nonnull_domain (&args.dom, domain);
    args.maxinfo = maxinfo;
    args.maplen = maplen;

    memset (&ret, 0, sizeof ret);
    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_VCPUS,
              (xdrproc_t) xdr_remote_domain_get_vcpus_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_get_vcpus_ret, (char *) &ret) == -1)
2254
        goto done;
2255 2256

    if (ret.info.info_len > maxinfo) {
2257 2258 2259
        errorf (domain->conn, VIR_ERR_RPC,
                _("host reports too many vCPUs: %d > %d"),
                ret.info.info_len, maxinfo);
2260
        goto cleanup;
2261
    }
2262
    if (ret.cpumaps.cpumaps_len > maxinfo * maplen) {
2263 2264 2265
        errorf (domain->conn, VIR_ERR_RPC,
                _("host reports map buffer length exceeds maximum: %d > %d"),
                ret.cpumaps.cpumaps_len, maxinfo * maplen);
2266
        goto cleanup;
2267 2268
    }

2269 2270 2271
    memset (info, 0, sizeof (virVcpuInfo) * maxinfo);
    memset (cpumaps, 0, maxinfo * maplen);

2272 2273 2274 2275 2276 2277 2278 2279 2280 2281
    for (i = 0; i < ret.info.info_len; ++i) {
        info[i].number = ret.info.info_val[i].number;
        info[i].state = ret.info.info_val[i].state;
        info[i].cpuTime = ret.info.info_val[i].cpu_time;
        info[i].cpu = ret.info.info_val[i].cpu;
    }

    for (i = 0; i < ret.cpumaps.cpumaps_len; ++i)
        cpumaps[i] = ret.cpumaps.cpumaps_val[i];

2282 2283 2284
    rv = ret.info.info_len;

cleanup:
2285
    xdr_free ((xdrproc_t) xdr_remote_domain_get_vcpus_ret, (char *) &ret);
2286 2287

done:
2288
    remoteDriverUnlock(priv);
2289
    return rv;
2290 2291 2292 2293 2294
}

static int
remoteDomainGetMaxVcpus (virDomainPtr domain)
{
2295
    int rv = -1;
2296 2297
    remote_domain_get_max_vcpus_args args;
    remote_domain_get_max_vcpus_ret ret;
2298
    struct private_data *priv = domain->conn->privateData;
2299

2300 2301
    remoteDriverLock(priv);

2302 2303 2304
    make_nonnull_domain (&args.dom, domain);

    memset (&ret, 0, sizeof ret);
2305
    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_MAX_VCPUS,
2306 2307
              (xdrproc_t) xdr_remote_domain_get_max_vcpus_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_get_max_vcpus_ret, (char *) &ret) == -1)
2308
        goto done;
2309

2310 2311 2312
    rv = ret.num;

done:
2313
    remoteDriverUnlock(priv);
2314
    return rv;
2315 2316
}

2317 2318 2319 2320 2321 2322
static int
remoteDomainGetSecurityLabel (virDomainPtr domain, virSecurityLabelPtr seclabel)
{
    remote_domain_get_security_label_args args;
    remote_domain_get_security_label_ret ret;
    struct private_data *priv = domain->conn->privateData;
2323 2324 2325
    int rv = -1;

    remoteDriverLock(priv);
2326 2327 2328

    make_nonnull_domain (&args.dom, domain);
    memset (&ret, 0, sizeof ret);
2329 2330
    memset (seclabel, 0, sizeof (*seclabel));

2331 2332 2333
    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL,
              (xdrproc_t) xdr_remote_domain_get_security_label_args, (char *)&args,
              (xdrproc_t) xdr_remote_domain_get_security_label_ret, (char *)&ret) == -1) {
2334
        goto done;
2335 2336 2337 2338 2339 2340
    }

    if (ret.label.label_val != NULL) {
        if (strlen (ret.label.label_val) >= sizeof seclabel->label) {
            errorf (domain->conn, VIR_ERR_RPC, _("security label exceeds maximum: %zd"),
                    sizeof seclabel->label - 1);
2341
            goto done;
2342 2343 2344 2345 2346
        }
        strcpy (seclabel->label, ret.label.label_val);
        seclabel->enforcing = ret.enforcing;
    }

2347 2348 2349 2350 2351
    rv = 0;

done:
    remoteDriverUnlock(priv);
    return rv;
2352 2353 2354 2355 2356 2357 2358
}

static int
remoteNodeGetSecurityModel (virConnectPtr conn, virSecurityModelPtr secmodel)
{
    remote_node_get_security_model_ret ret;
    struct private_data *priv = conn->privateData;
2359 2360 2361
    int rv = -1;

    remoteDriverLock(priv);
2362 2363

    memset (&ret, 0, sizeof ret);
2364 2365
    memset (secmodel, 0, sizeof (*secmodel));

2366 2367 2368
    if (call (conn, priv, 0, REMOTE_PROC_NODE_GET_SECURITY_MODEL,
              (xdrproc_t) xdr_void, NULL,
              (xdrproc_t) xdr_remote_node_get_security_model_ret, (char *)&ret) == -1) {
2369
        goto done;
2370 2371 2372 2373 2374 2375
    }

    if (ret.model.model_val != NULL) {
        if (strlen (ret.model.model_val) >= sizeof secmodel->model) {
            errorf (conn, VIR_ERR_RPC, _("security model exceeds maximum: %zd"),
                    sizeof secmodel->model - 1);
2376
            goto done;
2377 2378 2379 2380 2381 2382 2383 2384
        }
        strcpy (secmodel->model, ret.model.model_val);
    }

    if (ret.doi.doi_val != NULL) {
        if (strlen (ret.doi.doi_val) >= sizeof secmodel->doi) {
            errorf (conn, VIR_ERR_RPC, _("security doi exceeds maximum: %zd"),
                    sizeof secmodel->doi - 1);
2385
            goto done;
2386 2387 2388
        }
        strcpy (secmodel->doi, ret.doi.doi_val);
    }
2389 2390 2391 2392 2393 2394

    rv = 0;

done:
    remoteDriverUnlock(priv);
    return rv;
2395 2396
}

2397 2398 2399
static char *
remoteDomainDumpXML (virDomainPtr domain, int flags)
{
2400
    char *rv = NULL;
2401 2402
    remote_domain_dump_xml_args args;
    remote_domain_dump_xml_ret ret;
2403
    struct private_data *priv = domain->conn->privateData;
2404

2405 2406
    remoteDriverLock(priv);

2407 2408 2409 2410 2411 2412 2413
    make_nonnull_domain (&args.dom, domain);
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_DUMP_XML,
              (xdrproc_t) xdr_remote_domain_dump_xml_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_dump_xml_ret, (char *) &ret) == -1)
2414
        goto done;
2415 2416

    /* Caller frees. */
2417 2418 2419
    rv = ret.xml;

done:
2420
    remoteDriverUnlock(priv);
2421
    return rv;
2422 2423
}

2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485
static char *
remoteDomainXMLFromNative (virConnectPtr conn,
                           const char *format,
                           const char *config,
                           unsigned int flags)
{
    char *rv = NULL;
    remote_domain_xml_from_native_args args;
    remote_domain_xml_from_native_ret ret;
    struct private_data *priv = conn->privateData;

    remoteDriverLock(priv);

    args.nativeFormat = (char *)format;
    args.nativeConfig = (char *)config;
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_DOMAIN_XML_FROM_NATIVE,
              (xdrproc_t) xdr_remote_domain_xml_from_native_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_xml_from_native_ret, (char *) &ret) == -1)
        goto done;

    /* Caller frees. */
    rv = ret.domainXml;

done:
    remoteDriverUnlock(priv);
    return rv;
}

static char *
remoteDomainXMLToNative (virConnectPtr conn,
                         const char *format,
                         const char *xml,
                         unsigned int flags)
{
    char *rv = NULL;
    remote_domain_xml_to_native_args args;
    remote_domain_xml_to_native_ret ret;
    struct private_data *priv = conn->privateData;

    remoteDriverLock(priv);

    args.nativeFormat = (char *)format;
    args.domainXml = (char *)xml;
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_DOMAIN_XML_TO_NATIVE,
              (xdrproc_t) xdr_remote_domain_xml_to_native_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_xml_to_native_ret, (char *) &ret) == -1)
        goto done;

    /* Caller frees. */
    rv = ret.nativeConfig;

done:
    remoteDriverUnlock(priv);
    return rv;
}

2486 2487 2488 2489 2490 2491 2492
static int
remoteDomainMigratePrepare (virConnectPtr dconn,
                            char **cookie, int *cookielen,
                            const char *uri_in, char **uri_out,
                            unsigned long flags, const char *dname,
                            unsigned long resource)
{
2493
    int rv = -1;
2494 2495
    remote_domain_migrate_prepare_args args;
    remote_domain_migrate_prepare_ret ret;
2496
    struct private_data *priv = dconn->privateData;
2497

2498 2499
    remoteDriverLock(priv);

2500 2501 2502 2503 2504 2505 2506 2507 2508
    args.uri_in = uri_in == NULL ? NULL : (char **) &uri_in;
    args.flags = flags;
    args.dname = dname == NULL ? NULL : (char **) &dname;
    args.resource = resource;

    memset (&ret, 0, sizeof ret);
    if (call (dconn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_PREPARE,
              (xdrproc_t) xdr_remote_domain_migrate_prepare_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_migrate_prepare_ret, (char *) &ret) == -1)
2509
        goto done;
2510 2511 2512 2513 2514 2515 2516 2517

    if (ret.cookie.cookie_len > 0) {
        *cookie = ret.cookie.cookie_val; /* Caller frees. */
        *cookielen = ret.cookie.cookie_len;
    }
    if (ret.uri_out)
        *uri_out = *ret.uri_out; /* Caller frees. */

2518 2519 2520
    rv = 0;

done:
2521
    remoteDriverUnlock(priv);
2522
    return rv;
2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533
}

static int
remoteDomainMigratePerform (virDomainPtr domain,
                            const char *cookie,
                            int cookielen,
                            const char *uri,
                            unsigned long flags,
                            const char *dname,
                            unsigned long resource)
{
2534
    int rv = -1;
2535
    remote_domain_migrate_perform_args args;
2536
    struct private_data *priv = domain->conn->privateData;
2537

2538 2539
    remoteDriverLock(priv);

2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550
    make_nonnull_domain (&args.dom, domain);
    args.cookie.cookie_len = cookielen;
    args.cookie.cookie_val = (char *) cookie;
    args.uri = (char *) uri;
    args.flags = flags;
    args.dname = dname == NULL ? NULL : (char **) &dname;
    args.resource = resource;

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_PERFORM,
              (xdrproc_t) xdr_remote_domain_migrate_perform_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
2551
        goto done;
2552

2553 2554 2555
    rv = 0;

done:
2556
    remoteDriverUnlock(priv);
2557
    return rv;
2558 2559 2560 2561 2562 2563 2564 2565 2566 2567
}

static virDomainPtr
remoteDomainMigrateFinish (virConnectPtr dconn,
                           const char *dname,
                           const char *cookie,
                           int cookielen,
                           const char *uri,
                           unsigned long flags)
{
2568
    virDomainPtr ddom = NULL;
2569 2570
    remote_domain_migrate_finish_args args;
    remote_domain_migrate_finish_ret ret;
2571
    struct private_data *priv = dconn->privateData;
2572

2573 2574
    remoteDriverLock(priv);

2575 2576 2577 2578 2579 2580 2581 2582 2583 2584
    args.dname = (char *) dname;
    args.cookie.cookie_len = cookielen;
    args.cookie.cookie_val = (char *) cookie;
    args.uri = (char *) uri;
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (dconn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_FINISH,
              (xdrproc_t) xdr_remote_domain_migrate_finish_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_migrate_finish_ret, (char *) &ret) == -1)
2585
        goto done;
2586 2587 2588 2589

    ddom = get_nonnull_domain (dconn, ret.ddom);
    xdr_free ((xdrproc_t) &xdr_remote_domain_migrate_finish_ret, (char *) &ret);

2590
done:
2591
    remoteDriverUnlock(priv);
2592 2593 2594
    return ddom;
}

D
Daniel Veillard 已提交
2595 2596 2597 2598 2599 2600 2601 2602
static int
remoteDomainMigratePrepare2 (virConnectPtr dconn,
                             char **cookie, int *cookielen,
                             const char *uri_in, char **uri_out,
                             unsigned long flags, const char *dname,
                             unsigned long resource,
                             const char *dom_xml)
{
2603
    int rv = -1;
D
Daniel Veillard 已提交
2604 2605
    remote_domain_migrate_prepare2_args args;
    remote_domain_migrate_prepare2_ret ret;
2606
    struct private_data *priv = dconn->privateData;
D
Daniel Veillard 已提交
2607

2608 2609
    remoteDriverLock(priv);

D
Daniel Veillard 已提交
2610 2611 2612 2613 2614 2615 2616 2617 2618 2619
    args.uri_in = uri_in == NULL ? NULL : (char **) &uri_in;
    args.flags = flags;
    args.dname = dname == NULL ? NULL : (char **) &dname;
    args.resource = resource;
    args.dom_xml = (char *) dom_xml;

    memset (&ret, 0, sizeof ret);
    if (call (dconn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_PREPARE2,
              (xdrproc_t) xdr_remote_domain_migrate_prepare2_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_migrate_prepare2_ret, (char *) &ret) == -1)
2620
        goto done;
D
Daniel Veillard 已提交
2621 2622 2623 2624 2625 2626 2627 2628

    if (ret.cookie.cookie_len > 0) {
        *cookie = ret.cookie.cookie_val; /* Caller frees. */
        *cookielen = ret.cookie.cookie_len;
    }
    if (ret.uri_out)
        *uri_out = *ret.uri_out; /* Caller frees. */

2629 2630 2631
    rv = 0;

done:
2632
    remoteDriverUnlock(priv);
2633
    return rv;
D
Daniel Veillard 已提交
2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644
}

static virDomainPtr
remoteDomainMigrateFinish2 (virConnectPtr dconn,
                            const char *dname,
                            const char *cookie,
                            int cookielen,
                            const char *uri,
                            unsigned long flags,
                            int retcode)
{
2645
    virDomainPtr ddom = NULL;
D
Daniel Veillard 已提交
2646 2647
    remote_domain_migrate_finish2_args args;
    remote_domain_migrate_finish2_ret ret;
2648
    struct private_data *priv = dconn->privateData;
D
Daniel Veillard 已提交
2649

2650 2651
    remoteDriverLock(priv);

D
Daniel Veillard 已提交
2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662
    args.dname = (char *) dname;
    args.cookie.cookie_len = cookielen;
    args.cookie.cookie_val = (char *) cookie;
    args.uri = (char *) uri;
    args.flags = flags;
    args.retcode = retcode;

    memset (&ret, 0, sizeof ret);
    if (call (dconn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_FINISH2,
              (xdrproc_t) xdr_remote_domain_migrate_finish2_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_migrate_finish2_ret, (char *) &ret) == -1)
2663
        goto done;
D
Daniel Veillard 已提交
2664 2665 2666 2667

    ddom = get_nonnull_domain (dconn, ret.ddom);
    xdr_free ((xdrproc_t) &xdr_remote_domain_migrate_finish2_ret, (char *) &ret);

2668
done:
2669
    remoteDriverUnlock(priv);
D
Daniel Veillard 已提交
2670 2671 2672
    return ddom;
}

2673 2674 2675
static int
remoteListDefinedDomains (virConnectPtr conn, char **const names, int maxnames)
{
2676
    int rv = -1;
2677 2678 2679
    int i;
    remote_list_defined_domains_args args;
    remote_list_defined_domains_ret ret;
2680
    struct private_data *priv = conn->privateData;
2681

2682 2683
    remoteDriverLock(priv);

2684
    if (maxnames > REMOTE_DOMAIN_NAME_LIST_MAX) {
2685 2686 2687
        errorf (conn, VIR_ERR_RPC,
                _("too many remote domain names: %d > %d"),
                maxnames, REMOTE_DOMAIN_NAME_LIST_MAX);
2688
        goto done;
2689 2690 2691 2692 2693 2694 2695
    }
    args.maxnames = maxnames;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_LIST_DEFINED_DOMAINS,
              (xdrproc_t) xdr_remote_list_defined_domains_args, (char *) &args,
              (xdrproc_t) xdr_remote_list_defined_domains_ret, (char *) &ret) == -1)
2696
        goto done;
2697 2698

    if (ret.names.names_len > maxnames) {
2699 2700 2701
        errorf (conn, VIR_ERR_RPC,
                _("too many remote domain names: %d > %d"),
                ret.names.names_len, maxnames);
2702
        goto cleanup;
2703 2704 2705 2706 2707 2708 2709 2710 2711 2712
    }

    /* This call is caller-frees (although that isn't clear from
     * the documentation).  However xdr_free will free up both the
     * names and the list of pointers, so we have to strdup the
     * names here.
     */
    for (i = 0; i < ret.names.names_len; ++i)
        names[i] = strdup (ret.names.names_val[i]);

2713 2714 2715
    rv = ret.names.names_len;

cleanup:
2716 2717
    xdr_free ((xdrproc_t) xdr_remote_list_defined_domains_ret, (char *) &ret);

2718
done:
2719
    remoteDriverUnlock(priv);
2720
    return rv;
2721 2722 2723 2724 2725
}

static int
remoteNumOfDefinedDomains (virConnectPtr conn)
{
2726
    int rv = -1;
2727
    remote_num_of_defined_domains_ret ret;
2728
    struct private_data *priv = conn->privateData;
2729

2730 2731
    remoteDriverLock(priv);

2732 2733 2734 2735
    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NUM_OF_DEFINED_DOMAINS,
              (xdrproc_t) xdr_void, (char *) NULL,
              (xdrproc_t) xdr_remote_num_of_defined_domains_ret, (char *) &ret) == -1)
2736
        goto done;
2737

2738 2739 2740
    rv = ret.num;

done:
2741
    remoteDriverUnlock(priv);
2742
    return rv;
2743 2744 2745 2746 2747
}

static int
remoteDomainCreate (virDomainPtr domain)
{
2748
    int rv = -1;
2749
    remote_domain_create_args args;
2750 2751
    remote_domain_lookup_by_uuid_args args2;
    remote_domain_lookup_by_uuid_ret ret2;
2752
    struct private_data *priv = domain->conn->privateData;
2753

2754 2755
    remoteDriverLock(priv);

2756 2757 2758 2759 2760
    make_nonnull_domain (&args.dom, domain);

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_CREATE,
              (xdrproc_t) xdr_remote_domain_create_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
2761
        goto done;
2762

2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776
    /* Need to do a lookup figure out ID of newly started guest, because
     * bug in design of REMOTE_PROC_DOMAIN_CREATE means we aren't getting
     * it returned.
     */
    memcpy (args2.uuid, domain->uuid, VIR_UUID_BUFLEN);
    memset (&ret2, 0, sizeof ret2);
    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_LOOKUP_BY_UUID,
              (xdrproc_t) xdr_remote_domain_lookup_by_uuid_args, (char *) &args2,
              (xdrproc_t) xdr_remote_domain_lookup_by_uuid_ret, (char *) &ret2) == -1)
        goto done;

    domain->id = ret2.dom.id;
    xdr_free ((xdrproc_t) &xdr_remote_domain_lookup_by_uuid_ret, (char *) &ret2);

2777 2778 2779
    rv = 0;

done:
2780
    remoteDriverUnlock(priv);
2781
    return rv;
2782 2783 2784 2785 2786
}

static virDomainPtr
remoteDomainDefineXML (virConnectPtr conn, const char *xml)
{
2787
    virDomainPtr dom = NULL;
2788 2789
    remote_domain_define_xml_args args;
    remote_domain_define_xml_ret ret;
2790
    struct private_data *priv = conn->privateData;
2791

2792 2793
    remoteDriverLock(priv);

2794 2795 2796 2797 2798 2799
    args.xml = (char *) xml;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_DOMAIN_DEFINE_XML,
              (xdrproc_t) xdr_remote_domain_define_xml_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_define_xml_ret, (char *) &ret) == -1)
2800
        goto done;
2801 2802 2803 2804

    dom = get_nonnull_domain (conn, ret.dom);
    xdr_free ((xdrproc_t) xdr_remote_domain_define_xml_ret, (char *) &ret);

2805
done:
2806
    remoteDriverUnlock(priv);
2807 2808 2809 2810 2811 2812
    return dom;
}

static int
remoteDomainUndefine (virDomainPtr domain)
{
2813
    int rv = -1;
2814
    remote_domain_undefine_args args;
2815
    struct private_data *priv = domain->conn->privateData;
2816

2817 2818
    remoteDriverLock(priv);

2819 2820 2821 2822 2823
    make_nonnull_domain (&args.dom, domain);

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_UNDEFINE,
              (xdrproc_t) xdr_remote_domain_undefine_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
2824
        goto done;
2825

2826 2827 2828
    rv = 0;

done:
2829
    remoteDriverUnlock(priv);
2830
    return rv;
2831 2832 2833
}

static int
2834
remoteDomainAttachDevice (virDomainPtr domain, const char *xml)
2835
{
2836
    int rv = -1;
2837
    remote_domain_attach_device_args args;
2838
    struct private_data *priv = domain->conn->privateData;
2839

2840 2841
    remoteDriverLock(priv);

2842
    make_nonnull_domain (&args.dom, domain);
2843
    args.xml = (char *) xml;
2844 2845 2846 2847

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_ATTACH_DEVICE,
              (xdrproc_t) xdr_remote_domain_attach_device_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
2848
        goto done;
2849

2850 2851 2852
    rv = 0;

done:
2853
    remoteDriverUnlock(priv);
2854
    return rv;
2855 2856 2857
}

static int
2858
remoteDomainDetachDevice (virDomainPtr domain, const char *xml)
2859
{
2860
    int rv = -1;
2861
    remote_domain_detach_device_args args;
2862
    struct private_data *priv = domain->conn->privateData;
2863

2864 2865
    remoteDriverLock(priv);

2866
    make_nonnull_domain (&args.dom, domain);
2867
    args.xml = (char *) xml;
2868 2869 2870 2871

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_DETACH_DEVICE,
              (xdrproc_t) xdr_remote_domain_detach_device_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
2872
        goto done;
2873

2874 2875 2876
    rv = 0;

done:
2877
    remoteDriverUnlock(priv);
2878
    return rv;
2879 2880 2881 2882 2883
}

static int
remoteDomainGetAutostart (virDomainPtr domain, int *autostart)
{
2884
    int rv = -1;
2885 2886
    remote_domain_get_autostart_args args;
    remote_domain_get_autostart_ret ret;
2887
    struct private_data *priv = domain->conn->privateData;
2888

2889 2890
    remoteDriverLock(priv);

2891 2892 2893 2894 2895 2896
    make_nonnull_domain (&args.dom, domain);

    memset (&ret, 0, sizeof ret);
    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_AUTOSTART,
              (xdrproc_t) xdr_remote_domain_get_autostart_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_get_autostart_ret, (char *) &ret) == -1)
2897
        goto done;
2898 2899

    if (autostart) *autostart = ret.autostart;
2900 2901 2902
    rv = 0;

done:
2903
    remoteDriverUnlock(priv);
2904
    return rv;
2905 2906 2907 2908 2909
}

static int
remoteDomainSetAutostart (virDomainPtr domain, int autostart)
{
2910
    int rv = -1;
2911
    remote_domain_set_autostart_args args;
2912
    struct private_data *priv = domain->conn->privateData;
2913

2914 2915
    remoteDriverLock(priv);

2916 2917 2918 2919 2920 2921
    make_nonnull_domain (&args.dom, domain);
    args.autostart = autostart;

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SET_AUTOSTART,
              (xdrproc_t) xdr_remote_domain_set_autostart_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
2922
        goto done;
2923

2924 2925 2926
    rv = 0;

done:
2927
    remoteDriverUnlock(priv);
2928
    return rv;
2929 2930
}

2931 2932 2933
static char *
remoteDomainGetSchedulerType (virDomainPtr domain, int *nparams)
{
2934
    char *rv = NULL;
2935 2936
    remote_domain_get_scheduler_type_args args;
    remote_domain_get_scheduler_type_ret ret;
2937
    struct private_data *priv = domain->conn->privateData;
2938

2939 2940
    remoteDriverLock(priv);

2941 2942 2943 2944 2945 2946
    make_nonnull_domain (&args.dom, domain);

    memset (&ret, 0, sizeof ret);
    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_SCHEDULER_TYPE,
              (xdrproc_t) xdr_remote_domain_get_scheduler_type_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_get_scheduler_type_ret, (char *) &ret) == -1)
2947
        goto done;
2948 2949 2950 2951

    if (nparams) *nparams = ret.nparams;

    /* Caller frees this. */
2952 2953 2954
    rv = ret.type;

done:
2955
    remoteDriverUnlock(priv);
2956
    return rv;
2957 2958 2959 2960 2961 2962
}

static int
remoteDomainGetSchedulerParameters (virDomainPtr domain,
                                    virSchedParameterPtr params, int *nparams)
{
2963
    int rv = -1;
2964 2965
    remote_domain_get_scheduler_parameters_args args;
    remote_domain_get_scheduler_parameters_ret ret;
2966
    int i = -1;
2967
    struct private_data *priv = domain->conn->privateData;
2968

2969 2970
    remoteDriverLock(priv);

2971 2972 2973 2974 2975 2976 2977
    make_nonnull_domain (&args.dom, domain);
    args.nparams = *nparams;

    memset (&ret, 0, sizeof ret);
    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_SCHEDULER_PARAMETERS,
              (xdrproc_t) xdr_remote_domain_get_scheduler_parameters_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_get_scheduler_parameters_ret, (char *) &ret) == -1)
2978
        goto done;
2979 2980 2981 2982

    /* Check the length of the returned list carefully. */
    if (ret.params.params_len > REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX ||
        ret.params.params_len > *nparams) {
2983 2984 2985
        error (domain->conn, VIR_ERR_RPC,
               _("remoteDomainGetSchedulerParameters: "
                 "returned number of parameters exceeds limit"));
2986
        goto cleanup;
2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009
    }
    *nparams = ret.params.params_len;

    /* Deserialise the result. */
    for (i = 0; i < *nparams; ++i) {
        strncpy (params[i].field, ret.params.params_val[i].field,
                 VIR_DOMAIN_SCHED_FIELD_LENGTH);
        params[i].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
        params[i].type = ret.params.params_val[i].value.type;
        switch (params[i].type) {
        case VIR_DOMAIN_SCHED_FIELD_INT:
            params[i].value.i = ret.params.params_val[i].value.remote_sched_param_value_u.i; break;
        case VIR_DOMAIN_SCHED_FIELD_UINT:
            params[i].value.ui = ret.params.params_val[i].value.remote_sched_param_value_u.ui; break;
        case VIR_DOMAIN_SCHED_FIELD_LLONG:
            params[i].value.l = ret.params.params_val[i].value.remote_sched_param_value_u.l; break;
        case VIR_DOMAIN_SCHED_FIELD_ULLONG:
            params[i].value.ul = ret.params.params_val[i].value.remote_sched_param_value_u.ul; break;
        case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
            params[i].value.d = ret.params.params_val[i].value.remote_sched_param_value_u.d; break;
        case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
            params[i].value.b = ret.params.params_val[i].value.remote_sched_param_value_u.b; break;
        default:
3010 3011 3012
            error (domain->conn, VIR_ERR_RPC,
                   _("remoteDomainGetSchedulerParameters: "
                     "unknown parameter type"));
3013
            goto cleanup;
3014 3015 3016
        }
    }

3017 3018 3019
    rv = 0;

cleanup:
3020
    xdr_free ((xdrproc_t) xdr_remote_domain_get_scheduler_parameters_ret, (char *) &ret);
3021
done:
3022
    remoteDriverUnlock(priv);
3023
    return rv;
3024 3025 3026 3027 3028 3029
}

static int
remoteDomainSetSchedulerParameters (virDomainPtr domain,
                                    virSchedParameterPtr params, int nparams)
{
3030
    int rv = -1;
3031 3032
    remote_domain_set_scheduler_parameters_args args;
    int i, do_error;
3033
    struct private_data *priv = domain->conn->privateData;
3034

3035 3036
    remoteDriverLock(priv);

3037 3038 3039 3040
    make_nonnull_domain (&args.dom, domain);

    /* Serialise the scheduler parameters. */
    args.params.params_len = nparams;
3041
    if (VIR_ALLOC_N(args.params.params_val, nparams) < 0) {
3042
        error (domain->conn, VIR_ERR_RPC, _("out of memory allocating array"));
3043
        goto done;
3044 3045 3046 3047 3048 3049 3050
    }

    do_error = 0;
    for (i = 0; i < nparams; ++i) {
        // call() will free this:
        args.params.params_val[i].field = strdup (params[i].field);
        if (args.params.params_val[i].field == NULL) {
3051
            virReportOOMError (domain->conn);
3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068
            do_error = 1;
        }
        args.params.params_val[i].value.type = params[i].type;
        switch (params[i].type) {
        case VIR_DOMAIN_SCHED_FIELD_INT:
            args.params.params_val[i].value.remote_sched_param_value_u.i = params[i].value.i; break;
        case VIR_DOMAIN_SCHED_FIELD_UINT:
            args.params.params_val[i].value.remote_sched_param_value_u.ui = params[i].value.ui; break;
        case VIR_DOMAIN_SCHED_FIELD_LLONG:
            args.params.params_val[i].value.remote_sched_param_value_u.l = params[i].value.l; break;
        case VIR_DOMAIN_SCHED_FIELD_ULLONG:
            args.params.params_val[i].value.remote_sched_param_value_u.ul = params[i].value.ul; break;
        case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
            args.params.params_val[i].value.remote_sched_param_value_u.d = params[i].value.d; break;
        case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
            args.params.params_val[i].value.remote_sched_param_value_u.b = params[i].value.b; break;
        default:
3069
            error (domain->conn, VIR_ERR_RPC, _("unknown parameter type"));
3070 3071 3072 3073 3074 3075
            do_error = 1;
        }
    }

    if (do_error) {
        xdr_free ((xdrproc_t) xdr_remote_domain_set_scheduler_parameters_args, (char *) &args);
3076
        goto done;
3077 3078 3079 3080 3081
    }

    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SET_SCHEDULER_PARAMETERS,
              (xdrproc_t) xdr_remote_domain_set_scheduler_parameters_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
3082
        goto done;
3083

3084 3085 3086
    rv = 0;

done:
3087
    remoteDriverUnlock(priv);
3088
    return rv;
3089 3090
}

3091 3092 3093 3094
static int
remoteDomainBlockStats (virDomainPtr domain, const char *path,
                        struct _virDomainBlockStats *stats)
{
3095
    int rv = -1;
3096 3097
    remote_domain_block_stats_args args;
    remote_domain_block_stats_ret ret;
3098
    struct private_data *priv = domain->conn->privateData;
3099

3100 3101
    remoteDriverLock(priv);

3102 3103 3104 3105 3106 3107 3108 3109
    make_nonnull_domain (&args.dom, domain);
    args.path = (char *) path;

    memset (&ret, 0, sizeof ret);
    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_BLOCK_STATS,
              (xdrproc_t) xdr_remote_domain_block_stats_args, (char *) &args,
              (xdrproc_t) xdr_remote_domain_block_stats_ret, (char *) &ret)
        == -1)
3110
        goto done;
3111 3112 3113 3114 3115 3116 3117

    stats->rd_req = ret.rd_req;
    stats->rd_bytes = ret.rd_bytes;
    stats->wr_req = ret.wr_req;
    stats->wr_bytes = ret.wr_bytes;
    stats->errs = ret.errs;

3118 3119 3120
    rv = 0;

done:
3121
    remoteDriverUnlock(priv);
3122
    return rv;
3123 3124 3125 3126 3127 3128
}

static int
remoteDomainInterfaceStats (virDomainPtr domain, const char *path,
                            struct _virDomainInterfaceStats *stats)
{
3129
    int rv = -1;
3130 3131
    remote_domain_interface_stats_args args;
    remote_domain_interface_stats_ret ret;
3132
    struct private_data *priv = domain->conn->privateData;
3133

3134 3135
    remoteDriverLock(priv);

3136 3137 3138 3139 3140 3141 3142 3143 3144
    make_nonnull_domain (&args.dom, domain);
    args.path = (char *) path;

    memset (&ret, 0, sizeof ret);
    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_INTERFACE_STATS,
              (xdrproc_t) xdr_remote_domain_interface_stats_args,
                (char *) &args,
              (xdrproc_t) xdr_remote_domain_interface_stats_ret,
                (char *) &ret) == -1)
3145
        goto done;
3146 3147 3148 3149 3150 3151 3152 3153 3154 3155

    stats->rx_bytes = ret.rx_bytes;
    stats->rx_packets = ret.rx_packets;
    stats->rx_errs = ret.rx_errs;
    stats->rx_drop = ret.rx_drop;
    stats->tx_bytes = ret.tx_bytes;
    stats->tx_packets = ret.tx_packets;
    stats->tx_errs = ret.tx_errs;
    stats->tx_drop = ret.tx_drop;

3156 3157 3158
    rv = 0;

done:
3159
    remoteDriverUnlock(priv);
3160
    return rv;
3161 3162
}

3163 3164 3165 3166 3167 3168 3169 3170
static int
remoteDomainBlockPeek (virDomainPtr domain,
                       const char *path,
                       unsigned long long offset,
                       size_t size,
                       void *buffer,
                       unsigned int flags)
{
3171
    int rv = -1;
3172 3173
    remote_domain_block_peek_args args;
    remote_domain_block_peek_ret ret;
3174
    struct private_data *priv = domain->conn->privateData;
3175

3176 3177
    remoteDriverLock(priv);

3178 3179 3180 3181
    if (size > REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX) {
        errorf (domain->conn, VIR_ERR_RPC,
                _("block peek request too large for remote protocol, %zi > %d"),
                size, REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX);
3182
        goto done;
3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196
    }

    make_nonnull_domain (&args.dom, domain);
    args.path = (char *) path;
    args.offset = offset;
    args.size = size;
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_BLOCK_PEEK,
              (xdrproc_t) xdr_remote_domain_block_peek_args,
                (char *) &args,
              (xdrproc_t) xdr_remote_domain_block_peek_ret,
                (char *) &ret) == -1)
3197
        goto done;
3198 3199

    if (ret.buffer.buffer_len != size) {
3200 3201 3202
        errorf (domain->conn, VIR_ERR_RPC,
                "%s", _("returned buffer is not same size as requested"));
        goto cleanup;
3203 3204 3205
    }

    memcpy (buffer, ret.buffer.buffer_val, size);
3206 3207 3208
    rv = 0;

cleanup:
3209 3210
    free (ret.buffer.buffer_val);

3211
done:
3212
    remoteDriverUnlock(priv);
3213
    return rv;
3214 3215
}

R
Richard W.M. Jones 已提交
3216 3217 3218 3219 3220 3221 3222
static int
remoteDomainMemoryPeek (virDomainPtr domain,
                        unsigned long long offset,
                        size_t size,
                        void *buffer,
                        unsigned int flags)
{
3223
    int rv = -1;
R
Richard W.M. Jones 已提交
3224 3225
    remote_domain_memory_peek_args args;
    remote_domain_memory_peek_ret ret;
3226
    struct private_data *priv = domain->conn->privateData;
R
Richard W.M. Jones 已提交
3227

3228 3229
    remoteDriverLock(priv);

R
Richard W.M. Jones 已提交
3230 3231 3232 3233
    if (size > REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX) {
        errorf (domain->conn, VIR_ERR_RPC,
                _("memory peek request too large for remote protocol, %zi > %d"),
                size, REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX);
3234
        goto done;
R
Richard W.M. Jones 已提交
3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247
    }

    make_nonnull_domain (&args.dom, domain);
    args.offset = offset;
    args.size = size;
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_MEMORY_PEEK,
              (xdrproc_t) xdr_remote_domain_memory_peek_args,
                (char *) &args,
              (xdrproc_t) xdr_remote_domain_memory_peek_ret,
                (char *) &ret) == -1)
3248
        goto done;
R
Richard W.M. Jones 已提交
3249 3250

    if (ret.buffer.buffer_len != size) {
3251 3252 3253
        errorf (domain->conn, VIR_ERR_RPC,
                "%s", _("returned buffer is not same size as requested"));
        goto cleanup;
R
Richard W.M. Jones 已提交
3254 3255 3256
    }

    memcpy (buffer, ret.buffer.buffer_val, size);
3257 3258 3259
    rv = 0;

cleanup:
R
Richard W.M. Jones 已提交
3260 3261
    free (ret.buffer.buffer_val);

3262
done:
3263
    remoteDriverUnlock(priv);
3264
    return rv;
R
Richard W.M. Jones 已提交
3265 3266
}

3267 3268
/*----------------------------------------------------------------------*/

3269
static virDrvOpenStatus
3270
remoteNetworkOpen (virConnectPtr conn,
3271
                   virConnectAuthPtr auth,
3272
                   int flags)
3273
{
3274 3275 3276
    if (inside_daemon)
        return VIR_DRV_OPEN_DECLINED;

3277 3278
    if (conn &&
        conn->driver &&
3279
        STREQ (conn->driver->name, "remote")) {
3280 3281 3282
        struct private_data *priv;

       /* If we're here, the remote driver is already
3283 3284 3285
         * in use due to a) a QEMU uri, or b) a remote
         * URI. So we can re-use existing connection
         */
3286 3287 3288 3289 3290
        priv = conn->privateData;
        remoteDriverLock(priv);
        priv->localUses++;
        conn->networkPrivateData = priv;
        remoteDriverUnlock(priv);
3291
        return VIR_DRV_OPEN_SUCCESS;
3292 3293 3294
    } else {
        /* Using a non-remote driver, so we need to open a
         * new connection for network APIs, forcing it to
3295 3296
         * use the UNIX transport. This handles Xen driver
         * which doesn't have its own impl of the network APIs.
3297
         */
3298
        struct private_data *priv;
3299 3300 3301 3302 3303 3304
        int ret;
        ret = remoteOpenSecondaryDriver(conn,
                                        auth,
                                        flags,
                                        &priv);
        if (ret == VIR_DRV_OPEN_SUCCESS)
3305 3306 3307
            conn->networkPrivateData = priv;
        return ret;
    }
3308 3309 3310
}

static int
3311 3312
remoteNetworkClose (virConnectPtr conn)
{
3313
    int rv = 0;
3314 3315
    struct private_data *priv = conn->networkPrivateData;

3316 3317 3318 3319 3320 3321 3322 3323
    remoteDriverLock(priv);
    priv->localUses--;
    if (!priv->localUses) {
        rv = doRemoteClose(conn, priv);
        conn->networkPrivateData = NULL;
        remoteDriverUnlock(priv);
        virMutexDestroy(&priv->lock);
        VIR_FREE(priv);
3324
    }
3325 3326
    if (priv)
        remoteDriverUnlock(priv);
3327
    return rv;
3328 3329 3330 3331 3332
}

static int
remoteNumOfNetworks (virConnectPtr conn)
{
3333
    int rv = -1;
3334
    remote_num_of_networks_ret ret;
3335
    struct private_data *priv = conn->networkPrivateData;
3336

3337 3338
    remoteDriverLock(priv);

3339 3340 3341 3342
    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NUM_OF_NETWORKS,
              (xdrproc_t) xdr_void, (char *) NULL,
              (xdrproc_t) xdr_remote_num_of_networks_ret, (char *) &ret) == -1)
3343 3344 3345
        goto done;

    rv = ret.num;
3346

3347
done:
3348
    remoteDriverUnlock(priv);
3349
    return rv;
3350 3351 3352 3353 3354
}

static int
remoteListNetworks (virConnectPtr conn, char **const names, int maxnames)
{
3355
    int rv = -1;
3356 3357 3358
    int i;
    remote_list_networks_args args;
    remote_list_networks_ret ret;
3359
    struct private_data *priv = conn->networkPrivateData;
3360

3361 3362
    remoteDriverLock(priv);

3363
    if (maxnames > REMOTE_NETWORK_NAME_LIST_MAX) {
3364 3365 3366
        errorf (conn, VIR_ERR_RPC,
                _("too many remote networks: %d > %d"),
                maxnames, REMOTE_NETWORK_NAME_LIST_MAX);
3367
        goto done;
3368 3369 3370 3371 3372 3373 3374
    }
    args.maxnames = maxnames;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_LIST_NETWORKS,
              (xdrproc_t) xdr_remote_list_networks_args, (char *) &args,
              (xdrproc_t) xdr_remote_list_networks_ret, (char *) &ret) == -1)
3375
        goto done;
3376 3377

    if (ret.names.names_len > maxnames) {
3378 3379 3380
        errorf (conn, VIR_ERR_RPC,
                _("too many remote networks: %d > %d"),
                ret.names.names_len, maxnames);
3381
        goto cleanup;
3382 3383 3384 3385 3386 3387 3388 3389 3390 3391
    }

    /* This call is caller-frees (although that isn't clear from
     * the documentation).  However xdr_free will free up both the
     * names and the list of pointers, so we have to strdup the
     * names here.
     */
    for (i = 0; i < ret.names.names_len; ++i)
        names[i] = strdup (ret.names.names_val[i]);

3392 3393 3394
    rv = ret.names.names_len;

cleanup:
3395 3396
    xdr_free ((xdrproc_t) xdr_remote_list_networks_ret, (char *) &ret);

3397
done:
3398
    remoteDriverUnlock(priv);
3399
    return rv;
3400 3401 3402 3403 3404
}

static int
remoteNumOfDefinedNetworks (virConnectPtr conn)
{
3405
    int rv = -1;
3406
    remote_num_of_defined_networks_ret ret;
3407
    struct private_data *priv = conn->networkPrivateData;
3408

3409 3410
    remoteDriverLock(priv);

3411 3412 3413 3414
    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NUM_OF_DEFINED_NETWORKS,
              (xdrproc_t) xdr_void, (char *) NULL,
              (xdrproc_t) xdr_remote_num_of_defined_networks_ret, (char *) &ret) == -1)
3415 3416 3417
        goto done;

    rv = ret.num;
3418

3419
done:
3420
    remoteDriverUnlock(priv);
3421
    return rv;
3422 3423 3424 3425 3426 3427
}

static int
remoteListDefinedNetworks (virConnectPtr conn,
                           char **const names, int maxnames)
{
3428
    int rv = -1;
3429 3430 3431
    int i;
    remote_list_defined_networks_args args;
    remote_list_defined_networks_ret ret;
3432
    struct private_data *priv = conn->networkPrivateData;
3433

3434 3435
    remoteDriverLock(priv);

3436
    if (maxnames > REMOTE_NETWORK_NAME_LIST_MAX) {
3437 3438 3439
        errorf (conn, VIR_ERR_RPC,
                _("too many remote networks: %d > %d"),
                maxnames, REMOTE_NETWORK_NAME_LIST_MAX);
3440
        goto done;
3441 3442 3443 3444 3445 3446 3447
    }
    args.maxnames = maxnames;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_LIST_DEFINED_NETWORKS,
              (xdrproc_t) xdr_remote_list_defined_networks_args, (char *) &args,
              (xdrproc_t) xdr_remote_list_defined_networks_ret, (char *) &ret) == -1)
3448
        goto done;
3449 3450

    if (ret.names.names_len > maxnames) {
3451 3452 3453
        errorf (conn, VIR_ERR_RPC,
                _("too many remote networks: %d > %d"),
                ret.names.names_len, maxnames);
3454
        goto cleanup;
3455 3456 3457 3458 3459 3460 3461 3462 3463 3464
    }

    /* This call is caller-frees (although that isn't clear from
     * the documentation).  However xdr_free will free up both the
     * names and the list of pointers, so we have to strdup the
     * names here.
     */
    for (i = 0; i < ret.names.names_len; ++i)
        names[i] = strdup (ret.names.names_val[i]);

3465 3466 3467
    rv = ret.names.names_len;

cleanup:
3468 3469
    xdr_free ((xdrproc_t) xdr_remote_list_defined_networks_ret, (char *) &ret);

3470
done:
3471
    remoteDriverUnlock(priv);
3472
    return rv;
3473 3474 3475 3476 3477 3478
}

static virNetworkPtr
remoteNetworkLookupByUUID (virConnectPtr conn,
                           const unsigned char *uuid)
{
3479
    virNetworkPtr net = NULL;
3480 3481
    remote_network_lookup_by_uuid_args args;
    remote_network_lookup_by_uuid_ret ret;
3482
    struct private_data *priv = conn->networkPrivateData;
3483

3484 3485
    remoteDriverLock(priv);

3486 3487 3488 3489 3490 3491
    memcpy (args.uuid, uuid, VIR_UUID_BUFLEN);

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NETWORK_LOOKUP_BY_UUID,
              (xdrproc_t) xdr_remote_network_lookup_by_uuid_args, (char *) &args,
              (xdrproc_t) xdr_remote_network_lookup_by_uuid_ret, (char *) &ret) == -1)
3492
        goto done;
3493 3494 3495 3496

    net = get_nonnull_network (conn, ret.net);
    xdr_free ((xdrproc_t) &xdr_remote_network_lookup_by_uuid_ret, (char *) &ret);

3497
done:
3498
    remoteDriverUnlock(priv);
3499 3500 3501 3502 3503 3504 3505
    return net;
}

static virNetworkPtr
remoteNetworkLookupByName (virConnectPtr conn,
                           const char *name)
{
3506
    virNetworkPtr net = NULL;
3507 3508
    remote_network_lookup_by_name_args args;
    remote_network_lookup_by_name_ret ret;
3509
    struct private_data *priv = conn->networkPrivateData;
3510

3511 3512
    remoteDriverLock(priv);

3513 3514 3515 3516 3517 3518
    args.name = (char *) name;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NETWORK_LOOKUP_BY_NAME,
              (xdrproc_t) xdr_remote_network_lookup_by_name_args, (char *) &args,
              (xdrproc_t) xdr_remote_network_lookup_by_name_ret, (char *) &ret) == -1)
3519
        goto done;
3520 3521 3522 3523

    net = get_nonnull_network (conn, ret.net);
    xdr_free ((xdrproc_t) &xdr_remote_network_lookup_by_name_ret, (char *) &ret);

3524
done:
3525
    remoteDriverUnlock(priv);
3526 3527 3528 3529 3530 3531
    return net;
}

static virNetworkPtr
remoteNetworkCreateXML (virConnectPtr conn, const char *xmlDesc)
{
3532
    virNetworkPtr net = NULL;
3533 3534
    remote_network_create_xml_args args;
    remote_network_create_xml_ret ret;
3535
    struct private_data *priv = conn->networkPrivateData;
3536

3537 3538
    remoteDriverLock(priv);

3539 3540 3541 3542 3543 3544
    args.xml = (char *) xmlDesc;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NETWORK_CREATE_XML,
              (xdrproc_t) xdr_remote_network_create_xml_args, (char *) &args,
              (xdrproc_t) xdr_remote_network_create_xml_ret, (char *) &ret) == -1)
3545
        goto done;
3546 3547 3548 3549

    net = get_nonnull_network (conn, ret.net);
    xdr_free ((xdrproc_t) &xdr_remote_network_create_xml_ret, (char *) &ret);

3550
done:
3551
    remoteDriverUnlock(priv);
3552 3553 3554 3555 3556 3557
    return net;
}

static virNetworkPtr
remoteNetworkDefineXML (virConnectPtr conn, const char *xml)
{
3558
    virNetworkPtr net = NULL;
3559 3560
    remote_network_define_xml_args args;
    remote_network_define_xml_ret ret;
3561
    struct private_data *priv = conn->networkPrivateData;
3562

3563 3564
    remoteDriverLock(priv);

3565 3566 3567 3568 3569 3570
    args.xml = (char *) xml;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NETWORK_DEFINE_XML,
              (xdrproc_t) xdr_remote_network_define_xml_args, (char *) &args,
              (xdrproc_t) xdr_remote_network_define_xml_ret, (char *) &ret) == -1)
3571
        goto done;
3572 3573 3574 3575

    net = get_nonnull_network (conn, ret.net);
    xdr_free ((xdrproc_t) &xdr_remote_network_define_xml_ret, (char *) &ret);

3576
done:
3577
    remoteDriverUnlock(priv);
3578 3579 3580 3581 3582 3583
    return net;
}

static int
remoteNetworkUndefine (virNetworkPtr network)
{
3584
    int rv = -1;
3585
    remote_network_undefine_args args;
3586
    struct private_data *priv = network->conn->networkPrivateData;
3587

3588 3589
    remoteDriverLock(priv);

3590 3591 3592 3593 3594
    make_nonnull_network (&args.net, network);

    if (call (network->conn, priv, 0, REMOTE_PROC_NETWORK_UNDEFINE,
              (xdrproc_t) xdr_remote_network_undefine_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
3595
        goto done;
3596

3597 3598 3599
    rv = 0;

done:
3600
    remoteDriverUnlock(priv);
3601
    return rv;
3602 3603 3604 3605 3606
}

static int
remoteNetworkCreate (virNetworkPtr network)
{
3607
    int rv = -1;
3608
    remote_network_create_args args;
3609
    struct private_data *priv = network->conn->networkPrivateData;
3610

3611 3612
    remoteDriverLock(priv);

3613 3614 3615 3616 3617
    make_nonnull_network (&args.net, network);

    if (call (network->conn, priv, 0, REMOTE_PROC_NETWORK_CREATE,
              (xdrproc_t) xdr_remote_network_create_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
3618
        goto done;
3619

3620 3621 3622
    rv = 0;

done:
3623
    remoteDriverUnlock(priv);
3624
    return rv;
3625 3626 3627 3628 3629
}

static int
remoteNetworkDestroy (virNetworkPtr network)
{
3630
    int rv = -1;
3631
    remote_network_destroy_args args;
3632
    struct private_data *priv = network->conn->networkPrivateData;
3633

3634 3635
    remoteDriverLock(priv);

3636 3637 3638 3639 3640
    make_nonnull_network (&args.net, network);

    if (call (network->conn, priv, 0, REMOTE_PROC_NETWORK_DESTROY,
              (xdrproc_t) xdr_remote_network_destroy_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
3641
        goto done;
3642

3643 3644 3645
    rv = 0;

done:
3646
    remoteDriverUnlock(priv);
3647
    return rv;
3648 3649 3650 3651 3652
}

static char *
remoteNetworkDumpXML (virNetworkPtr network, int flags)
{
3653
    char *rv = NULL;
3654 3655
    remote_network_dump_xml_args args;
    remote_network_dump_xml_ret ret;
3656
    struct private_data *priv = network->conn->networkPrivateData;
3657

3658 3659
    remoteDriverLock(priv);

3660 3661 3662 3663 3664 3665 3666
    make_nonnull_network (&args.net, network);
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (network->conn, priv, 0, REMOTE_PROC_NETWORK_DUMP_XML,
              (xdrproc_t) xdr_remote_network_dump_xml_args, (char *) &args,
              (xdrproc_t) xdr_remote_network_dump_xml_ret, (char *) &ret) == -1)
3667
        goto done;
3668 3669

    /* Caller frees. */
3670 3671 3672
    rv = ret.xml;

done:
3673
    remoteDriverUnlock(priv);
3674
    return rv;
3675 3676 3677 3678 3679
}

static char *
remoteNetworkGetBridgeName (virNetworkPtr network)
{
3680
    char *rv = NULL;
3681 3682
    remote_network_get_bridge_name_args args;
    remote_network_get_bridge_name_ret ret;
3683
    struct private_data *priv = network->conn->networkPrivateData;
3684

3685 3686
    remoteDriverLock(priv);

3687 3688 3689 3690 3691 3692
    make_nonnull_network (&args.net, network);

    memset (&ret, 0, sizeof ret);
    if (call (network->conn, priv, 0, REMOTE_PROC_NETWORK_GET_BRIDGE_NAME,
              (xdrproc_t) xdr_remote_network_get_bridge_name_args, (char *) &args,
              (xdrproc_t) xdr_remote_network_get_bridge_name_ret, (char *) &ret) == -1)
3693
        goto done;
3694 3695

    /* Caller frees. */
3696 3697 3698
    rv = ret.name;

done:
3699
    remoteDriverUnlock(priv);
3700
    return rv;
3701 3702 3703 3704 3705
}

static int
remoteNetworkGetAutostart (virNetworkPtr network, int *autostart)
{
3706
    int rv = -1;
3707 3708
    remote_network_get_autostart_args args;
    remote_network_get_autostart_ret ret;
3709
    struct private_data *priv = network->conn->networkPrivateData;
3710

3711 3712
    remoteDriverLock(priv);

3713 3714 3715 3716 3717 3718
    make_nonnull_network (&args.net, network);

    memset (&ret, 0, sizeof ret);
    if (call (network->conn, priv, 0, REMOTE_PROC_NETWORK_GET_AUTOSTART,
              (xdrproc_t) xdr_remote_network_get_autostart_args, (char *) &args,
              (xdrproc_t) xdr_remote_network_get_autostart_ret, (char *) &ret) == -1)
3719
        goto done;
3720 3721 3722

    if (autostart) *autostart = ret.autostart;

3723 3724 3725
    rv = 0;

done:
3726
    remoteDriverUnlock(priv);
3727
    return rv;
3728 3729 3730 3731 3732
}

static int
remoteNetworkSetAutostart (virNetworkPtr network, int autostart)
{
3733
    int rv = -1;
3734
    remote_network_set_autostart_args args;
3735
    struct private_data *priv = network->conn->networkPrivateData;
3736

3737 3738
    remoteDriverLock(priv);

3739 3740 3741 3742 3743 3744
    make_nonnull_network (&args.net, network);
    args.autostart = autostart;

    if (call (network->conn, priv, 0, REMOTE_PROC_NETWORK_SET_AUTOSTART,
              (xdrproc_t) xdr_remote_network_set_autostart_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
3745
        goto done;
3746

3747 3748 3749
    rv = 0;

done:
3750
    remoteDriverUnlock(priv);
3751
    return rv;
3752 3753
}

3754 3755 3756



D
Daniel Veillard 已提交
3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895
/*----------------------------------------------------------------------*/

static virDrvOpenStatus
remoteInterfaceOpen (virConnectPtr conn,
                   virConnectAuthPtr auth,
                   int flags)
{
    if (inside_daemon)
        return VIR_DRV_OPEN_DECLINED;

    if (conn &&
        conn->driver &&
        STREQ (conn->driver->name, "remote")) {
        struct private_data *priv;

       /* If we're here, the remote driver is already
         * in use due to a) a QEMU uri, or b) a remote
         * URI. So we can re-use existing connection
         */
        priv = conn->privateData;
        remoteDriverLock(priv);
        priv->localUses++;
        conn->interfacePrivateData = priv;
        remoteDriverUnlock(priv);
        return VIR_DRV_OPEN_SUCCESS;
    } else {
        /* Using a non-remote driver, so we need to open a
         * new connection for interface APIs, forcing it to
         * use the UNIX transport. This handles Xen driver
         * which doesn't have its own impl of the interface APIs.
         */
        struct private_data *priv;
        int ret;
        ret = remoteOpenSecondaryDriver(conn,
                                        auth,
                                        flags,
                                        &priv);
        if (ret == VIR_DRV_OPEN_SUCCESS)
            conn->interfacePrivateData = priv;
        return ret;
    }
}

static int
remoteInterfaceClose (virConnectPtr conn)
{
    int rv = 0;
    struct private_data *priv = conn->interfacePrivateData;

    remoteDriverLock(priv);
    priv->localUses--;
    if (!priv->localUses) {
        rv = doRemoteClose(conn, priv);
        conn->interfacePrivateData = NULL;
        remoteDriverUnlock(priv);
        virMutexDestroy(&priv->lock);
        VIR_FREE(priv);
    }
    if (priv)
        remoteDriverUnlock(priv);
    return rv;
}

static int
remoteNumOfInterfaces (virConnectPtr conn)
{
    int rv = -1;
    remote_num_of_interfaces_ret ret;
    struct private_data *priv = conn->interfacePrivateData;

    remoteDriverLock(priv);

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NUM_OF_INTERFACES,
              (xdrproc_t) xdr_void, (char *) NULL,
              (xdrproc_t) xdr_remote_num_of_interfaces_ret, (char *) &ret) == -1)
        goto done;

    rv = ret.num;

done:
    remoteDriverUnlock(priv);
    return rv;
}

static int
remoteListInterfaces (virConnectPtr conn, char **const names, int maxnames)
{
    int rv = -1;
    int i;
    remote_list_interfaces_args args;
    remote_list_interfaces_ret ret;
    struct private_data *priv = conn->interfacePrivateData;

    remoteDriverLock(priv);

    if (maxnames > REMOTE_INTERFACE_NAME_LIST_MAX) {
        errorf (conn, VIR_ERR_RPC,
                _("too many remote interfaces: %d > %d"),
                maxnames, REMOTE_INTERFACE_NAME_LIST_MAX);
        goto done;
    }
    args.maxnames = maxnames;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_LIST_INTERFACES,
              (xdrproc_t) xdr_remote_list_interfaces_args, (char *) &args,
              (xdrproc_t) xdr_remote_list_interfaces_ret, (char *) &ret) == -1)
        goto done;

    if (ret.names.names_len > maxnames) {
        errorf (conn, VIR_ERR_RPC,
                _("too many remote interfaces: %d > %d"),
                ret.names.names_len, maxnames);
        goto cleanup;
    }

    /* This call is caller-frees (although that isn't clear from
     * the documentation).  However xdr_free will free up both the
     * names and the list of pointers, so we have to strdup the
     * names here.
     */
    for (i = 0; i < ret.names.names_len; ++i)
        names[i] = strdup (ret.names.names_val[i]);

    rv = ret.names.names_len;

cleanup:
    xdr_free ((xdrproc_t) xdr_remote_list_interfaces_ret, (char *) &ret);

done:
    remoteDriverUnlock(priv);
    return rv;
}

static virInterfacePtr
remoteInterfaceLookupByName (virConnectPtr conn,
                             const char *name)
{
3896
    virInterfacePtr iface = NULL;
D
Daniel Veillard 已提交
3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910
    remote_interface_lookup_by_name_args args;
    remote_interface_lookup_by_name_ret ret;
    struct private_data *priv = conn->interfacePrivateData;

    remoteDriverLock(priv);

    args.name = (char *) name;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_INTERFACE_LOOKUP_BY_NAME,
              (xdrproc_t) xdr_remote_interface_lookup_by_name_args, (char *) &args,
              (xdrproc_t) xdr_remote_interface_lookup_by_name_ret, (char *) &ret) == -1)
        goto done;

3911
    iface = get_nonnull_interface (conn, ret.iface);
D
Daniel Veillard 已提交
3912 3913 3914 3915
    xdr_free ((xdrproc_t) &xdr_remote_interface_lookup_by_name_ret, (char *) &ret);

done:
    remoteDriverUnlock(priv);
3916
    return iface;
D
Daniel Veillard 已提交
3917 3918 3919 3920 3921 3922
}

static virInterfacePtr
remoteInterfaceLookupByMACString (virConnectPtr conn,
                                  const char *mac)
{
3923
    virInterfacePtr iface = NULL;
D
Daniel Veillard 已提交
3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937
    remote_interface_lookup_by_mac_string_args args;
    remote_interface_lookup_by_mac_string_ret ret;
    struct private_data *priv = conn->interfacePrivateData;

    remoteDriverLock(priv);

    args.mac = (char *) mac;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_INTERFACE_LOOKUP_BY_MAC_STRING,
              (xdrproc_t) xdr_remote_interface_lookup_by_mac_string_args, (char *) &args,
              (xdrproc_t) xdr_remote_interface_lookup_by_mac_string_ret, (char *) &ret) == -1)
        goto done;

3938
    iface = get_nonnull_interface (conn, ret.iface);
D
Daniel Veillard 已提交
3939 3940 3941 3942
    xdr_free ((xdrproc_t) &xdr_remote_interface_lookup_by_mac_string_ret, (char *) &ret);

done:
    remoteDriverUnlock(priv);
3943
    return iface;
D
Daniel Veillard 已提交
3944 3945 3946
}

static char *
3947
remoteInterfaceGetXMLDesc (virInterfacePtr iface,
D
Daniel Veillard 已提交
3948 3949 3950 3951 3952
                           unsigned int flags)
{
    char *rv = NULL;
    remote_interface_get_xml_desc_args args;
    remote_interface_get_xml_desc_ret ret;
3953
    struct private_data *priv = iface->conn->interfacePrivateData;
D
Daniel Veillard 已提交
3954 3955 3956

    remoteDriverLock(priv);

3957
    make_nonnull_interface (&args.iface, iface);
D
Daniel Veillard 已提交
3958 3959 3960
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
3961
    if (call (iface->conn, priv, 0, REMOTE_PROC_INTERFACE_GET_XML_DESC,
D
Daniel Veillard 已提交
3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978
              (xdrproc_t) xdr_remote_interface_get_xml_desc_args, (char *) &args,
              (xdrproc_t) xdr_remote_interface_get_xml_desc_ret, (char *) &ret) == -1)
        goto done;

    /* Caller frees. */
    rv = ret.xml;

done:
    remoteDriverUnlock(priv);
    return rv;
}

static virInterfacePtr
remoteInterfaceDefineXML (virConnectPtr conn,
                          const char *xmlDesc,
                          unsigned int flags)
{
3979
    virInterfacePtr iface = NULL;
D
Daniel Veillard 已提交
3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994
    remote_interface_define_xml_args args;
    remote_interface_define_xml_ret ret;
    struct private_data *priv = conn->interfacePrivateData;

    remoteDriverLock(priv);

    args.xml = (char *) xmlDesc;
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_INTERFACE_DEFINE_XML,
              (xdrproc_t) xdr_remote_interface_define_xml_args, (char *) &args,
              (xdrproc_t) xdr_remote_interface_define_xml_ret, (char *) &ret) == -1)
        goto done;

3995
    iface = get_nonnull_interface (conn, ret.iface);
D
Daniel Veillard 已提交
3996 3997 3998 3999
    xdr_free ((xdrproc_t) &xdr_remote_interface_define_xml_ret, (char *) &ret);

done:
    remoteDriverUnlock(priv);
4000
    return iface;
D
Daniel Veillard 已提交
4001 4002 4003
}

static int
4004
remoteInterfaceUndefine (virInterfacePtr iface)
D
Daniel Veillard 已提交
4005 4006 4007
{
    int rv = -1;
    remote_interface_undefine_args args;
4008
    struct private_data *priv = iface->conn->interfacePrivateData;
D
Daniel Veillard 已提交
4009 4010 4011

    remoteDriverLock(priv);

4012
    make_nonnull_interface (&args.iface, iface);
D
Daniel Veillard 已提交
4013

4014
    if (call (iface->conn, priv, 0, REMOTE_PROC_INTERFACE_UNDEFINE,
D
Daniel Veillard 已提交
4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026
              (xdrproc_t) xdr_remote_interface_undefine_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
        goto done;

    rv = 0;

done:
    remoteDriverUnlock(priv);
    return rv;
}

static int
4027
remoteInterfaceCreate (virInterfacePtr iface,
D
Daniel Veillard 已提交
4028 4029 4030 4031
                       unsigned int flags)
{
    int rv = -1;
    remote_interface_create_args args;
4032
    struct private_data *priv = iface->conn->interfacePrivateData;
D
Daniel Veillard 已提交
4033 4034 4035

    remoteDriverLock(priv);

4036
    make_nonnull_interface (&args.iface, iface);
D
Daniel Veillard 已提交
4037 4038
    args.flags = flags;

4039
    if (call (iface->conn, priv, 0, REMOTE_PROC_INTERFACE_CREATE,
D
Daniel Veillard 已提交
4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051
              (xdrproc_t) xdr_remote_interface_create_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
        goto done;

    rv = 0;

done:
    remoteDriverUnlock(priv);
    return rv;
}

static int
4052
remoteInterfaceDestroy (virInterfacePtr iface,
D
Daniel Veillard 已提交
4053 4054 4055 4056
                        unsigned int flags)
{
    int rv = -1;
    remote_interface_destroy_args args;
4057
    struct private_data *priv = iface->conn->interfacePrivateData;
D
Daniel Veillard 已提交
4058 4059 4060

    remoteDriverLock(priv);

4061
    make_nonnull_interface (&args.iface, iface);
D
Daniel Veillard 已提交
4062 4063
    args.flags = flags;

4064
    if (call (iface->conn, priv, 0, REMOTE_PROC_INTERFACE_DESTROY,
D
Daniel Veillard 已提交
4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075
              (xdrproc_t) xdr_remote_interface_destroy_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
        goto done;

    rv = 0;

done:
    remoteDriverUnlock(priv);
    return rv;
}

4076 4077
/*----------------------------------------------------------------------*/

4078
static virDrvOpenStatus
4079 4080 4081 4082 4083 4084 4085 4086 4087 4088
remoteStorageOpen (virConnectPtr conn,
                   virConnectAuthPtr auth,
                   int flags)
{
    if (inside_daemon)
        return VIR_DRV_OPEN_DECLINED;

    if (conn &&
        conn->driver &&
        STREQ (conn->driver->name, "remote")) {
4089
        struct private_data *priv = conn->privateData;
4090 4091 4092 4093
        /* If we're here, the remote driver is already
         * in use due to a) a QEMU uri, or b) a remote
         * URI. So we can re-use existing connection
         */
4094 4095 4096 4097
        remoteDriverLock(priv);
        priv->localUses++;
        conn->storagePrivateData = priv;
        remoteDriverUnlock(priv);
4098 4099 4100
        return VIR_DRV_OPEN_SUCCESS;
    } else if (conn->networkDriver &&
               STREQ (conn->networkDriver->name, "remote")) {
4101 4102 4103 4104 4105
        struct private_data *priv = conn->networkPrivateData;
        remoteDriverLock(priv);
        conn->storagePrivateData = priv;
        priv->localUses++;
        remoteDriverUnlock(priv);
4106 4107 4108 4109 4110 4111 4112
        return VIR_DRV_OPEN_SUCCESS;
    } else {
        /* Using a non-remote driver, so we need to open a
         * new connection for network APIs, forcing it to
         * use the UNIX transport. This handles Xen driver
         * which doesn't have its own impl of the network APIs.
         */
4113
        struct private_data *priv;
4114 4115 4116 4117 4118 4119
        int ret;
        ret = remoteOpenSecondaryDriver(conn,
                                        auth,
                                        flags,
                                        &priv);
        if (ret == VIR_DRV_OPEN_SUCCESS)
4120 4121 4122 4123 4124 4125 4126 4127 4128
            conn->storagePrivateData = priv;
        return ret;
    }
}

static int
remoteStorageClose (virConnectPtr conn)
{
    int ret = 0;
4129 4130
    struct private_data *priv = conn->storagePrivateData;

4131 4132 4133 4134 4135 4136 4137 4138
    remoteDriverLock(priv);
    priv->localUses--;
    if (!priv->localUses) {
        ret = doRemoteClose(conn, priv);
        conn->storagePrivateData = NULL;
        remoteDriverUnlock(priv);
        virMutexDestroy(&priv->lock);
        VIR_FREE(priv);
4139
    }
4140 4141
    if (priv)
        remoteDriverUnlock(priv);
4142

4143 4144 4145 4146 4147 4148
    return ret;
}

static int
remoteNumOfStoragePools (virConnectPtr conn)
{
4149
    int rv = -1;
4150
    remote_num_of_storage_pools_ret ret;
4151
    struct private_data *priv = conn->storagePrivateData;
4152

4153 4154
    remoteDriverLock(priv);

4155 4156 4157 4158
    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NUM_OF_STORAGE_POOLS,
              (xdrproc_t) xdr_void, (char *) NULL,
              (xdrproc_t) xdr_remote_num_of_storage_pools_ret, (char *) &ret) == -1)
4159 4160 4161
        goto done;

    rv = ret.num;
4162

4163
done:
4164
    remoteDriverUnlock(priv);
4165
    return rv;
4166 4167 4168 4169 4170
}

static int
remoteListStoragePools (virConnectPtr conn, char **const names, int maxnames)
{
4171
    int rv = -1;
4172 4173 4174
    int i;
    remote_list_storage_pools_args args;
    remote_list_storage_pools_ret ret;
4175
    struct private_data *priv = conn->storagePrivateData;
4176

4177 4178
    remoteDriverLock(priv);

4179 4180
    if (maxnames > REMOTE_STORAGE_POOL_NAME_LIST_MAX) {
        error (conn, VIR_ERR_RPC, _("too many storage pools requested"));
4181
        goto done;
4182 4183 4184 4185 4186 4187 4188
    }
    args.maxnames = maxnames;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_LIST_STORAGE_POOLS,
              (xdrproc_t) xdr_remote_list_storage_pools_args, (char *) &args,
              (xdrproc_t) xdr_remote_list_storage_pools_ret, (char *) &ret) == -1)
4189
        goto done;
4190 4191 4192

    if (ret.names.names_len > maxnames) {
        error (conn, VIR_ERR_RPC, _("too many storage pools received"));
4193
        goto cleanup;
4194 4195 4196 4197 4198 4199 4200 4201 4202 4203
    }

    /* This call is caller-frees (although that isn't clear from
     * the documentation).  However xdr_free will free up both the
     * names and the list of pointers, so we have to strdup the
     * names here.
     */
    for (i = 0; i < ret.names.names_len; ++i)
        names[i] = strdup (ret.names.names_val[i]);

4204 4205 4206
    rv = ret.names.names_len;

cleanup:
4207 4208
    xdr_free ((xdrproc_t) xdr_remote_list_storage_pools_ret, (char *) &ret);

4209
done:
4210
    remoteDriverUnlock(priv);
4211
    return rv;
4212 4213 4214 4215 4216
}

static int
remoteNumOfDefinedStoragePools (virConnectPtr conn)
{
4217
    int rv = -1;
4218
    remote_num_of_defined_storage_pools_ret ret;
4219
    struct private_data *priv = conn->storagePrivateData;
4220

4221 4222
    remoteDriverLock(priv);

4223 4224 4225 4226
    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NUM_OF_DEFINED_STORAGE_POOLS,
              (xdrproc_t) xdr_void, (char *) NULL,
              (xdrproc_t) xdr_remote_num_of_defined_storage_pools_ret, (char *) &ret) == -1)
4227
        goto done;
4228

4229 4230 4231
    rv = ret.num;

done:
4232
    remoteDriverUnlock(priv);
4233
    return rv;
4234 4235 4236 4237 4238 4239
}

static int
remoteListDefinedStoragePools (virConnectPtr conn,
                               char **const names, int maxnames)
{
4240
    int rv = -1;
4241 4242 4243
    int i;
    remote_list_defined_storage_pools_args args;
    remote_list_defined_storage_pools_ret ret;
4244
    struct private_data *priv = conn->storagePrivateData;
4245

4246 4247
    remoteDriverLock(priv);

4248 4249
    if (maxnames > REMOTE_STORAGE_POOL_NAME_LIST_MAX) {
        error (conn, VIR_ERR_RPC, _("too many storage pools requested"));
4250
        goto done;
4251 4252 4253 4254 4255 4256 4257
    }
    args.maxnames = maxnames;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_LIST_DEFINED_STORAGE_POOLS,
              (xdrproc_t) xdr_remote_list_defined_storage_pools_args, (char *) &args,
              (xdrproc_t) xdr_remote_list_defined_storage_pools_ret, (char *) &ret) == -1)
4258
        goto done;
4259 4260 4261

    if (ret.names.names_len > maxnames) {
        error (conn, VIR_ERR_RPC, _("too many storage pools received"));
4262
        goto cleanup;
4263 4264 4265 4266 4267 4268 4269 4270 4271 4272
    }

    /* This call is caller-frees (although that isn't clear from
     * the documentation).  However xdr_free will free up both the
     * names and the list of pointers, so we have to strdup the
     * names here.
     */
    for (i = 0; i < ret.names.names_len; ++i)
        names[i] = strdup (ret.names.names_val[i]);

4273 4274 4275
    rv = ret.names.names_len;

cleanup:
4276 4277
    xdr_free ((xdrproc_t) xdr_remote_list_defined_storage_pools_ret, (char *) &ret);

4278
done:
4279
    remoteDriverUnlock(priv);
4280
    return rv;
4281 4282
}

4283 4284 4285 4286 4287 4288
static char *
remoteFindStoragePoolSources (virConnectPtr conn,
                              const char *type,
                              const char *srcSpec,
                              unsigned int flags)
{
4289
    char *rv = NULL;
4290 4291
    remote_find_storage_pool_sources_args args;
    remote_find_storage_pool_sources_ret ret;
4292
    struct private_data *priv = conn->storagePrivateData;
4293 4294
    const char *emptyString = "";

4295 4296
    remoteDriverLock(priv);

4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315
    args.type = (char*)type;
    /*
     * I'd think the following would work here:
     *    args.srcSpec = (char**)&srcSpec;
     * since srcSpec is a remote_string (not a remote_nonnull_string).
     *
     * But when srcSpec is NULL, this yields:
     *    libvir: Remote error : marshalling args
     *
     * So for now I'm working around this by turning NULL srcSpecs
     * into empty strings.
     */
    args.srcSpec = srcSpec ? (char **)&srcSpec : (char **)&emptyString;
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_FIND_STORAGE_POOL_SOURCES,
              (xdrproc_t) xdr_remote_find_storage_pool_sources_args, (char *) &args,
              (xdrproc_t) xdr_remote_find_storage_pool_sources_ret, (char *) &ret) == -1)
4316
        goto done;
4317

4318
    rv = ret.xml;
4319 4320 4321 4322
    ret.xml = NULL; /* To stop xdr_free free'ing it */

    xdr_free ((xdrproc_t) xdr_remote_find_storage_pool_sources_ret, (char *) &ret);

4323
done:
4324
    remoteDriverUnlock(priv);
4325
    return rv;
4326 4327
}

4328 4329 4330 4331
static virStoragePoolPtr
remoteStoragePoolLookupByUUID (virConnectPtr conn,
                               const unsigned char *uuid)
{
4332
    virStoragePoolPtr pool = NULL;
4333 4334
    remote_storage_pool_lookup_by_uuid_args args;
    remote_storage_pool_lookup_by_uuid_ret ret;
4335
    struct private_data *priv = conn->storagePrivateData;
4336

4337 4338
    remoteDriverLock(priv);

4339 4340 4341 4342 4343 4344
    memcpy (args.uuid, uuid, VIR_UUID_BUFLEN);

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_UUID,
              (xdrproc_t) xdr_remote_storage_pool_lookup_by_uuid_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_pool_lookup_by_uuid_ret, (char *) &ret) == -1)
4345
        goto done;
4346 4347 4348 4349

    pool = get_nonnull_storage_pool (conn, ret.pool);
    xdr_free ((xdrproc_t) &xdr_remote_storage_pool_lookup_by_uuid_ret, (char *) &ret);

4350
done:
4351
    remoteDriverUnlock(priv);
4352 4353 4354 4355 4356 4357 4358
    return pool;
}

static virStoragePoolPtr
remoteStoragePoolLookupByName (virConnectPtr conn,
                               const char *name)
{
4359
    virStoragePoolPtr pool = NULL;
4360 4361
    remote_storage_pool_lookup_by_name_args args;
    remote_storage_pool_lookup_by_name_ret ret;
4362
    struct private_data *priv = conn->storagePrivateData;
4363

4364 4365
    remoteDriverLock(priv);

4366 4367 4368 4369 4370 4371
    args.name = (char *) name;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_NAME,
              (xdrproc_t) xdr_remote_storage_pool_lookup_by_name_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_pool_lookup_by_name_ret, (char *) &ret) == -1)
4372
        goto done;
4373 4374 4375 4376

    pool = get_nonnull_storage_pool (conn, ret.pool);
    xdr_free ((xdrproc_t) &xdr_remote_storage_pool_lookup_by_name_ret, (char *) &ret);

4377
done:
4378
    remoteDriverUnlock(priv);
4379 4380 4381 4382 4383 4384
    return pool;
}

static virStoragePoolPtr
remoteStoragePoolLookupByVolume (virStorageVolPtr vol)
{
4385
    virStoragePoolPtr pool = NULL;
4386 4387
    remote_storage_pool_lookup_by_volume_args args;
    remote_storage_pool_lookup_by_volume_ret ret;
4388
    struct private_data *priv = vol->conn->storagePrivateData;
4389

4390 4391
    remoteDriverLock(priv);

4392 4393 4394 4395 4396 4397
    make_nonnull_storage_vol (&args.vol, vol);

    memset (&ret, 0, sizeof ret);
    if (call (vol->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_VOLUME,
              (xdrproc_t) xdr_remote_storage_pool_lookup_by_volume_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_pool_lookup_by_volume_ret, (char *) &ret) == -1)
4398
        goto done;
4399 4400 4401 4402

    pool = get_nonnull_storage_pool (vol->conn, ret.pool);
    xdr_free ((xdrproc_t) &xdr_remote_storage_pool_lookup_by_volume_ret, (char *) &ret);

4403
done:
4404
    remoteDriverUnlock(priv);
4405 4406 4407 4408 4409 4410 4411
    return pool;
}


static virStoragePoolPtr
remoteStoragePoolCreateXML (virConnectPtr conn, const char *xmlDesc, unsigned int flags)
{
4412
    virStoragePoolPtr pool = NULL;
4413 4414
    remote_storage_pool_create_xml_args args;
    remote_storage_pool_create_xml_ret ret;
4415
    struct private_data *priv = conn->storagePrivateData;
4416

4417 4418
    remoteDriverLock(priv);

4419 4420 4421 4422 4423 4424 4425
    args.xml = (char *) xmlDesc;
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_STORAGE_POOL_CREATE_XML,
              (xdrproc_t) xdr_remote_storage_pool_create_xml_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_pool_create_xml_ret, (char *) &ret) == -1)
4426
        goto done;
4427 4428 4429 4430

    pool = get_nonnull_storage_pool (conn, ret.pool);
    xdr_free ((xdrproc_t) &xdr_remote_storage_pool_create_xml_ret, (char *) &ret);

4431
done:
4432
    remoteDriverUnlock(priv);
4433 4434 4435 4436 4437 4438
    return pool;
}

static virStoragePoolPtr
remoteStoragePoolDefineXML (virConnectPtr conn, const char *xml, unsigned int flags)
{
4439
    virStoragePoolPtr pool = NULL;
4440 4441
    remote_storage_pool_define_xml_args args;
    remote_storage_pool_define_xml_ret ret;
4442
    struct private_data *priv = conn->storagePrivateData;
4443

4444 4445
    remoteDriverLock(priv);

4446 4447 4448 4449 4450 4451 4452
    args.xml = (char *) xml;
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_STORAGE_POOL_DEFINE_XML,
              (xdrproc_t) xdr_remote_storage_pool_define_xml_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_pool_define_xml_ret, (char *) &ret) == -1)
4453
        goto done;
4454 4455 4456 4457

    pool = get_nonnull_storage_pool (conn, ret.pool);
    xdr_free ((xdrproc_t) &xdr_remote_storage_pool_define_xml_ret, (char *) &ret);

4458
done:
4459
    remoteDriverUnlock(priv);
4460 4461 4462 4463 4464 4465
    return pool;
}

static int
remoteStoragePoolUndefine (virStoragePoolPtr pool)
{
4466
    int rv = -1;
4467
    remote_storage_pool_undefine_args args;
4468
    struct private_data *priv = pool->conn->storagePrivateData;
4469

4470 4471
    remoteDriverLock(priv);

4472 4473 4474 4475 4476
    make_nonnull_storage_pool (&args.pool, pool);

    if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_UNDEFINE,
              (xdrproc_t) xdr_remote_storage_pool_undefine_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
4477
        goto done;
4478

4479 4480 4481
    rv = 0;

done:
4482
    remoteDriverUnlock(priv);
4483
    return rv;
4484 4485 4486 4487 4488
}

static int
remoteStoragePoolCreate (virStoragePoolPtr pool, unsigned int flags)
{
4489
    int rv = -1;
4490
    remote_storage_pool_create_args args;
4491
    struct private_data *priv = pool->conn->storagePrivateData;
4492

4493 4494
    remoteDriverLock(priv);

4495 4496 4497 4498 4499 4500
    make_nonnull_storage_pool (&args.pool, pool);
    args.flags = flags;

    if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_CREATE,
              (xdrproc_t) xdr_remote_storage_pool_create_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
4501
        goto done;
4502

4503 4504 4505
    rv = 0;

done:
4506
    remoteDriverUnlock(priv);
4507
    return rv;
4508 4509 4510 4511 4512 4513
}

static int
remoteStoragePoolBuild (virStoragePoolPtr pool,
                        unsigned int flags)
{
4514
    int rv = -1;
4515
    remote_storage_pool_build_args args;
4516
    struct private_data *priv = pool->conn->storagePrivateData;
4517

4518 4519
    remoteDriverLock(priv);

4520 4521 4522 4523 4524 4525
    make_nonnull_storage_pool (&args.pool, pool);
    args.flags = flags;

    if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_BUILD,
              (xdrproc_t) xdr_remote_storage_pool_build_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
4526
        goto done;
4527

4528 4529 4530
    rv = 0;

done:
4531
    remoteDriverUnlock(priv);
4532
    return rv;
4533 4534 4535 4536 4537
}

static int
remoteStoragePoolDestroy (virStoragePoolPtr pool)
{
4538
    int rv = -1;
4539
    remote_storage_pool_destroy_args args;
4540
    struct private_data *priv = pool->conn->storagePrivateData;
4541

4542 4543
    remoteDriverLock(priv);

4544 4545 4546 4547 4548
    make_nonnull_storage_pool (&args.pool, pool);

    if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_DESTROY,
              (xdrproc_t) xdr_remote_storage_pool_destroy_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
4549
        goto done;
4550

4551 4552 4553
    rv = 0;

done:
4554
    remoteDriverUnlock(priv);
4555
    return rv;
4556 4557 4558 4559 4560 4561
}

static int
remoteStoragePoolDelete (virStoragePoolPtr pool,
                         unsigned int flags)
{
4562
    int rv = -1;
4563
    remote_storage_pool_delete_args args;
4564
    struct private_data *priv = pool->conn->storagePrivateData;
4565

4566 4567
    remoteDriverLock(priv);

4568 4569 4570 4571 4572 4573
    make_nonnull_storage_pool (&args.pool, pool);
    args.flags = flags;

    if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_DELETE,
              (xdrproc_t) xdr_remote_storage_pool_delete_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
4574
        goto done;
4575

4576 4577 4578
    rv = 0;

done:
4579
    remoteDriverUnlock(priv);
4580
    return rv;
4581 4582 4583 4584 4585 4586
}

static int
remoteStoragePoolRefresh (virStoragePoolPtr pool,
                          unsigned int flags)
{
4587
    int rv = -1;
4588
    remote_storage_pool_refresh_args args;
4589
    struct private_data *priv = pool->conn->storagePrivateData;
4590

4591 4592
    remoteDriverLock(priv);

4593 4594 4595 4596 4597 4598
    make_nonnull_storage_pool (&args.pool, pool);
    args.flags = flags;

    if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_REFRESH,
              (xdrproc_t) xdr_remote_storage_pool_refresh_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
4599
        goto done;
4600

4601 4602 4603
    rv = 0;

done:
4604
    remoteDriverUnlock(priv);
4605
    return rv;
4606 4607 4608 4609 4610
}

static int
remoteStoragePoolGetInfo (virStoragePoolPtr pool, virStoragePoolInfoPtr info)
{
4611
    int rv = -1;
4612 4613
    remote_storage_pool_get_info_args args;
    remote_storage_pool_get_info_ret ret;
4614
    struct private_data *priv = pool->conn->storagePrivateData;
4615

4616 4617
    remoteDriverLock(priv);

4618 4619 4620 4621 4622 4623
    make_nonnull_storage_pool (&args.pool, pool);

    memset (&ret, 0, sizeof ret);
    if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_GET_INFO,
              (xdrproc_t) xdr_remote_storage_pool_get_info_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_pool_get_info_ret, (char *) &ret) == -1)
4624
        goto done;
4625 4626 4627 4628 4629 4630

    info->state = ret.state;
    info->capacity = ret.capacity;
    info->allocation = ret.allocation;
    info->available = ret.available;

4631 4632 4633
    rv = 0;

done:
4634
    remoteDriverUnlock(priv);
4635
    return rv;
4636 4637 4638 4639 4640 4641
}

static char *
remoteStoragePoolDumpXML (virStoragePoolPtr pool,
                          unsigned int flags)
{
4642
    char *rv = NULL;
4643 4644
    remote_storage_pool_dump_xml_args args;
    remote_storage_pool_dump_xml_ret ret;
4645
    struct private_data *priv = pool->conn->storagePrivateData;
4646

4647 4648
    remoteDriverLock(priv);

4649 4650 4651 4652 4653 4654 4655
    make_nonnull_storage_pool (&args.pool, pool);
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_DUMP_XML,
              (xdrproc_t) xdr_remote_storage_pool_dump_xml_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_pool_dump_xml_ret, (char *) &ret) == -1)
4656
        goto done;
4657 4658

    /* Caller frees. */
4659 4660 4661
    rv = ret.xml;

done:
4662
    remoteDriverUnlock(priv);
4663
    return rv;
4664 4665 4666 4667 4668
}

static int
remoteStoragePoolGetAutostart (virStoragePoolPtr pool, int *autostart)
{
4669
    int rv = -1;
4670 4671
    remote_storage_pool_get_autostart_args args;
    remote_storage_pool_get_autostart_ret ret;
4672
    struct private_data *priv = pool->conn->storagePrivateData;
4673

4674 4675
    remoteDriverLock(priv);

4676 4677 4678 4679 4680 4681
    make_nonnull_storage_pool (&args.pool, pool);

    memset (&ret, 0, sizeof ret);
    if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_GET_AUTOSTART,
              (xdrproc_t) xdr_remote_storage_pool_get_autostart_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_pool_get_autostart_ret, (char *) &ret) == -1)
4682
        goto done;
4683 4684 4685

    if (autostart) *autostart = ret.autostart;

4686 4687 4688
    rv = 0;

done:
4689
    remoteDriverUnlock(priv);
4690
    return rv;
4691 4692 4693 4694 4695
}

static int
remoteStoragePoolSetAutostart (virStoragePoolPtr pool, int autostart)
{
4696
    int rv = -1;
4697
    remote_storage_pool_set_autostart_args args;
4698
    struct private_data *priv = pool->conn->storagePrivateData;
4699

4700 4701
    remoteDriverLock(priv);

4702 4703 4704 4705 4706 4707
    make_nonnull_storage_pool (&args.pool, pool);
    args.autostart = autostart;

    if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_SET_AUTOSTART,
              (xdrproc_t) xdr_remote_storage_pool_set_autostart_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
4708
        goto done;
4709

4710 4711 4712
    rv = 0;

done:
4713
    remoteDriverUnlock(priv);
4714
    return rv;
4715 4716 4717 4718 4719 4720
}


static int
remoteStoragePoolNumOfVolumes (virStoragePoolPtr pool)
{
4721
    int rv = -1;
4722 4723
    remote_storage_pool_num_of_volumes_args args;
    remote_storage_pool_num_of_volumes_ret ret;
4724
    struct private_data *priv = pool->conn->storagePrivateData;
4725

4726 4727
    remoteDriverLock(priv);

4728 4729 4730 4731 4732 4733
    make_nonnull_storage_pool(&args.pool, pool);

    memset (&ret, 0, sizeof ret);
    if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_NUM_OF_VOLUMES,
              (xdrproc_t) xdr_remote_storage_pool_num_of_volumes_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_pool_num_of_volumes_ret, (char *) &ret) == -1)
4734 4735 4736
        goto done;

    rv = ret.num;
4737

4738
done:
4739
    remoteDriverUnlock(priv);
4740
    return rv;
4741 4742 4743 4744 4745
}

static int
remoteStoragePoolListVolumes (virStoragePoolPtr pool, char **const names, int maxnames)
{
4746
    int rv = -1;
4747 4748 4749
    int i;
    remote_storage_pool_list_volumes_args args;
    remote_storage_pool_list_volumes_ret ret;
4750
    struct private_data *priv = pool->conn->storagePrivateData;
4751

4752 4753
    remoteDriverLock(priv);

4754 4755
    if (maxnames > REMOTE_STORAGE_VOL_NAME_LIST_MAX) {
        error (pool->conn, VIR_ERR_RPC, _("too many storage volumes requested"));
4756
        goto done;
4757 4758 4759 4760 4761 4762 4763 4764
    }
    args.maxnames = maxnames;
    make_nonnull_storage_pool(&args.pool, pool);

    memset (&ret, 0, sizeof ret);
    if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_POOL_LIST_VOLUMES,
              (xdrproc_t) xdr_remote_storage_pool_list_volumes_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_pool_list_volumes_ret, (char *) &ret) == -1)
4765
        goto done;
4766 4767 4768

    if (ret.names.names_len > maxnames) {
        error (pool->conn, VIR_ERR_RPC, _("too many storage volumes received"));
4769
        goto cleanup;
4770 4771 4772 4773 4774 4775 4776 4777 4778 4779
    }

    /* This call is caller-frees (although that isn't clear from
     * the documentation).  However xdr_free will free up both the
     * names and the list of pointers, so we have to strdup the
     * names here.
     */
    for (i = 0; i < ret.names.names_len; ++i)
        names[i] = strdup (ret.names.names_val[i]);

4780 4781 4782
    rv = ret.names.names_len;

cleanup:
4783 4784
    xdr_free ((xdrproc_t) xdr_remote_storage_pool_list_volumes_ret, (char *) &ret);

4785
done:
4786
    remoteDriverUnlock(priv);
4787
    return rv;
4788 4789 4790 4791 4792 4793 4794 4795
}



static virStorageVolPtr
remoteStorageVolLookupByName (virStoragePoolPtr pool,
                              const char *name)
{
4796
    virStorageVolPtr vol = NULL;
4797 4798
    remote_storage_vol_lookup_by_name_args args;
    remote_storage_vol_lookup_by_name_ret ret;
4799
    struct private_data *priv = pool->conn->storagePrivateData;
4800

4801 4802
    remoteDriverLock(priv);

4803 4804 4805 4806 4807 4808 4809
    make_nonnull_storage_pool(&args.pool, pool);
    args.name = (char *) name;

    memset (&ret, 0, sizeof ret);
    if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_NAME,
              (xdrproc_t) xdr_remote_storage_vol_lookup_by_name_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_vol_lookup_by_name_ret, (char *) &ret) == -1)
4810
        goto done;
4811 4812 4813 4814

    vol = get_nonnull_storage_vol (pool->conn, ret.vol);
    xdr_free ((xdrproc_t) &xdr_remote_storage_vol_lookup_by_name_ret, (char *) &ret);

4815
done:
4816
    remoteDriverUnlock(priv);
4817 4818 4819 4820 4821 4822 4823
    return vol;
}

static virStorageVolPtr
remoteStorageVolLookupByKey (virConnectPtr conn,
                             const char *key)
{
4824
    virStorageVolPtr  vol = NULL;
4825 4826
    remote_storage_vol_lookup_by_key_args args;
    remote_storage_vol_lookup_by_key_ret ret;
4827
    struct private_data *priv = conn->storagePrivateData;
4828

4829 4830
    remoteDriverLock(priv);

4831 4832 4833 4834 4835 4836
    args.key = (char *) key;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_KEY,
              (xdrproc_t) xdr_remote_storage_vol_lookup_by_key_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_vol_lookup_by_key_ret, (char *) &ret) == -1)
4837
        goto done;
4838 4839 4840 4841

    vol = get_nonnull_storage_vol (conn, ret.vol);
    xdr_free ((xdrproc_t) &xdr_remote_storage_vol_lookup_by_key_ret, (char *) &ret);

4842
done:
4843
    remoteDriverUnlock(priv);
4844 4845 4846 4847 4848 4849 4850
    return vol;
}

static virStorageVolPtr
remoteStorageVolLookupByPath (virConnectPtr conn,
                              const char *path)
{
4851
    virStorageVolPtr vol = NULL;
4852 4853
    remote_storage_vol_lookup_by_path_args args;
    remote_storage_vol_lookup_by_path_ret ret;
4854
    struct private_data *priv = conn->storagePrivateData;
4855

4856 4857
    remoteDriverLock(priv);

4858 4859 4860 4861 4862 4863
    args.path = (char *) path;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_PATH,
              (xdrproc_t) xdr_remote_storage_vol_lookup_by_path_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_vol_lookup_by_path_ret, (char *) &ret) == -1)
4864
        goto done;
4865 4866 4867 4868

    vol = get_nonnull_storage_vol (conn, ret.vol);
    xdr_free ((xdrproc_t) &xdr_remote_storage_vol_lookup_by_path_ret, (char *) &ret);

4869
done:
4870
    remoteDriverUnlock(priv);
4871 4872 4873 4874 4875 4876 4877
    return vol;
}

static virStorageVolPtr
remoteStorageVolCreateXML (virStoragePoolPtr pool, const char *xmlDesc,
                           unsigned int flags)
{
4878
    virStorageVolPtr vol = NULL;
4879 4880
    remote_storage_vol_create_xml_args args;
    remote_storage_vol_create_xml_ret ret;
4881
    struct private_data *priv = pool->conn->storagePrivateData;
4882

4883 4884
    remoteDriverLock(priv);

4885 4886 4887 4888 4889 4890 4891 4892
    make_nonnull_storage_pool (&args.pool, pool);
    args.xml = (char *) xmlDesc;
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_VOL_CREATE_XML,
              (xdrproc_t) xdr_remote_storage_vol_create_xml_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_vol_create_xml_ret, (char *) &ret) == -1)
4893
        goto done;
4894 4895 4896 4897

    vol = get_nonnull_storage_vol (pool->conn, ret.vol);
    xdr_free ((xdrproc_t) &xdr_remote_storage_vol_create_xml_ret, (char *) &ret);

4898
done:
4899
    remoteDriverUnlock(priv);
4900 4901 4902
    return vol;
}

4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934
static virStorageVolPtr
remoteStorageVolCreateXMLFrom (virStoragePoolPtr pool,
                               const char *xmlDesc,
                               virStorageVolPtr clonevol,
                               unsigned int flags)
{
    virStorageVolPtr newvol = NULL;
    remote_storage_vol_create_xml_from_args args;
    remote_storage_vol_create_xml_from_ret ret;
    struct private_data *priv = pool->conn->storagePrivateData;

    remoteDriverLock(priv);

    make_nonnull_storage_pool (&args.pool, pool);
    make_nonnull_storage_vol (&args.clonevol, clonevol);
    args.xml = (char *) xmlDesc;
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (pool->conn, priv, 0, REMOTE_PROC_STORAGE_VOL_CREATE_XML_FROM,
              (xdrproc_t) xdr_remote_storage_vol_create_xml_from_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_vol_create_xml_from_ret, (char *) &ret) == -1)
        goto done;

    newvol = get_nonnull_storage_vol (pool->conn, ret.vol);
    xdr_free ((xdrproc_t) &xdr_remote_storage_vol_create_xml_from_ret, (char *) &ret);

done:
    remoteDriverUnlock(priv);
    return newvol;
}

4935 4936 4937 4938
static int
remoteStorageVolDelete (virStorageVolPtr vol,
                        unsigned int flags)
{
4939
    int rv = -1;
4940
    remote_storage_vol_delete_args args;
4941
    struct private_data *priv = vol->conn->storagePrivateData;
4942

4943 4944
    remoteDriverLock(priv);

4945 4946 4947 4948 4949 4950
    make_nonnull_storage_vol (&args.vol, vol);
    args.flags = flags;

    if (call (vol->conn, priv, 0, REMOTE_PROC_STORAGE_VOL_DELETE,
              (xdrproc_t) xdr_remote_storage_vol_delete_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
4951
        goto done;
4952

4953 4954 4955
    rv = 0;

done:
4956
    remoteDriverUnlock(priv);
4957
    return rv;
4958 4959 4960 4961 4962
}

static int
remoteStorageVolGetInfo (virStorageVolPtr vol, virStorageVolInfoPtr info)
{
4963
    int rv = -1;
4964 4965
    remote_storage_vol_get_info_args args;
    remote_storage_vol_get_info_ret ret;
4966
    struct private_data *priv = vol->conn->storagePrivateData;
4967

4968 4969
    remoteDriverLock(priv);

4970 4971 4972 4973 4974 4975
    make_nonnull_storage_vol (&args.vol, vol);

    memset (&ret, 0, sizeof ret);
    if (call (vol->conn, priv, 0, REMOTE_PROC_STORAGE_VOL_GET_INFO,
              (xdrproc_t) xdr_remote_storage_vol_get_info_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_vol_get_info_ret, (char *) &ret) == -1)
4976
        goto done;
4977 4978 4979 4980 4981

    info->type = ret.type;
    info->capacity = ret.capacity;
    info->allocation = ret.allocation;

4982 4983 4984
    rv = 0;

done:
4985
    remoteDriverUnlock(priv);
4986
    return rv;
4987 4988 4989 4990 4991 4992
}

static char *
remoteStorageVolDumpXML (virStorageVolPtr vol,
                         unsigned int flags)
{
4993
    char *rv = NULL;
4994 4995
    remote_storage_vol_dump_xml_args args;
    remote_storage_vol_dump_xml_ret ret;
4996
    struct private_data *priv = vol->conn->storagePrivateData;
4997

4998 4999
    remoteDriverLock(priv);

5000 5001 5002 5003 5004 5005 5006
    make_nonnull_storage_vol (&args.vol, vol);
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (vol->conn, priv, 0, REMOTE_PROC_STORAGE_VOL_DUMP_XML,
              (xdrproc_t) xdr_remote_storage_vol_dump_xml_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_vol_dump_xml_ret, (char *) &ret) == -1)
5007
        goto done;
5008 5009

    /* Caller frees. */
5010 5011 5012
    rv = ret.xml;

done:
5013
    remoteDriverUnlock(priv);
5014
    return rv;
5015 5016 5017 5018 5019
}

static char *
remoteStorageVolGetPath (virStorageVolPtr vol)
{
5020
    char *rv = NULL;
5021 5022
    remote_storage_vol_get_path_args args;
    remote_storage_vol_get_path_ret ret;
5023
    struct private_data *priv = vol->conn->storagePrivateData;
5024

5025 5026
    remoteDriverLock(priv);

5027 5028 5029 5030 5031 5032
    make_nonnull_storage_vol (&args.vol, vol);

    memset (&ret, 0, sizeof ret);
    if (call (vol->conn, priv, 0, REMOTE_PROC_STORAGE_VOL_GET_PATH,
              (xdrproc_t) xdr_remote_storage_vol_get_path_args, (char *) &args,
              (xdrproc_t) xdr_remote_storage_vol_get_path_ret, (char *) &ret) == -1)
5033
        goto done;
5034 5035

    /* Caller frees. */
5036 5037 5038
    rv = ret.name;

done:
5039
    remoteDriverUnlock(priv);
5040
    return rv;
5041 5042 5043
}


5044 5045 5046 5047 5048 5049 5050
/*----------------------------------------------------------------------*/

static virDrvOpenStatus
remoteDevMonOpen(virConnectPtr conn,
                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                 int flags ATTRIBUTE_UNUSED)
{
5051 5052 5053
    if (inside_daemon)
        return VIR_DRV_OPEN_DECLINED;

5054 5055 5056
    if (conn &&
        conn->driver &&
        STREQ (conn->driver->name, "remote")) {
5057
        struct private_data *priv = conn->privateData;
5058 5059 5060 5061
        /* If we're here, the remote driver is already
         * in use due to a) a QEMU uri, or b) a remote
         * URI. So we can re-use existing connection
         */
5062 5063 5064 5065
        remoteDriverLock(priv);
        priv->localUses++;
        conn->devMonPrivateData = priv;
        remoteDriverUnlock(priv);
5066
        return VIR_DRV_OPEN_SUCCESS;
5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081
    } else if (conn->networkDriver &&
               STREQ (conn->networkDriver->name, "remote")) {
        struct private_data *priv = conn->networkPrivateData;
        remoteDriverLock(priv);
        conn->devMonPrivateData = priv;
        priv->localUses++;
        remoteDriverUnlock(priv);
        return VIR_DRV_OPEN_SUCCESS;
    } else {
        /* Using a non-remote driver, so we need to open a
         * new connection for network APIs, forcing it to
         * use the UNIX transport. This handles Xen driver
         * which doesn't have its own impl of the network APIs.
         */
        struct private_data *priv;
5082 5083 5084 5085 5086 5087
        int ret;
        ret = remoteOpenSecondaryDriver(conn,
                                        auth,
                                        flags,
                                        &priv);
        if (ret == VIR_DRV_OPEN_SUCCESS)
5088 5089 5090
            conn->devMonPrivateData = priv;
        return ret;
    }
5091 5092 5093 5094 5095
}

static int remoteDevMonClose(virConnectPtr conn)
{
    int ret = 0;
5096 5097
    struct private_data *priv = conn->devMonPrivateData;

5098 5099 5100 5101 5102 5103 5104 5105
    remoteDriverLock(priv);
    priv->localUses--;
    if (!priv->localUses) {
        ret = doRemoteClose(conn, priv);
        conn->devMonPrivateData = NULL;
        remoteDriverUnlock(priv);
        virMutexDestroy(&priv->lock);
        VIR_FREE(priv);
5106
    }
5107 5108
    if (priv)
        remoteDriverUnlock(priv);
5109 5110 5111 5112 5113 5114 5115
    return ret;
}

static int remoteNodeNumOfDevices(virConnectPtr conn,
                                  const char *cap,
                                  unsigned int flags)
{
5116
    int rv = -1;
5117 5118
    remote_node_num_of_devices_args args;
    remote_node_num_of_devices_ret ret;
5119
    struct private_data *priv = conn->devMonPrivateData;
5120

5121 5122
    remoteDriverLock(priv);

5123 5124 5125 5126 5127 5128 5129
    args.cap = cap ? (char **)&cap : NULL;
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NODE_NUM_OF_DEVICES,
              (xdrproc_t) xdr_remote_node_num_of_devices_args, (char *) &args,
              (xdrproc_t) xdr_remote_node_num_of_devices_ret, (char *) &ret) == -1)
5130 5131 5132
        goto done;

    rv = ret.num;
5133

5134
done:
5135
    remoteDriverUnlock(priv);
5136
    return rv;
5137 5138 5139 5140 5141 5142 5143 5144 5145
}


static int remoteNodeListDevices(virConnectPtr conn,
                                 const char *cap,
                                 char **const names,
                                 int maxnames,
                                 unsigned int flags)
{
5146
    int rv = -1;
5147 5148 5149
    int i;
    remote_node_list_devices_args args;
    remote_node_list_devices_ret ret;
5150
    struct private_data *priv = conn->devMonPrivateData;
5151

5152 5153
    remoteDriverLock(priv);

5154 5155
    if (maxnames > REMOTE_NODE_DEVICE_NAME_LIST_MAX) {
        error (conn, VIR_ERR_RPC, _("too many device names requested"));
5156
        goto done;
5157 5158 5159 5160 5161 5162 5163 5164 5165
    }
    args.cap = cap ? (char **)&cap : NULL;
    args.maxnames = maxnames;
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NODE_LIST_DEVICES,
              (xdrproc_t) xdr_remote_node_list_devices_args, (char *) &args,
              (xdrproc_t) xdr_remote_node_list_devices_ret, (char *) &ret) == -1)
5166
        goto done;
5167 5168 5169

    if (ret.names.names_len > maxnames) {
        error (conn, VIR_ERR_RPC, _("too many device names received"));
5170
        goto cleanup;
5171 5172 5173 5174 5175 5176 5177 5178 5179 5180
    }

    /* This call is caller-frees (although that isn't clear from
     * the documentation).  However xdr_free will free up both the
     * names and the list of pointers, so we have to strdup the
     * names here.
     */
    for (i = 0; i < ret.names.names_len; ++i)
        names[i] = strdup (ret.names.names_val[i]);

5181 5182 5183
    rv = ret.names.names_len;

cleanup:
5184 5185
    xdr_free ((xdrproc_t) xdr_remote_node_list_devices_ret, (char *) &ret);

5186
done:
5187
    remoteDriverUnlock(priv);
5188
    return rv;
5189 5190 5191 5192 5193 5194 5195 5196
}


static virNodeDevicePtr remoteNodeDeviceLookupByName(virConnectPtr conn,
                                                     const char *name)
{
    remote_node_device_lookup_by_name_args args;
    remote_node_device_lookup_by_name_ret ret;
5197
    virNodeDevicePtr dev = NULL;
5198
    struct private_data *priv = conn->devMonPrivateData;
5199

5200 5201
    remoteDriverLock(priv);

5202 5203 5204 5205 5206 5207
    args.name = (char *)name;

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, 0, REMOTE_PROC_NODE_DEVICE_LOOKUP_BY_NAME,
              (xdrproc_t) xdr_remote_node_device_lookup_by_name_args, (char *) &args,
              (xdrproc_t) xdr_remote_node_device_lookup_by_name_ret, (char *) &ret) == -1)
5208
        goto done;
5209 5210 5211 5212 5213

    dev = get_nonnull_node_device(conn, ret.dev);

    xdr_free ((xdrproc_t) xdr_remote_node_device_lookup_by_name_ret, (char *) &ret);

5214
done:
5215
    remoteDriverUnlock(priv);
5216 5217 5218 5219 5220 5221
    return dev;
}

static char *remoteNodeDeviceDumpXML(virNodeDevicePtr dev,
                                     unsigned int flags)
{
5222
    char *rv = NULL;
5223 5224
    remote_node_device_dump_xml_args args;
    remote_node_device_dump_xml_ret ret;
5225
    struct private_data *priv = dev->conn->devMonPrivateData;
5226

5227 5228
    remoteDriverLock(priv);

5229 5230 5231 5232 5233 5234 5235
    args.name = dev->name;
    args.flags = flags;

    memset (&ret, 0, sizeof ret);
    if (call (dev->conn, priv, 0, REMOTE_PROC_NODE_DEVICE_DUMP_XML,
              (xdrproc_t) xdr_remote_node_device_dump_xml_args, (char *) &args,
              (xdrproc_t) xdr_remote_node_device_dump_xml_ret, (char *) &ret) == -1)
5236
        goto done;
5237 5238

    /* Caller frees. */
5239 5240 5241
    rv = ret.xml;

done:
5242
    remoteDriverUnlock(priv);
5243
    return rv;
5244 5245 5246 5247
}

static char *remoteNodeDeviceGetParent(virNodeDevicePtr dev)
{
5248
    char *rv = NULL;
5249 5250
    remote_node_device_get_parent_args args;
    remote_node_device_get_parent_ret ret;
5251
    struct private_data *priv = dev->conn->devMonPrivateData;
5252

5253 5254
    remoteDriverLock(priv);

5255 5256 5257 5258 5259 5260
    args.name = dev->name;

    memset (&ret, 0, sizeof ret);
    if (call (dev->conn, priv, 0, REMOTE_PROC_NODE_DEVICE_GET_PARENT,
              (xdrproc_t) xdr_remote_node_device_get_parent_args, (char *) &args,
              (xdrproc_t) xdr_remote_node_device_get_parent_ret, (char *) &ret) == -1)
5261
        goto done;
5262 5263

    /* Caller frees. */
5264
    rv = ret.parent ? *ret.parent : NULL;
5265
    VIR_FREE(ret.parent);
5266 5267

done:
5268
    remoteDriverUnlock(priv);
5269
    return rv;
5270 5271 5272 5273
}

static int remoteNodeDeviceNumOfCaps(virNodeDevicePtr dev)
{
5274
    int rv = -1;
5275 5276
    remote_node_device_num_of_caps_args args;
    remote_node_device_num_of_caps_ret ret;
5277
    struct private_data *priv = dev->conn->devMonPrivateData;
5278

5279 5280
    remoteDriverLock(priv);

5281 5282 5283 5284 5285 5286
    args.name = dev->name;

    memset (&ret, 0, sizeof ret);
    if (call (dev->conn, priv, 0, REMOTE_PROC_NODE_DEVICE_NUM_OF_CAPS,
              (xdrproc_t) xdr_remote_node_device_num_of_caps_args, (char *) &args,
              (xdrproc_t) xdr_remote_node_device_num_of_caps_ret, (char *) &ret) == -1)
5287 5288 5289
        goto done;

    rv = ret.num;
5290

5291
done:
5292
    remoteDriverUnlock(priv);
5293
    return rv;
5294 5295 5296 5297 5298 5299
}

static int remoteNodeDeviceListCaps(virNodeDevicePtr dev,
                                    char **const names,
                                    int maxnames)
{
5300
    int rv = -1;
5301 5302 5303
    int i;
    remote_node_device_list_caps_args args;
    remote_node_device_list_caps_ret ret;
5304
    struct private_data *priv = dev->conn->devMonPrivateData;
5305

5306 5307
    remoteDriverLock(priv);

5308 5309
    if (maxnames > REMOTE_NODE_DEVICE_CAPS_LIST_MAX) {
        error (dev->conn, VIR_ERR_RPC, _("too many capability names requested"));
5310
        goto done;
5311 5312 5313 5314 5315 5316 5317 5318
    }
    args.maxnames = maxnames;
    args.name = dev->name;

    memset (&ret, 0, sizeof ret);
    if (call (dev->conn, priv, 0, REMOTE_PROC_NODE_DEVICE_LIST_CAPS,
              (xdrproc_t) xdr_remote_node_device_list_caps_args, (char *) &args,
              (xdrproc_t) xdr_remote_node_device_list_caps_ret, (char *) &ret) == -1)
5319
        goto done;
5320 5321 5322

    if (ret.names.names_len > maxnames) {
        error (dev->conn, VIR_ERR_RPC, _("too many capability names received"));
5323
        goto cleanup;
5324 5325 5326 5327 5328 5329 5330 5331 5332 5333
    }

    /* This call is caller-frees (although that isn't clear from
     * the documentation).  However xdr_free will free up both the
     * names and the list of pointers, so we have to strdup the
     * names here.
     */
    for (i = 0; i < ret.names.names_len; ++i)
        names[i] = strdup (ret.names.names_val[i]);

5334 5335 5336
    rv = ret.names.names_len;

cleanup:
5337 5338
    xdr_free ((xdrproc_t) xdr_remote_node_device_list_caps_ret, (char *) &ret);

5339
done:
5340
    remoteDriverUnlock(priv);
5341
    return rv;
5342 5343
}

5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412
static int
remoteNodeDeviceDettach (virNodeDevicePtr dev)
{
    int rv = -1;
    remote_node_device_dettach_args args;
    struct private_data *priv = dev->conn->privateData;

    remoteDriverLock(priv);

    args.name = dev->name;

    if (call (dev->conn, priv, 0, REMOTE_PROC_NODE_DEVICE_DETTACH,
              (xdrproc_t) xdr_remote_node_device_dettach_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
        goto done;

    rv = 0;

done:
    remoteDriverUnlock(priv);
    return rv;
}

static int
remoteNodeDeviceReAttach (virNodeDevicePtr dev)
{
    int rv = -1;
    remote_node_device_re_attach_args args;
    struct private_data *priv = dev->conn->privateData;

    remoteDriverLock(priv);

    args.name = dev->name;

    if (call (dev->conn, priv, 0, REMOTE_PROC_NODE_DEVICE_RE_ATTACH,
              (xdrproc_t) xdr_remote_node_device_re_attach_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
        goto done;

    rv = 0;

done:
    remoteDriverUnlock(priv);
    return rv;
}

static int
remoteNodeDeviceReset (virNodeDevicePtr dev)
{
    int rv = -1;
    remote_node_device_reset_args args;
    struct private_data *priv = dev->conn->privateData;

    remoteDriverLock(priv);

    args.name = dev->name;

    if (call (dev->conn, priv, 0, REMOTE_PROC_NODE_DEVICE_RESET,
              (xdrproc_t) xdr_remote_node_device_reset_args, (char *) &args,
              (xdrproc_t) xdr_void, (char *) NULL) == -1)
        goto done;

    rv = 0;

done:
    remoteDriverUnlock(priv);
    return rv;
}

5413

5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453
static virNodeDevicePtr
remoteNodeDeviceCreateXML(virConnectPtr conn,
                          const char *xmlDesc,
                          unsigned int flags)
{
    remote_node_device_create_xml_args args;
    remote_node_device_create_xml_ret ret;
    virNodeDevicePtr dev = NULL;
    struct private_data *priv = conn->privateData;

    remoteDriverLock(priv);

    memset(&ret, 0, sizeof ret);
    args.xml_desc = (char *)xmlDesc;
    args.flags = flags;

    if (call(conn, priv, 0, REMOTE_PROC_NODE_DEVICE_CREATE_XML,
             (xdrproc_t) xdr_remote_node_device_create_xml_args, (char *) &args,
             (xdrproc_t) xdr_remote_node_device_create_xml_ret, (char *) &ret) == -1)
        goto done;

    dev = get_nonnull_node_device(conn, ret.dev);
    xdr_free ((xdrproc_t) xdr_remote_node_device_create_xml_ret, (char *) &ret);

done:
    remoteDriverUnlock(priv);
    return dev;
}

static int
remoteNodeDeviceDestroy(virNodeDevicePtr dev)
{
    int rv = -1;
    remote_node_device_destroy_args args;
    struct private_data *priv = dev->conn->privateData;

    remoteDriverLock(priv);

    args.name = dev->name;

5454
    if (call(dev->conn, priv, 0, REMOTE_PROC_NODE_DEVICE_DESTROY,
5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466
             (xdrproc_t) xdr_remote_node_device_destroy_args, (char *) &args,
             (xdrproc_t) xdr_void, (char *) NULL) == -1)
        goto done;

    rv = 0;

done:
    remoteDriverUnlock(priv);
    return rv;
}


5467 5468
/*----------------------------------------------------------------------*/

5469
static int
5470
remoteAuthenticate (virConnectPtr conn, struct private_data *priv, int in_open,
5471 5472 5473 5474 5475 5476
                    virConnectAuthPtr auth
#if !HAVE_SASL && !HAVE_POLKIT
                    ATTRIBUTE_UNUSED
#endif
                    ,
                    const char *authtype)
5477 5478
{
    struct remote_auth_list_ret ret;
5479
    int err, type = REMOTE_AUTH_NONE;
5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495

    memset(&ret, 0, sizeof ret);
    err = call (conn, priv,
                REMOTE_CALL_IN_OPEN | REMOTE_CALL_QUIET_MISSING_RPC,
                REMOTE_PROC_AUTH_LIST,
                (xdrproc_t) xdr_void, (char *) NULL,
                (xdrproc_t) xdr_remote_auth_list_ret, (char *) &ret);
    if (err == -2) /* Missing RPC - old server - ignore */
        return 0;

    if (err < 0)
        return -1;

    if (ret.types.types_len == 0)
        return 0;

5496 5497 5498 5499 5500 5501 5502 5503
    if (authtype) {
        int want, i;
        if (STRCASEEQ(authtype, "sasl") ||
            STRCASEEQLEN(authtype, "sasl.", 5)) {
            want = REMOTE_AUTH_SASL;
        } else if (STRCASEEQ(authtype, "polkit")) {
            want = REMOTE_AUTH_POLKIT;
        } else {
5504
            virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
5505 5506 5507
                             VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR,
                             NULL, NULL, NULL, 0, 0,
                             _("unknown authentication type %s"), authtype);
5508 5509 5510 5511 5512 5513 5514
            return -1;
        }
        for (i = 0 ; i < ret.types.types_len ; i++) {
            if (ret.types.types_val[i] == want)
                type = want;
        }
        if (type == REMOTE_AUTH_NONE) {
5515
            virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
5516
                             VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
5517 5518
                             _("requested authentication type %s rejected"),
                             authtype);
5519 5520 5521 5522 5523 5524 5525
            return -1;
        }
    } else {
        type = ret.types.types_val[0];
    }

    switch (type) {
5526
#if HAVE_SASL
5527 5528 5529 5530 5531 5532 5533
    case REMOTE_AUTH_SASL: {
        const char *mech = NULL;
        if (authtype &&
            STRCASEEQLEN(authtype, "sasl.", 5))
            mech = authtype + 5;

        if (remoteAuthSASL(conn, priv, in_open, auth, mech) < 0) {
5534
            VIR_FREE(ret.types.types_val);
5535 5536 5537
            return -1;
        }
        break;
5538
    }
5539 5540
#endif

5541 5542
#if HAVE_POLKIT
    case REMOTE_AUTH_POLKIT:
5543
        if (remoteAuthPolkit(conn, priv, in_open, auth) < 0) {
5544
            VIR_FREE(ret.types.types_val);
5545 5546 5547 5548 5549
            return -1;
        }
        break;
#endif

5550 5551 5552 5553 5554
    case REMOTE_AUTH_NONE:
        /* Nothing todo, hurrah ! */
        break;

    default:
5555
        virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
5556 5557 5558 5559
                         VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR,
                         NULL, NULL, NULL, 0, 0,
                         _("unsupported authentication type %d"),
                         ret.types.types_val[0]);
5560
        VIR_FREE(ret.types.types_val);
5561 5562 5563
        return -1;
    }

5564
    VIR_FREE(ret.types.types_val);
5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584

    return 0;
}



#if HAVE_SASL
/*
 * NB, keep in sync with similar method in qemud/remote.c
 */
static char *addrToString(struct sockaddr_storage *sa, socklen_t salen)
{
    char host[NI_MAXHOST], port[NI_MAXSERV];
    char *addr;
    int err;

    if ((err = getnameinfo((struct sockaddr *)sa, salen,
                           host, sizeof(host),
                           port, sizeof(port),
                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
5585
        virRaiseError (NULL, NULL, NULL, VIR_FROM_REMOTE,
5586 5587 5588 5589
                       VIR_ERR_UNKNOWN_HOST, VIR_ERR_ERROR,
                       NULL, NULL, NULL, 0, 0,
                       _("Cannot resolve address %d: %s"),
                       err, gai_strerror(err));
5590 5591 5592
        return NULL;
    }

5593 5594
    if (virAsprintf(&addr, "%s;%s", host, port) == -1) {
        virReportOOMError(NULL);
5595 5596 5597 5598 5599 5600 5601
        return NULL;
    }

    return addr;
}


5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679
static int remoteAuthCredVir2SASL(int vircred)
{
    switch (vircred) {
    case VIR_CRED_USERNAME:
        return SASL_CB_USER;

    case VIR_CRED_AUTHNAME:
        return SASL_CB_AUTHNAME;

    case VIR_CRED_LANGUAGE:
        return SASL_CB_LANGUAGE;

    case VIR_CRED_CNONCE:
        return SASL_CB_CNONCE;

    case VIR_CRED_PASSPHRASE:
        return SASL_CB_PASS;

    case VIR_CRED_ECHOPROMPT:
        return SASL_CB_ECHOPROMPT;

    case VIR_CRED_NOECHOPROMPT:
        return SASL_CB_NOECHOPROMPT;

    case VIR_CRED_REALM:
        return SASL_CB_GETREALM;
    }

    return 0;
}

static int remoteAuthCredSASL2Vir(int vircred)
{
    switch (vircred) {
    case SASL_CB_USER:
        return VIR_CRED_USERNAME;

    case SASL_CB_AUTHNAME:
        return VIR_CRED_AUTHNAME;

    case SASL_CB_LANGUAGE:
        return VIR_CRED_LANGUAGE;

    case SASL_CB_CNONCE:
        return VIR_CRED_CNONCE;

    case SASL_CB_PASS:
        return VIR_CRED_PASSPHRASE;

    case SASL_CB_ECHOPROMPT:
        return VIR_CRED_ECHOPROMPT;

    case SASL_CB_NOECHOPROMPT:
        return VIR_CRED_NOECHOPROMPT;

    case SASL_CB_GETREALM:
        return VIR_CRED_REALM;
    }

    return 0;
}

/*
 * @param credtype array of credential types client supports
 * @param ncredtype size of credtype array
 * @return the SASL callback structure, or NULL on error
 *
 * Build up the SASL callback structure. We register one callback for
 * each credential type that the libvirt client indicated they support.
 * We explicitly leav the callback function pointer at NULL though,
 * because we don't actually want to get SASL callbacks triggered.
 * Instead, we want the start/step functions to return SASL_INTERACT.
 * This lets us give the libvirt client a list of all required
 * credentials in one go, rather than triggering the callback one
 * credential at a time,
 */
static sasl_callback_t *remoteAuthMakeCallbacks(int *credtype, int ncredtype)
{
5680
    sasl_callback_t *cbs;
5681
    int i, n;
5682
    if (VIR_ALLOC_N(cbs, ncredtype+1) < 0) {
5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701
        return NULL;
    }

    for (i = 0, n = 0 ; i < ncredtype ; i++) {
        int id = remoteAuthCredVir2SASL(credtype[i]);
        if (id != 0)
            cbs[n++].id = id;
        /* Don't fill proc or context fields of sasl_callback_t
         * because we want to use interactions instead */
    }
    cbs[n].id = 0;
    return cbs;
}


/*
 * @param interact SASL interactions required
 * @param cred populated with libvirt credential metadata
 * @return the size of the cred array returned
5702
 *
5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716
 * Builds up an array of libvirt credential structs, populating
 * with data from the SASL interaction struct. These two structs
 * are basically a 1-to-1 copy of each other.
 */
static int remoteAuthMakeCredentials(sasl_interact_t *interact,
                                     virConnectCredentialPtr *cred)
{
    int ninteract;
    if (!cred)
        return -1;

    for (ninteract = 0 ; interact[ninteract].id != 0 ; ninteract++)
        ; /* empty */

5717
    if (VIR_ALLOC_N(*cred, ninteract) < 0)
5718 5719 5720 5721 5722
        return -1;

    for (ninteract = 0 ; interact[ninteract].id != 0 ; ninteract++) {
        (*cred)[ninteract].type = remoteAuthCredSASL2Vir(interact[ninteract].id);
        if (!(*cred)[ninteract].type) {
5723
            VIR_FREE(*cred);
5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741
            return -1;
        }
        if (interact[ninteract].challenge)
            (*cred)[ninteract].challenge = interact[ninteract].challenge;
        (*cred)[ninteract].prompt = interact[ninteract].prompt;
        if (interact[ninteract].defresult)
            (*cred)[ninteract].defresult = interact[ninteract].defresult;
        (*cred)[ninteract].result = NULL;
    }

    return ninteract;
}

static void remoteAuthFreeCredentials(virConnectCredentialPtr cred,
                                      int ncred)
{
    int i;
    for (i = 0 ; i < ncred ; i++)
5742 5743
        VIR_FREE(cred[i].result);
    VIR_FREE(cred);
5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764
}


/*
 * @param cred the populated libvirt credentials
 * @param interact the SASL interactions to fill in results for
 *
 * Fills the SASL interactions with the result from the libvirt
 * callbacks
 */
static void remoteAuthFillInteract(virConnectCredentialPtr cred,
                                   sasl_interact_t *interact)
{
    int ninteract;
    for (ninteract = 0 ; interact[ninteract].id != 0 ; ninteract++) {
        interact[ninteract].result = cred[ninteract].result;
        interact[ninteract].len = cred[ninteract].resultlen;
    }
}

/* Perform the SASL authentication process
5765 5766
 */
static int
5767 5768
remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
                virConnectAuthPtr auth, const char *wantmech)
5769 5770
{
    sasl_conn_t *saslconn = NULL;
5771
    sasl_security_properties_t secprops;
5772 5773 5774 5775 5776 5777
    remote_auth_sasl_init_ret iret;
    remote_auth_sasl_start_args sargs;
    remote_auth_sasl_start_ret sret;
    remote_auth_sasl_step_args pargs;
    remote_auth_sasl_step_ret pret;
    const char *clientout;
5778
    char *serverin = NULL;
5779 5780 5781 5782 5783
    unsigned int clientoutlen, serverinlen;
    const char *mech;
    int err, complete;
    struct sockaddr_storage sa;
    socklen_t salen;
5784
    char *localAddr = NULL, *remoteAddr = NULL;
5785 5786
    const void *val;
    sasl_ssf_t ssf;
5787 5788 5789 5790 5791 5792
    sasl_callback_t *saslcb = NULL;
    sasl_interact_t *interact = NULL;
    virConnectCredentialPtr cred = NULL;
    int ncred = 0;
    int ret = -1;
    const char *mechlist;
5793

5794
    DEBUG0("Client initialize SASL authentication");
5795 5796 5797
    /* Sets up the SASL library as a whole */
    err = sasl_client_init(NULL);
    if (err != SASL_OK) {
5798
        virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
5799
                         VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
5800
                         _("failed to initialize SASL library: %d (%s)"),
5801
                         err, sasl_errstring(err, NULL, NULL));
5802
        goto cleanup;
5803 5804 5805 5806 5807
    }

    /* Get local address in form  IPADDR:PORT */
    salen = sizeof(sa);
    if (getsockname(priv->sock, (struct sockaddr*)&sa, &salen) < 0) {
5808 5809
        virReportSystemError(in_open ? NULL : conn, errno, "%s",
                             _("failed to get sock address"));
5810
        goto cleanup;
5811
    }
5812 5813
    if ((localAddr = addrToString(&sa, salen)) == NULL)
        goto cleanup;
5814 5815 5816 5817

    /* Get remote address in form  IPADDR:PORT */
    salen = sizeof(sa);
    if (getpeername(priv->sock, (struct sockaddr*)&sa, &salen) < 0) {
5818 5819
        virReportSystemError(in_open ? NULL : conn, errno, "%s",
                             _("failed to get peer address"));
5820
        goto cleanup;
5821
    }
5822 5823 5824
    if ((remoteAddr = addrToString(&sa, salen)) == NULL)
        goto cleanup;

5825 5826 5827 5828 5829 5830
    if (auth) {
        if ((saslcb = remoteAuthMakeCallbacks(auth->credtype, auth->ncredtype)) == NULL)
            goto cleanup;
    } else {
        saslcb = NULL;
    }
5831 5832 5833 5834 5835 5836

    /* Setup a handle for being a client */
    err = sasl_client_new("libvirt",
                          priv->hostname,
                          localAddr,
                          remoteAddr,
5837
                          saslcb,
5838 5839
                          SASL_SUCCESS_DATA,
                          &saslconn);
5840

5841
    if (err != SASL_OK) {
5842
        virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
5843
                         VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
5844
                         _("Failed to create SASL client context: %d (%s)"),
5845
                         err, sasl_errstring(err, NULL, NULL));
5846
        goto cleanup;
5847 5848
    }

5849 5850 5851 5852 5853 5854
    /* Initialize some connection props we care about */
    if (priv->uses_tls) {
        gnutls_cipher_algorithm_t cipher;

        cipher = gnutls_cipher_get(priv->session);
        if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
5855
            virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
5856
                             VIR_ERR_INTERNAL_ERROR, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
5857
                             "%s", _("invalid cipher size for TLS session"));
5858
            goto cleanup;
5859 5860 5861
        }
        ssf *= 8; /* key size is bytes, sasl wants bits */

5862
        DEBUG("Setting external SSF %d", ssf);
5863 5864
        err = sasl_setprop(saslconn, SASL_SSF_EXTERNAL, &ssf);
        if (err != SASL_OK) {
5865
            virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
5866
                             VIR_ERR_INTERNAL_ERROR, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
5867
                             _("cannot set external SSF %d (%s)"),
5868
                             err, sasl_errstring(err, NULL, NULL));
5869
            goto cleanup;
5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883
        }
    }

    memset (&secprops, 0, sizeof secprops);
    /* If we've got TLS, we don't care about SSF */
    secprops.min_ssf = priv->uses_tls ? 0 : 56; /* Equiv to DES supported by all Kerberos */
    secprops.max_ssf = priv->uses_tls ? 0 : 100000; /* Very strong ! AES == 256 */
    secprops.maxbufsize = 100000;
    /* If we're not TLS, then forbid any anonymous or trivially crackable auth */
    secprops.security_flags = priv->uses_tls ? 0 :
        SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;

    err = sasl_setprop(saslconn, SASL_SEC_PROPS, &secprops);
    if (err != SASL_OK) {
5884
        virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
5885
                         VIR_ERR_INTERNAL_ERROR, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
5886
                         _("cannot set security props %d (%s)"),
5887
                         err, sasl_errstring(err, NULL, NULL));
5888
        goto cleanup;
5889 5890
    }

5891 5892 5893 5894
    /* First call is to inquire about supported mechanisms in the server */
    memset (&iret, 0, sizeof iret);
    if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_INIT,
              (xdrproc_t) xdr_void, (char *)NULL,
5895 5896
              (xdrproc_t) xdr_remote_auth_sasl_init_ret, (char *) &iret) != 0)
        goto cleanup;
5897 5898


5899 5900 5901
    mechlist = iret.mechlist;
    if (wantmech) {
        if (strstr(mechlist, wantmech) == NULL) {
5902
            virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
5903 5904 5905 5906
                             VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR,
                             NULL, NULL, NULL, 0, 0,
                             _("SASL mechanism %s not supported by server"),
                             wantmech);
5907
            VIR_FREE(iret.mechlist);
5908 5909 5910 5911 5912
            goto cleanup;
        }
        mechlist = wantmech;
    }
 restart:
5913
    /* Start the auth negotiation on the client end first */
5914
    DEBUG("Client start negotiation mechlist '%s'", mechlist);
5915
    err = sasl_client_start(saslconn,
5916 5917
                            mechlist,
                            &interact,
5918 5919 5920
                            &clientout,
                            &clientoutlen,
                            &mech);
5921
    if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) {
5922
        virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
5923
                         VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
5924
                         _("Failed to start SASL negotiation: %d (%s)"),
5925
                         err, sasl_errdetail(saslconn));
5926
        VIR_FREE(iret.mechlist);
5927 5928 5929 5930 5931
        goto cleanup;
    }

    /* Need to gather some credentials from the client */
    if (err == SASL_INTERACT) {
5932
        const char *msg;
5933 5934 5935 5936 5937 5938
        if (cred) {
            remoteAuthFreeCredentials(cred, ncred);
            cred = NULL;
        }
        if ((ncred =
             remoteAuthMakeCredentials(interact, &cred)) < 0) {
5939
            virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
5940 5941 5942
                             VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR,
                             NULL, NULL, NULL, 0, 0,
                             "%s", _("Failed to make auth credentials"));
5943
            VIR_FREE(iret.mechlist);
5944 5945 5946
            goto cleanup;
        }
        /* Run the authentication callback */
5947
        if (auth && auth->cb) {
5948 5949 5950
            if ((*(auth->cb))(cred, ncred, auth->cbdata) >= 0) {
                remoteAuthFillInteract(cred, interact);
                goto restart;
5951
            }
5952
            msg = "Failed to collect auth credentials";
5953
        } else {
5954
            msg = "No authentication callback available";
5955
        }
5956
        virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
5957
                         VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL,
5958
                         0, 0, "%s", msg);
5959
        goto cleanup;
5960
    }
5961
    VIR_FREE(iret.mechlist);
5962 5963

    if (clientoutlen > REMOTE_AUTH_SASL_DATA_MAX) {
5964
        virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
5965
                         VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
5966 5967
                         _("SASL negotiation data too long: %d bytes"),
                         clientoutlen);
5968
        goto cleanup;
5969 5970 5971 5972 5973 5974 5975
    }
    /* NB, distinction of NULL vs "" is *critical* in SASL */
    memset(&sargs, 0, sizeof sargs);
    sargs.nil = clientout ? 0 : 1;
    sargs.data.data_val = (char*)clientout;
    sargs.data.data_len = clientoutlen;
    sargs.mech = (char*)mech;
5976
    DEBUG("Server start negotiation with mech %s. Data %d bytes %p", mech, clientoutlen, clientout);
5977 5978 5979 5980 5981

    /* Now send the initial auth data to the server */
    memset (&sret, 0, sizeof sret);
    if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_START,
              (xdrproc_t) xdr_remote_auth_sasl_start_args, (char *) &sargs,
5982 5983
              (xdrproc_t) xdr_remote_auth_sasl_start_ret, (char *) &sret) != 0)
        goto cleanup;
5984 5985 5986 5987 5988

    complete = sret.complete;
    /* NB, distinction of NULL vs "" is *critical* in SASL */
    serverin = sret.nil ? NULL : sret.data.data_val;
    serverinlen = sret.data.data_len;
5989 5990
    DEBUG("Client step result complete: %d. Data %d bytes %p",
          complete, serverinlen, serverin);
5991 5992 5993

    /* Loop-the-loop...
     * Even if the server has completed, the client must *always* do at least one step
D
Daniel Veillard 已提交
5994
     * in this loop to verify the server isn't lying about something. Mutual auth */
5995
    for (;;) {
5996
    restep:
5997 5998 5999
        err = sasl_client_step(saslconn,
                               serverin,
                               serverinlen,
6000
                               &interact,
6001 6002
                               &clientout,
                               &clientoutlen);
6003
        if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) {
6004
            virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
6005
                             VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
6006
                             _("Failed SASL step: %d (%s)"),
6007
                             err, sasl_errdetail(saslconn));
6008 6009 6010 6011
            goto cleanup;
        }
        /* Need to gather some credentials from the client */
        if (err == SASL_INTERACT) {
6012
            const char *msg;
6013 6014 6015 6016 6017
            if (cred) {
                remoteAuthFreeCredentials(cred, ncred);
                cred = NULL;
            }
            if ((ncred = remoteAuthMakeCredentials(interact, &cred)) < 0) {
6018
                virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
6019
                                 VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
6020
                                 "%s", _("Failed to make auth credentials"));
6021 6022 6023
                goto cleanup;
            }
            /* Run the authentication callback */
6024
            if (auth && auth->cb) {
6025 6026 6027
                if ((*(auth->cb))(cred, ncred, auth->cbdata) >= 0) {
                    remoteAuthFillInteract(cred, interact);
                    goto restep;
6028
                }
6029
                msg = "Failed to collect auth credentials";
6030
            } else {
6031
                msg = "No authentication callback available";
6032
            }
6033
            virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
6034
                             VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL,
6035
                             0, 0, "%s", msg);
6036
            goto cleanup;
6037 6038
        }

6039
        VIR_FREE(serverin);
6040
        DEBUG("Client step result %d. Data %d bytes %p", err, clientoutlen, clientout);
6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051

        /* Previous server call showed completion & we're now locally complete too */
        if (complete && err == SASL_OK)
            break;

        /* Not done, prepare to talk with the server for another iteration */
        /* NB, distinction of NULL vs "" is *critical* in SASL */
        memset(&pargs, 0, sizeof pargs);
        pargs.nil = clientout ? 0 : 1;
        pargs.data.data_val = (char*)clientout;
        pargs.data.data_len = clientoutlen;
6052
        DEBUG("Server step with %d bytes %p", clientoutlen, clientout);
6053 6054 6055 6056

        memset (&pret, 0, sizeof pret);
        if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_STEP,
                  (xdrproc_t) xdr_remote_auth_sasl_step_args, (char *) &pargs,
6057 6058
                  (xdrproc_t) xdr_remote_auth_sasl_step_ret, (char *) &pret) != 0)
            goto cleanup;
6059 6060 6061 6062 6063 6064

        complete = pret.complete;
        /* NB, distinction of NULL vs "" is *critical* in SASL */
        serverin = pret.nil ? NULL : pret.data.data_val;
        serverinlen = pret.data.data_len;

6065 6066
        DEBUG("Client step result complete: %d. Data %d bytes %p",
              complete, serverinlen, serverin);
6067 6068 6069

        /* This server call shows complete, and earlier client step was OK */
        if (complete && err == SASL_OK) {
6070
            VIR_FREE(serverin);
6071 6072 6073 6074
            break;
        }
    }

6075 6076 6077 6078
    /* Check for suitable SSF if non-TLS */
    if (!priv->uses_tls) {
        err = sasl_getprop(saslconn, SASL_SSF, &val);
        if (err != SASL_OK) {
6079
            virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
6080
                             VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
6081
                             _("cannot query SASL ssf on connection %d (%s)"),
6082
                             err, sasl_errstring(err, NULL, NULL));
6083
            goto cleanup;
6084 6085
        }
        ssf = *(const int *)val;
6086
        DEBUG("SASL SSF value %d", ssf);
6087
        if (ssf < 56) { /* 56 == DES level, good for Kerberos */
6088
            virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
6089
                             VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
6090
                             _("negotiation SSF %d was not strong enough"), ssf);
6091
            goto cleanup;
6092 6093 6094
        }
    }

6095
    DEBUG0("SASL authentication complete");
6096
    priv->saslconn = saslconn;
6097 6098 6099
    ret = 0;

 cleanup:
6100 6101 6102
    VIR_FREE(localAddr);
    VIR_FREE(remoteAddr);
    VIR_FREE(serverin);
6103

6104
    VIR_FREE(saslcb);
6105 6106 6107
    remoteAuthFreeCredentials(cred, ncred);
    if (ret != 0 && saslconn)
        sasl_dispose(&saslconn);
6108

6109
    return ret;
6110 6111 6112
}
#endif /* HAVE_SASL */

6113 6114 6115 6116 6117 6118 6119 6120 6121

#if HAVE_POLKIT
/* Perform the PolicyKit authentication process
 */
static int
remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open,
                  virConnectAuthPtr auth)
{
    remote_auth_polkit_ret ret;
6122
    int i, allowcb = 0;
6123 6124 6125 6126 6127 6128 6129 6130
    virConnectCredential cred = {
        VIR_CRED_EXTERNAL,
        conn->flags & VIR_CONNECT_RO ? "org.libvirt.unix.monitor" : "org.libvirt.unix.manage",
        "PolicyKit",
        NULL,
        NULL,
        0,
    };
6131
    DEBUG0("Client initialize PolicyKit authentication");
6132

6133
    if (auth && auth->cb) {
6134
        /* Check if the necessary credential type for PolicyKit is supported */
6135 6136 6137 6138
        for (i = 0 ; i < auth->ncredtype ; i++) {
            if (auth->credtype[i] == VIR_CRED_EXTERNAL)
                allowcb = 1;
        }
6139

6140 6141 6142
        if (allowcb) {
            /* Run the authentication callback */
            if ((*(auth->cb))(&cred, 1, auth->cbdata) < 0) {
6143
                virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
6144
                                 VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
J
Jim Meyering 已提交
6145
                                 "%s", _("Failed to collect auth credentials"));
6146 6147
                return -1;
            }
6148
        } else {
6149
            DEBUG0("Client auth callback does not support PolicyKit");
6150 6151
        }
    } else {
6152
        DEBUG0("No auth callback provided");
6153 6154 6155 6156 6157 6158 6159 6160 6161
    }

    memset (&ret, 0, sizeof ret);
    if (call (conn, priv, in_open, REMOTE_PROC_AUTH_POLKIT,
              (xdrproc_t) xdr_void, (char *)NULL,
              (xdrproc_t) xdr_remote_auth_polkit_ret, (char *) &ret) != 0) {
        return -1; /* virError already set by call */
    }

6162
    DEBUG0("PolicyKit authentication complete");
6163 6164 6165
    return 0;
}
#endif /* HAVE_POLKIT */
6166 6167 6168
/*----------------------------------------------------------------------*/

static int remoteDomainEventRegister (virConnectPtr conn,
6169 6170
                                      virConnectDomainEventCallback callback,
                                      void *opaque,
6171
                                      virFreeCallback freecb)
6172
{
6173
    int rv = -1;
6174 6175
    struct private_data *priv = conn->privateData;

6176 6177
    remoteDriverLock(priv);

6178 6179
    if (priv->eventFlushTimer < 0) {
         error (conn, VIR_ERR_NO_SUPPORT, _("no event support"));
6180
         goto done;
6181
    }
6182
    if (virDomainEventCallbackListAdd(conn, priv->callbackList,
6183
                                      callback, opaque, freecb) < 0) {
6184
         error (conn, VIR_ERR_RPC, _("adding cb to list"));
6185
         goto done;
6186 6187 6188 6189 6190 6191 6192
    }

    if ( priv->callbackList->count == 1 ) {
        /* Tell the server when we are the first callback deregistering */
        if (call (conn, priv, 0, REMOTE_PROC_DOMAIN_EVENTS_REGISTER,
                (xdrproc_t) xdr_void, (char *) NULL,
                (xdrproc_t) xdr_void, (char *) NULL) == -1)
6193
            goto done;
6194 6195
    }

6196 6197 6198
    rv = 0;

done:
6199
    remoteDriverUnlock(priv);
6200
    return rv;
6201 6202 6203
}

static int remoteDomainEventDeregister (virConnectPtr conn,
6204
                                        virConnectDomainEventCallback callback)
6205 6206
{
    struct private_data *priv = conn->privateData;
6207
    int rv = -1;
6208

6209 6210
    remoteDriverLock(priv);

6211
    if (virDomainEventCallbackListRemove(conn, priv->callbackList,
6212
                                         callback) < 0) {
6213
         error (conn, VIR_ERR_RPC, _("removing cb fron list"));
6214
         goto done;
6215 6216 6217 6218 6219 6220 6221
    }

    if ( priv->callbackList->count == 0 ) {
        /* Tell the server when we are the last callback deregistering */
        if (call (conn, priv, 0, REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER,
                (xdrproc_t) xdr_void, (char *) NULL,
                (xdrproc_t) xdr_void, (char *) NULL) == -1)
6222
            goto done;
6223 6224
    }

6225 6226 6227
    rv = 0;

done:
6228
    remoteDriverUnlock(priv);
6229
    return rv;
6230
}
6231

6232 6233
/*----------------------------------------------------------------------*/

6234

6235 6236 6237 6238 6239 6240 6241 6242
static struct remote_thread_call *
prepareCall(virConnectPtr conn,
            struct private_data *priv,
            int flags,
            int proc_nr,
            xdrproc_t args_filter, char *args,
            xdrproc_t ret_filter, char *ret)
{
6243
    XDR xdr;
6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256
    struct remote_message_header hdr;
    struct remote_thread_call *rv;

    if (VIR_ALLOC(rv) < 0)
        return NULL;

    if (virCondInit(&rv->cond) < 0) {
        VIR_FREE(rv);
        error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
               VIR_ERR_INTERNAL_ERROR,
               _("cannot initialize mutex"));
        return NULL;
    }
6257 6258

    /* Get a unique serial number for this message. */
6259 6260 6261 6262
    rv->serial = priv->counter++;
    rv->proc_nr = proc_nr;
    rv->ret_filter = ret_filter;
    rv->ret = ret;
6263 6264 6265 6266 6267

    hdr.prog = REMOTE_PROGRAM;
    hdr.vers = REMOTE_PROTOCOL_VERSION;
    hdr.proc = proc_nr;
    hdr.direction = REMOTE_CALL;
6268
    hdr.serial = rv->serial;
6269 6270 6271
    hdr.status = REMOTE_OK;

    /* Serialise header followed by args. */
6272
    xdrmem_create (&xdr, rv->buffer+4, REMOTE_MESSAGE_MAX, XDR_ENCODE);
6273
    if (!xdr_remote_message_header (&xdr, &hdr)) {
6274
        error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
6275
               VIR_ERR_RPC, _("xdr_remote_message_header failed"));
6276
        goto error;
6277 6278 6279
    }

    if (!(*args_filter) (&xdr, args)) {
6280 6281
        error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, VIR_ERR_RPC,
               _("marshalling args"));
6282
        goto error;
6283 6284 6285
    }

    /* Get the length stored in buffer. */
6286
    rv->bufferLength = xdr_getpos (&xdr);
6287 6288 6289 6290 6291
    xdr_destroy (&xdr);

    /* Length must include the length word itself (always encoded in
     * 4 bytes as per RFC 4506).
     */
6292
    rv->bufferLength += REMOTE_MESSAGE_HEADER_XDR_LEN;
6293 6294

    /* Encode the length word. */
6295 6296
    xdrmem_create (&xdr, rv->buffer, REMOTE_MESSAGE_HEADER_XDR_LEN, XDR_ENCODE);
    if (!xdr_u_int (&xdr, &rv->bufferLength)) {
6297
        error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, VIR_ERR_RPC,
6298
               _("xdr_u_int (length word)"));
6299
        goto error;
6300 6301 6302
    }
    xdr_destroy (&xdr);

6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342
    return rv;

error:
    xdr_destroy (&xdr);
    VIR_FREE(rv);
    return NULL;
}



static int
processCallWrite(virConnectPtr conn,
                 struct private_data *priv,
                 int in_open /* if we are in virConnectOpen */,
                 const char *bytes, int len)
{
    int ret;

    if (priv->uses_tls) {
    tls_resend:
        ret = gnutls_record_send (priv->session, bytes, len);
        if (ret < 0) {
            if (ret == GNUTLS_E_INTERRUPTED)
                goto tls_resend;
            if (ret == GNUTLS_E_AGAIN)
                return 0;

            error (in_open ? NULL : conn,
                   VIR_ERR_GNUTLS_ERROR, gnutls_strerror (ret));
            return -1;
        }
    } else {
    resend:
        ret = send (priv->sock, bytes, len, 0);
        if (ret == -1) {
            if (errno == EINTR)
                goto resend;
            if (errno == EWOULDBLOCK)
                return 0;

6343 6344
            virReportSystemError(in_open ? NULL : conn, errno,
                                 "%s", _("cannot send data"));
6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392
            return -1;

        }
    }

    return ret;
}


static int
processCallRead(virConnectPtr conn,
                struct private_data *priv,
                int in_open /* if we are in virConnectOpen */,
                char *bytes, int len)
{
    int ret;

    if (priv->uses_tls) {
    tls_resend:
        ret = gnutls_record_recv (priv->session, bytes, len);
        if (ret == GNUTLS_E_INTERRUPTED)
            goto tls_resend;
        if (ret == GNUTLS_E_AGAIN)
            return 0;

        /* Treat 0 == EOF as an error */
        if (ret <= 0) {
            if (ret < 0)
                errorf (in_open ? NULL : conn,
                        VIR_ERR_GNUTLS_ERROR,
                        _("failed to read from TLS socket %s"),
                        gnutls_strerror (ret));
            else
                errorf (in_open ? NULL : conn,
                        VIR_ERR_SYSTEM_ERROR,
                        "%s", _("server closed connection"));
            return -1;
        }
    } else {
    resend:
        ret = recv (priv->sock, bytes, len, 0);
        if (ret <= 0) {
            if (ret == -1) {
                if (errno == EINTR)
                    goto resend;
                if (errno == EWOULDBLOCK)
                    return 0;

6393 6394
                virReportSystemError(in_open ? NULL : conn, errno,
                                     "%s", _("cannot recv data"));
6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564
            } else {
                errorf (in_open ? NULL : conn,
                        VIR_ERR_SYSTEM_ERROR,
                        "%s", _("server closed connection"));
            }
            return -1;
        }
    }

    return ret;
}


static int
processCallSendOne(virConnectPtr conn,
                   struct private_data *priv,
                   int in_open,
                   struct remote_thread_call *thecall)
{
#if HAVE_SASL
    if (priv->saslconn) {
        const char *output;
        unsigned int outputlen;
        int err, ret;

        if (!priv->saslEncoded) {
            err = sasl_encode(priv->saslconn,
                              thecall->buffer + thecall->bufferOffset,
                              thecall->bufferLength - thecall->bufferOffset,
                              &output, &outputlen);
            if (err != SASL_OK) {
                errorf (in_open ? NULL : conn, VIR_ERR_INTERNAL_ERROR,
                        _("failed to encode SASL data: %s"),
                        sasl_errstring(err, NULL, NULL));
                return -1;
            }
            priv->saslEncoded = output;
            priv->saslEncodedLength = outputlen;
            priv->saslEncodedOffset = 0;

            thecall->bufferOffset = thecall->bufferLength;
        }

        ret = processCallWrite(conn, priv, in_open,
                               priv->saslEncoded + priv->saslEncodedOffset,
                               priv->saslEncodedLength - priv->saslEncodedOffset);
        if (ret < 0)
            return ret;
        priv->saslEncodedOffset += ret;

        if (priv->saslEncodedOffset == priv->saslEncodedLength) {
            priv->saslEncoded = NULL;
            priv->saslEncodedOffset = priv->saslEncodedLength = 0;
            thecall->mode = REMOTE_MODE_WAIT_RX;
        }
    } else {
#endif
        int ret;
        ret = processCallWrite(conn, priv, in_open,
                               thecall->buffer + thecall->bufferOffset,
                               thecall->bufferLength - thecall->bufferOffset);
        if (ret < 0)
            return ret;
        thecall->bufferOffset += ret;

        if (thecall->bufferOffset == thecall->bufferLength) {
            thecall->bufferOffset = thecall->bufferLength = 0;
            thecall->mode = REMOTE_MODE_WAIT_RX;
        }
#if HAVE_SASL
    }
#endif
    return 0;
}


static int
processCallSend(virConnectPtr conn, struct private_data *priv,
                int in_open) {
    struct remote_thread_call *thecall = priv->waitDispatch;

    while (thecall &&
           thecall->mode != REMOTE_MODE_WAIT_TX)
        thecall = thecall->next;

    if (!thecall)
        return -1; /* Shouldn't happen, but you never know... */

    while (thecall) {
        int ret = processCallSendOne(conn, priv, in_open, thecall);
        if (ret < 0)
            return ret;

        if (thecall->mode == REMOTE_MODE_WAIT_TX)
            return 0; /* Blocking write, to back to event loop */

        thecall = thecall->next;
    }

    return 0; /* No more calls to send, all done */
}

static int
processCallRecvSome(virConnectPtr conn, struct private_data *priv,
                    int in_open) {
    unsigned int wantData;

    /* Start by reading length word */
    if (priv->bufferLength == 0)
        priv->bufferLength = 4;

    wantData = priv->bufferLength - priv->bufferOffset;

#if HAVE_SASL
    if (priv->saslconn) {
        if (priv->saslDecoded == NULL) {
            char encoded[8192];
            unsigned int encodedLen = sizeof(encoded);
            int ret, err;
            ret = processCallRead(conn, priv, in_open,
                                  encoded, encodedLen);
            if (ret < 0)
                return -1;
            if (ret == 0)
                return 0;

            err = sasl_decode(priv->saslconn, encoded, ret,
                              &priv->saslDecoded, &priv->saslDecodedLength);
            if (err != SASL_OK) {
                errorf (in_open ? NULL : conn, VIR_ERR_INTERNAL_ERROR,
                        _("failed to decode SASL data: %s"),
                        sasl_errstring(err, NULL, NULL));
                return -1;
            }
            priv->saslDecodedOffset = 0;
        }

        if ((priv->saslDecodedLength - priv->saslDecodedOffset) < wantData)
            wantData = (priv->saslDecodedLength - priv->saslDecodedOffset);

        memcpy(priv->buffer + priv->bufferOffset,
               priv->saslDecoded + priv->saslDecodedOffset,
               wantData);
        priv->saslDecodedOffset += wantData;
        priv->bufferOffset += wantData;
        if (priv->saslDecodedOffset == priv->saslDecodedLength) {
            priv->saslDecodedLength = priv->saslDecodedLength = 0;
            priv->saslDecoded = NULL;
        }

        return wantData;
    } else {
#endif
        int ret;

        ret = processCallRead(conn, priv, in_open,
                              priv->buffer + priv->bufferOffset,
                              wantData);
        if (ret < 0)
            return -1;
        if (ret == 0)
            return 0;

        priv->bufferOffset += ret;

        return ret;
#if HAVE_SASL
    }
#endif
}
6565 6566


6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593
static void
processCallAsyncEvent(virConnectPtr conn, struct private_data *priv,
                      int in_open,
                      remote_message_header *hdr,
                      XDR *xdr) {
    /* An async message has come in while we were waiting for the
     * response. Process it to pull it off the wire, and try again
     */
    DEBUG0("Encountered an event while waiting for a response");

    if (in_open) {
        DEBUG("Ignoring bogus event %d received while in open", hdr->proc);
        return;
    }

    if (hdr->proc == REMOTE_PROC_DOMAIN_EVENT) {
        remoteDomainQueueEvent(conn, xdr);
        virEventUpdateTimeout(priv->eventFlushTimer, 0);
    } else {
        DEBUG("Unexpected event proc %d", hdr->proc);
    }
}

static int
processCallRecvLen(virConnectPtr conn, struct private_data *priv,
                   int in_open) {
    XDR xdr;
6594
    unsigned int len;
6595 6596

    xdrmem_create (&xdr, priv->buffer, priv->bufferLength, XDR_DECODE);
6597
    if (!xdr_u_int (&xdr, &len)) {
6598
        error (in_open ? NULL : conn,
6599
               VIR_ERR_RPC, _("xdr_u_int (length word, reply)"));
6600 6601 6602 6603
        return -1;
    }
    xdr_destroy (&xdr);

6604 6605 6606 6607 6608 6609
    if (len < REMOTE_MESSAGE_HEADER_XDR_LEN) {
        error (in_open ? NULL : conn,
               VIR_ERR_RPC, _("packet received from server too small"));
        return -1;
    }

6610
    /* Length includes length word - adjust to real length to read. */
6611
    len -= REMOTE_MESSAGE_HEADER_XDR_LEN;
6612

6613
    if (len > REMOTE_MESSAGE_MAX) {
6614
        error (in_open ? NULL : conn,
6615
               VIR_ERR_RPC, _("packet received from server too large"));
6616 6617 6618
        return -1;
    }

6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633
    /* Extend our declared buffer length and carry
       on reading the header + payload */
    priv->bufferLength += len;
    DEBUG("Got length, now need %d total (%d more)", priv->bufferLength, len);
    return 0;
}


static int
processCallRecvMsg(virConnectPtr conn, struct private_data *priv,
                   int in_open) {
    XDR xdr;
    struct remote_message_header hdr;
    int len = priv->bufferLength - 4;
    struct remote_thread_call *thecall;
6634 6635

    /* Deserialise reply header. */
6636
    xdrmem_create (&xdr, priv->buffer + 4, len, XDR_DECODE);
6637
    if (!xdr_remote_message_header (&xdr, &hdr)) {
6638
        error (in_open ? NULL : conn,
6639
               VIR_ERR_RPC, _("invalid header in reply"));
6640 6641 6642 6643 6644
        return -1;
    }

    /* Check program, version, etc. are what we expect. */
    if (hdr.prog != REMOTE_PROGRAM) {
6645 6646 6647 6648 6649
        virRaiseError (in_open ? NULL : conn,
                       NULL, NULL, VIR_FROM_REMOTE,
                       VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
                       _("unknown program (received %x, expected %x)"),
                       hdr.prog, REMOTE_PROGRAM);
6650 6651 6652
        return -1;
    }
    if (hdr.vers != REMOTE_PROTOCOL_VERSION) {
6653 6654 6655 6656 6657
        virRaiseError (in_open ? NULL : conn,
                       NULL, NULL, VIR_FROM_REMOTE,
                       VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
                       _("unknown protocol version (received %x, expected %x)"),
                       hdr.vers, REMOTE_PROTOCOL_VERSION);
6658 6659 6660
        return -1;
    }

6661 6662 6663 6664 6665 6666 6667
    /* Async events from server need special handling */
    if (hdr.direction == REMOTE_MESSAGE) {
        processCallAsyncEvent(conn, priv, in_open,
                              &hdr, &xdr);
        xdr_destroy(&xdr);
        return 0;
    }
6668

6669 6670 6671 6672 6673 6674 6675
    if (hdr.direction != REMOTE_REPLY) {
        virRaiseError (in_open ? NULL : conn,
                       NULL, NULL, VIR_FROM_REMOTE,
                       VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
                       _("got unexpected RPC call %d from server"),
                       hdr.proc);
        xdr_destroy(&xdr);
6676 6677
        return -1;
    }
6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693

    /* Ok, definitely got an RPC reply now find
       out who's been waiting for it */

    thecall = priv->waitDispatch;
    while (thecall &&
           thecall->serial != hdr.serial)
        thecall = thecall->next;

    if (!thecall) {
        virRaiseError (in_open ? NULL : conn,
                       NULL, NULL, VIR_FROM_REMOTE,
                       VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
                       _("no call waiting for reply with serial %d"),
                       hdr.serial);
        xdr_destroy(&xdr);
6694 6695
        return -1;
    }
6696 6697 6698 6699 6700 6701 6702 6703

    if (hdr.proc != thecall->proc_nr) {
        virRaiseError (in_open ? NULL : conn,
                       NULL, NULL, VIR_FROM_REMOTE,
                       VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
                       _("unknown procedure (received %x, expected %x)"),
                       hdr.proc, thecall->proc_nr);
        xdr_destroy (&xdr);
6704 6705 6706 6707 6708 6709 6710 6711 6712
        return -1;
    }

    /* Status is either REMOTE_OK (meaning that what follows is a ret
     * structure), or REMOTE_ERROR (and what follows is a remote_error
     * structure).
     */
    switch (hdr.status) {
    case REMOTE_OK:
6713 6714
        if (!(*thecall->ret_filter) (&xdr, thecall->ret)) {
            error (in_open ? NULL : conn, VIR_ERR_RPC,
6715
                   _("unmarshalling ret"));
6716 6717
            return -1;
        }
6718
        thecall->mode = REMOTE_MODE_COMPLETE;
6719 6720 6721 6722
        xdr_destroy (&xdr);
        return 0;

    case REMOTE_ERROR:
6723 6724 6725
        memset (&thecall->err, 0, sizeof thecall->err);
        if (!xdr_remote_error (&xdr, &thecall->err)) {
            error (in_open ? NULL : conn,
6726
                   VIR_ERR_RPC, _("unmarshalling remote_error"));
6727 6728 6729
            return -1;
        }
        xdr_destroy (&xdr);
6730 6731
        thecall->mode = REMOTE_MODE_ERROR;
        return 0;
6732 6733

    default:
6734 6735 6736 6737
        virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
                       VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
                       _("unknown status (received %x)"),
                       hdr.status);
6738 6739 6740 6741 6742
        xdr_destroy (&xdr);
        return -1;
    }
}

6743 6744

static int
6745
processCallRecv(virConnectPtr conn, struct private_data *priv,
6746 6747
                int in_open)
{
6748
    /* Read as much data as is available, until we get
6749
     * EAGAIN
6750
     */
6751
    for (;;) {
6752
        int ret = processCallRecvSome(conn, priv, in_open);
6753

6754 6755 6756 6757
        if (ret < 0)
            return -1;
        if (ret == 0)
            return 0;  /* Blocking on read */
6758

6759 6760 6761 6762
        /* Check for completion of our goal */
        if (priv->bufferOffset == priv->bufferLength) {
            if (priv->bufferOffset == 4) {
                ret = processCallRecvLen(conn, priv, in_open);
6763 6764 6765 6766 6767 6768 6769 6770 6771
                if (ret < 0)
                    return -1;

                /*
                 * We'll carry on around the loop to immediately
                 * process the message body, because it has probably
                 * already arrived. Worst case, we'll get EAGAIN on
                 * next iteration.
                 */
6772 6773 6774
            } else {
                ret = processCallRecvMsg(conn, priv, in_open);
                priv->bufferOffset = priv->bufferLength = 0;
6775 6776 6777 6778 6779 6780 6781 6782
                /*
                 * We've completed one call, so return even
                 * though there might still be more data on
                 * the wire. We need to actually let the caller
                 * deal with this arrived message to keep good
                 * response, and also to correctly handle EOF.
                 */
                return ret;
6783 6784 6785
            }
        }
    }
6786 6787
}

6788 6789 6790 6791 6792
/*
 * Process all calls pending dispatch/receive until we
 * get a reply to our own call. Then quit and pass the buck
 * to someone else.
 */
6793
static int
6794 6795 6796 6797
processCalls(virConnectPtr conn,
             struct private_data *priv,
             int in_open,
             struct remote_thread_call *thiscall)
6798
{
6799 6800
    struct pollfd fds[2];
    int ret;
6801

6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840
    fds[0].fd = priv->sock;
    fds[1].fd = priv->wakeupReadFD;

    for (;;) {
        struct remote_thread_call *tmp = priv->waitDispatch;
        struct remote_thread_call *prev;
        char ignore;

        fds[0].events = fds[0].revents = 0;
        fds[1].events = fds[1].revents = 0;

        fds[1].events = POLLIN;
        while (tmp) {
            if (tmp->mode == REMOTE_MODE_WAIT_RX)
                fds[0].events |= POLLIN;
            if (tmp->mode == REMOTE_MODE_WAIT_TX)
                fds[0].events |= POLLOUT;

            tmp = tmp->next;
        }

        /* Release lock while poll'ing so other threads
         * can stuff themselves on the queue */
        remoteDriverUnlock(priv);

    repoll:
        ret = poll(fds, ARRAY_CARDINALITY(fds), -1);
        if (ret < 0 && errno == EINTR)
            goto repoll;
        remoteDriverLock(priv);

        if (fds[1].revents) {
            DEBUG0("Woken up from poll by other thread");
            saferead(priv->wakeupReadFD, &ignore, sizeof(ignore));
        }

        if (ret < 0) {
            if (errno == EWOULDBLOCK)
                continue;
6841 6842
            virReportSystemError(in_open ? NULL : conn, errno,
                                 "%s", _("poll on socket failed"));
6843
            goto error;
6844 6845 6846 6847
        }

        if (fds[0].revents & POLLOUT) {
            if (processCallSend(conn, priv, in_open) < 0)
6848
                goto error;
6849
        }
6850 6851 6852

        if (fds[0].revents & POLLIN) {
            if (processCallRecv(conn, priv, in_open) < 0)
6853
                goto error;
6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877
        }

        /* Iterate through waiting threads and if
         * any are complete then tell 'em to wakeup
         */
        tmp = priv->waitDispatch;
        prev = NULL;
        while (tmp) {
            if (tmp != thiscall &&
                (tmp->mode == REMOTE_MODE_COMPLETE ||
                 tmp->mode == REMOTE_MODE_ERROR)) {
                /* Take them out of the list */
                if (prev)
                    prev->next = tmp->next;
                else
                    priv->waitDispatch = tmp->next;

                /* And wake them up....
                 * ...they won't actually wakeup until
                 * we release our mutex a short while
                 * later...
                 */
                DEBUG("Waking up sleep %d %p %p", tmp->proc_nr, tmp, priv->waitDispatch);
                virCondSignal(&tmp->cond);
6878
            }
6879 6880
            prev = tmp;
            tmp = tmp->next;
6881 6882
        }

6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898
        /* Now see if *we* are done */
        if (thiscall->mode == REMOTE_MODE_COMPLETE ||
            thiscall->mode == REMOTE_MODE_ERROR) {
            /* We're at head of the list already, so
             * remove us
             */
            priv->waitDispatch = thiscall->next;
            DEBUG("Giving up the buck %d %p %p", thiscall->proc_nr, thiscall, priv->waitDispatch);
            /* See if someone else is still waiting
             * and if so, then pass the buck ! */
            if (priv->waitDispatch) {
                DEBUG("Passing the buck to %d %p", priv->waitDispatch->proc_nr, priv->waitDispatch);
                virCondSignal(&priv->waitDispatch->cond);
            }
            return 0;
        }
6899

6900 6901 6902 6903

        if (fds[0].revents & (POLLHUP | POLLERR)) {
            errorf(in_open ? NULL : conn, VIR_ERR_INTERNAL_ERROR,
                   "%s", _("received hangup / error event on socket"));
6904
            goto error;
6905 6906
        }
    }
6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918


error:
    priv->waitDispatch = thiscall->next;
    DEBUG("Giving up the buck due to I/O error %d %p %p", thiscall->proc_nr, thiscall, priv->waitDispatch);
    /* See if someone else is still waiting
     * and if so, then pass the buck ! */
    if (priv->waitDispatch) {
        DEBUG("Passing the buck to %d %p", priv->waitDispatch->proc_nr, priv->waitDispatch);
        virCondSignal(&priv->waitDispatch->cond);
    }
    return -1;
6919 6920
}

6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953
/*
 * This function performs a remote procedure call to procedure PROC_NR.
 *
 * NB. This does not free the args structure (not desirable, since you
 * often want this allocated on the stack or else it contains strings
 * which come from the user).  It does however free any intermediate
 * results, eg. the error structure if there is one.
 *
 * NB(2). Make sure to memset (&ret, 0, sizeof ret) before calling,
 * else Bad Things will happen in the XDR code.
 *
 * NB(3) You must have the private_data lock before calling this
 *
 * NB(4) This is very complicated. Due to connection cloning, multiple
 * threads can want to use the socket at once. Obviously only one of
 * them can. So if someone's using the socket, other threads are put
 * to sleep on condition variables. THe existing thread may completely
 * send & receive their RPC call/reply while they're asleep. Or it
 * may only get around to dealing with sending the call. Or it may
 * get around to neither. So upon waking up from slumber, the other
 * thread may or may not have more work todo.
 *
 * We call this dance  'passing the buck'
 *
 *      http://en.wikipedia.org/wiki/Passing_the_buck
 *
 *   "Buck passing or passing the buck is the action of transferring
 *    responsibility or blame unto another person. It is also used as
 *    a strategy in power politics when the actions of one country/
 *    nation are blamed on another, providing an opportunity for war."
 *
 * NB(5) Don't Panic!
 */
6954
static int
6955 6956 6957 6958 6959
call (virConnectPtr conn, struct private_data *priv,
      int flags /* if we are in virConnectOpen */,
      int proc_nr,
      xdrproc_t args_filter, char *args,
      xdrproc_t ret_filter, char *ret)
6960
{
6961 6962
    int rv;
    struct remote_thread_call *thiscall;
6963

6964 6965 6966 6967 6968 6969
    DEBUG("Doing call %d %p", proc_nr, priv->waitDispatch);
    thiscall = prepareCall(conn, priv, flags, proc_nr,
                           args_filter, args,
                           ret_filter, ret);

    if (!thiscall) {
6970
        virReportOOMError (flags & REMOTE_CALL_IN_OPEN ? NULL : conn);
6971 6972 6973
        return -1;
    }

6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984
    /* Check to see if another thread is dispatching */
    if (priv->waitDispatch) {
        /* Stick ourselves on the end of the wait queue */
        struct remote_thread_call *tmp = priv->waitDispatch;
        char ignore = 1;
        while (tmp && tmp->next)
            tmp = tmp->next;
        if (tmp)
            tmp->next = thiscall;
        else
            priv->waitDispatch = thiscall;
6985

6986 6987
        /* Force other thread to wakup from poll */
        safewrite(priv->wakeupSendFD, &ignore, sizeof(ignore));
6988

6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006
        DEBUG("Going to sleep %d %p %p", proc_nr, priv->waitDispatch, thiscall);
        /* Go to sleep while other thread is working... */
        if (virCondWait(&thiscall->cond, &priv->lock) < 0) {
            if (priv->waitDispatch == thiscall) {
                priv->waitDispatch = thiscall->next;
            } else {
                tmp = priv->waitDispatch;
                while (tmp && tmp->next &&
                       tmp->next != thiscall) {
                    tmp = tmp->next;
                }
                if (tmp && tmp->next == thiscall)
                    tmp->next = thiscall->next;
            }
            errorf(flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
                   VIR_ERR_INTERNAL_ERROR, "%s",
                   _("failed to wait on condition"));
            VIR_FREE(thiscall);
7007
            return -1;
7008
        }
7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024

        DEBUG("Wokeup from sleep %d %p %p", proc_nr, priv->waitDispatch, thiscall);
        /* Two reasons we can be woken up
         *  1. Other thread has got our reply ready for us
         *  2. Other thread is all done, and it is our turn to
         *     be the dispatcher to finish waiting for
         *     our reply
         */
        if (thiscall->mode == REMOTE_MODE_COMPLETE ||
            thiscall->mode == REMOTE_MODE_ERROR) {
            /*
             * We avoided catching the buck and our reply is ready !
             * We've already had 'thiscall' removed from the list
             * so just need to (maybe) handle errors & free it
             */
            goto cleanup;
7025
        }
7026 7027 7028

        /* Grr, someone passed the buck onto us ... */

7029
    } else {
7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072
        /* We're first to catch the buck */
        priv->waitDispatch = thiscall;
    }

    DEBUG("We have the buck %d %p %p", proc_nr, priv->waitDispatch, thiscall);
    /*
     * The buck stops here!
     *
     * At this point we're about to own the dispatch
     * process...
     */

    /*
     * Avoid needless wake-ups of the event loop in the
     * case where this call is being made from a different
     * thread than the event loop. These wake-ups would
     * cause the event loop thread to be blocked on the
     * mutex for the duration of the call
     */
    if (priv->watch >= 0)
        virEventUpdateHandle(priv->watch, 0);

    rv = processCalls(conn, priv,
                      flags & REMOTE_CALL_IN_OPEN ? 1 : 0,
                      thiscall);

    if (priv->watch >= 0)
        virEventUpdateHandle(priv->watch, VIR_EVENT_HANDLE_READABLE);

    if (rv < 0) {
        VIR_FREE(thiscall);
        return -1;
    }

cleanup:
    DEBUG("All done with our call %d %p %p", proc_nr, priv->waitDispatch, thiscall);
    if (thiscall->mode == REMOTE_MODE_ERROR) {
        /* See if caller asked us to keep quiet about missing RPCs
         * eg for interop with older servers */
        if (flags & REMOTE_CALL_QUIET_MISSING_RPC &&
            thiscall->err.domain == VIR_FROM_REMOTE &&
            thiscall->err.code == VIR_ERR_RPC &&
            thiscall->err.level == VIR_ERR_ERROR &&
7073
            thiscall->err.message &&
7074 7075 7076 7077 7078 7079
            STRPREFIX(*thiscall->err.message, "unknown procedure")) {
            rv = -2;
        } else {
            server_error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
                          &thiscall->err);
            rv = -1;
7080
        }
7081
        xdr_free((xdrproc_t)xdr_remote_error,  (char *)&thiscall->err);
7082 7083
    } else {
        rv = 0;
7084
    }
7085 7086 7087
    VIR_FREE(thiscall);
    return rv;
}
7088

7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116
/**
 * remoteDomainReadEvent
 *
 * Read the event data off the wire
 */
static virDomainEventPtr
remoteDomainReadEvent(virConnectPtr conn, XDR *xdr)
{
    remote_domain_event_ret ret;
    virDomainPtr dom;
    virDomainEventPtr event = NULL;
    memset (&ret, 0, sizeof ret);

    /* unmarshall parameters, and process it*/
    if (! xdr_remote_domain_event_ret(xdr, &ret) ) {
        error (conn, VIR_ERR_RPC,
               _("remoteDomainProcessEvent: unmarshalling ret"));
        return NULL;
    }

    dom = get_nonnull_domain(conn,ret.dom);
    if (!dom)
        return NULL;

    event = virDomainEventNewFromDom(dom, ret.event, ret.detail);

    virDomainFree(dom);
    return event;
7117 7118
}

7119 7120
static void
remoteDomainQueueEvent(virConnectPtr conn, XDR *xdr)
7121
{
7122 7123
    struct private_data *priv = conn->privateData;
    virDomainEventPtr event;
7124

7125 7126 7127
    event = remoteDomainReadEvent(conn, xdr);
    if (!event)
        return;
7128

7129 7130 7131 7132 7133
    if (virDomainEventQueuePush(priv->domainEvents,
                                event) < 0) {
        DEBUG0("Error adding event to queue");
        virDomainEventFree(event);
    }
7134 7135
}

7136 7137 7138 7139 7140 7141 7142 7143 7144 7145
/** remoteDomainEventFired:
 *
 * The callback for monitoring the remote socket
 * for event data
 */
void
remoteDomainEventFired(int watch,
                       int fd,
                       int event,
                       void *opaque)
7146
{
7147 7148
    virConnectPtr        conn = opaque;
    struct private_data *priv = conn->privateData;
7149

7150
    remoteDriverLock(priv);
7151

7152 7153 7154
    /* This should be impossible, but it doesn't hurt to check */
    if (priv->waitDispatch)
        goto done;
7155

7156
    DEBUG("Event fired %d %d %d %X", watch, fd, event, event);
7157

7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176
    if (event & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR)) {
         DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or "
               "VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__);
         virEventRemoveHandle(watch);
         priv->watch = -1;
         goto done;
    }

    if (fd != priv->sock) {
        virEventRemoveHandle(watch);
        priv->watch = -1;
        goto done;
    }

    if (processCallRecv(conn, priv, 0) < 0)
        DEBUG0("Something went wrong during async message processing");

done:
    remoteDriverUnlock(priv);
7177 7178
}

7179 7180
void
remoteDomainEventQueueFlush(int timer ATTRIBUTE_UNUSED, void *opaque)
7181
{
7182 7183 7184 7185 7186 7187 7188 7189 7190 7191
    virConnectPtr conn = opaque;
    struct private_data *priv = conn->privateData;

    remoteDriverLock(priv);

    virDomainEventQueueDispatch(priv->domainEvents, priv->callbackList,
                                virDomainEventDispatchDefaultFunc, NULL);
    virEventUpdateTimeout(priv->eventFlushTimer, -1);

    remoteDriverUnlock(priv);
7192 7193
}

7194

7195 7196 7197 7198 7199 7200
/* For errors internal to this library. */
static void
error (virConnectPtr conn, virErrorNumber code, const char *info)
{
    const char *errmsg;

7201 7202
    errmsg = virErrorMsg (code, info);
    virRaiseError (conn, NULL, NULL, VIR_FROM_REMOTE,
7203 7204 7205 7206
                     code, VIR_ERR_ERROR, errmsg, info, NULL, 0, 0,
                     errmsg, info);
}

7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223
/* For errors internal to this library.
   Identical to the above, but with a format string and optional params.  */
static void
errorf (virConnectPtr conn, virErrorNumber code, const char *fmt, ...)
{
    const char *errmsg;
    va_list args;
    char errorMessage[256];

    if (fmt) {
        va_start(args, fmt);
        vsnprintf(errorMessage, sizeof errorMessage - 1, fmt, args);
        va_end(args);
    } else {
        errorMessage[0] = '\0';
    }

7224 7225
    errmsg = virErrorMsg (code, errorMessage);
    virRaiseError (conn, NULL, NULL, VIR_FROM_REMOTE,
7226 7227 7228
                     code, VIR_ERR_ERROR,
                     errmsg, errorMessage, NULL, -1, -1,
                     errmsg, errorMessage);
7229 7230
}

7231 7232 7233 7234 7235 7236 7237
/* For errors generated on the server side and sent back to us. */
static void
server_error (virConnectPtr conn, remote_error *err)
{
    virDomainPtr dom;
    virNetworkPtr net;

7238
    /* Get the domain and network, if set. */
7239 7240 7241
    dom = err->dom ? get_nonnull_domain (conn, *err->dom) : NULL;
    net = err->net ? get_nonnull_network (conn, *err->net) : NULL;

7242
    virRaiseError (conn, dom, net,
7243
                     err->domain, err->code, err->level,
D
Daniel P. Berrange 已提交
7244 7245 7246
                     err->str1 ? *err->str1 : NULL,
                     err->str2 ? *err->str2 : NULL,
                     err->str3 ? *err->str3 : NULL,
7247
                     err->int1, err->int2,
D
Daniel P. Berrange 已提交
7248
                     "%s", err->message ? *err->message : NULL);
7249 7250 7251 7252
    if (dom)
        virDomainFree(dom);
    if (net)
        virNetworkFree(net);
7253 7254 7255 7256
}

/* get_nonnull_domain and get_nonnull_network turn an on-wire
 * (name, uuid) pair into virDomainPtr or virNetworkPtr object.
7257
 * These can return NULL if underlying memory allocations fail,
7258
 * but if they do then virterror_internal.has been set.
7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274
 */
static virDomainPtr
get_nonnull_domain (virConnectPtr conn, remote_nonnull_domain domain)
{
    virDomainPtr dom;
    dom = virGetDomain (conn, domain.name, BAD_CAST domain.uuid);
    if (dom) dom->id = domain.id;
    return dom;
}

static virNetworkPtr
get_nonnull_network (virConnectPtr conn, remote_nonnull_network network)
{
    return virGetNetwork (conn, network.name, BAD_CAST network.uuid);
}

D
Daniel Veillard 已提交
7275
static virInterfacePtr
7276
get_nonnull_interface (virConnectPtr conn, remote_nonnull_interface iface)
D
Daniel Veillard 已提交
7277
{
7278
    return virGetInterface (conn, iface.name, iface.mac);
D
Daniel Veillard 已提交
7279 7280
}

7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292
static virStoragePoolPtr
get_nonnull_storage_pool (virConnectPtr conn, remote_nonnull_storage_pool pool)
{
    return virGetStoragePool (conn, pool.name, BAD_CAST pool.uuid);
}

static virStorageVolPtr
get_nonnull_storage_vol (virConnectPtr conn, remote_nonnull_storage_vol vol)
{
    return virGetStorageVol (conn, vol.pool, vol.name, vol.key);
}

7293 7294 7295 7296 7297 7298
static virNodeDevicePtr
get_nonnull_node_device (virConnectPtr conn, remote_nonnull_node_device dev)
{
    return virGetNodeDevice(conn, dev.name);
}

7299 7300 7301 7302
/* Make remote_nonnull_domain and remote_nonnull_network. */
static void
make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr dom_src)
{
7303
    dom_dst->id = dom_src->id;
7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314
    dom_dst->name = dom_src->name;
    memcpy (dom_dst->uuid, dom_src->uuid, VIR_UUID_BUFLEN);
}

static void
make_nonnull_network (remote_nonnull_network *net_dst, virNetworkPtr net_src)
{
    net_dst->name = net_src->name;
    memcpy (net_dst->uuid, net_src->uuid, VIR_UUID_BUFLEN);
}

D
Daniel Veillard 已提交
7315 7316 7317 7318 7319 7320 7321 7322
static void
make_nonnull_interface (remote_nonnull_interface *interface_dst,
                        virInterfacePtr interface_src)
{
    interface_dst->name = interface_src->name;
    interface_dst->mac = interface_src->mac;
}

7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337
static void
make_nonnull_storage_pool (remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr pool_src)
{
    pool_dst->name = pool_src->name;
    memcpy (pool_dst->uuid, pool_src->uuid, VIR_UUID_BUFLEN);
}

static void
make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src)
{
    vol_dst->pool = vol_src->pool;
    vol_dst->name = vol_src->name;
    vol_dst->key = vol_src->key;
}

7338 7339
/*----------------------------------------------------------------------*/

7340 7341 7342 7343 7344
unsigned long remoteVersion(void)
{
    return REMOTE_PROTOCOL_VERSION;
}

7345
static virDriver driver = {
7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382
    VIR_DRV_REMOTE,
    "remote",
    remoteOpen, /* open */
    remoteClose, /* close */
    remoteSupportsFeature, /* supports_feature */
    remoteType, /* type */
    remoteGetVersion, /* version */
    remoteGetHostname, /* getHostname */
    remoteGetMaxVcpus, /* getMaxVcpus */
    remoteNodeGetInfo, /* nodeGetInfo */
    remoteGetCapabilities, /* getCapabilities */
    remoteListDomains, /* listDomains */
    remoteNumOfDomains, /* numOfDomains */
    remoteDomainCreateXML, /* domainCreateXML */
    remoteDomainLookupByID, /* domainLookupByID */
    remoteDomainLookupByUUID, /* domainLookupByUUID */
    remoteDomainLookupByName, /* domainLookupByName */
    remoteDomainSuspend, /* domainSuspend */
    remoteDomainResume, /* domainResume */
    remoteDomainShutdown, /* domainShutdown */
    remoteDomainReboot, /* domainReboot */
    remoteDomainDestroy, /* domainDestroy */
    remoteDomainGetOSType, /* domainGetOSType */
    remoteDomainGetMaxMemory, /* domainGetMaxMemory */
    remoteDomainSetMaxMemory, /* domainSetMaxMemory */
    remoteDomainSetMemory, /* domainSetMemory */
    remoteDomainGetInfo, /* domainGetInfo */
    remoteDomainSave, /* domainSave */
    remoteDomainRestore, /* domainRestore */
    remoteDomainCoreDump, /* domainCoreDump */
    remoteDomainSetVcpus, /* domainSetVcpus */
    remoteDomainPinVcpu, /* domainPinVcpu */
    remoteDomainGetVcpus, /* domainGetVcpus */
    remoteDomainGetMaxVcpus, /* domainGetMaxVcpus */
    remoteDomainGetSecurityLabel, /* domainGetSecurityLabel */
    remoteNodeGetSecurityModel, /* nodeGetSecurityModel */
    remoteDomainDumpXML, /* domainDumpXML */
7383 7384
    remoteDomainXMLFromNative, /* domainXMLFromNative */
    remoteDomainXMLToNative, /* domainXMLToNative */
7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412
    remoteListDefinedDomains, /* listDefinedDomains */
    remoteNumOfDefinedDomains, /* numOfDefinedDomains */
    remoteDomainCreate, /* domainCreate */
    remoteDomainDefineXML, /* domainDefineXML */
    remoteDomainUndefine, /* domainUndefine */
    remoteDomainAttachDevice, /* domainAttachDevice */
    remoteDomainDetachDevice, /* domainDetachDevice */
    remoteDomainGetAutostart, /* domainGetAutostart */
    remoteDomainSetAutostart, /* domainSetAutostart */
    remoteDomainGetSchedulerType, /* domainGetSchedulerType */
    remoteDomainGetSchedulerParameters, /* domainGetSchedulerParameters */
    remoteDomainSetSchedulerParameters, /* domainSetSchedulerParameters */
    remoteDomainMigratePrepare, /* domainMigratePrepare */
    remoteDomainMigratePerform, /* domainMigratePerform */
    remoteDomainMigrateFinish, /* domainMigrateFinish */
    remoteDomainBlockStats, /* domainBlockStats */
    remoteDomainInterfaceStats, /* domainInterfaceStats */
    remoteDomainBlockPeek, /* domainBlockPeek */
    remoteDomainMemoryPeek, /* domainMemoryPeek */
    remoteNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
    remoteNodeGetFreeMemory, /* getFreeMemory */
    remoteDomainEventRegister, /* domainEventRegister */
    remoteDomainEventDeregister, /* domainEventDeregister */
    remoteDomainMigratePrepare2, /* domainMigratePrepare2 */
    remoteDomainMigrateFinish2, /* domainMigrateFinish2 */
    remoteNodeDeviceDettach, /* nodeDeviceDettach */
    remoteNodeDeviceReAttach, /* nodeDeviceReAttach */
    remoteNodeDeviceReset, /* nodeDeviceReset */
7413 7414 7415
};

static virNetworkDriver network_driver = {
7416
    .name = "remote",
7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435
    .open = remoteNetworkOpen,
    .close = remoteNetworkClose,
    .numOfNetworks = remoteNumOfNetworks,
    .listNetworks = remoteListNetworks,
    .numOfDefinedNetworks = remoteNumOfDefinedNetworks,
    .listDefinedNetworks = remoteListDefinedNetworks,
    .networkLookupByUUID = remoteNetworkLookupByUUID,
    .networkLookupByName = remoteNetworkLookupByName,
    .networkCreateXML = remoteNetworkCreateXML,
    .networkDefineXML = remoteNetworkDefineXML,
    .networkUndefine = remoteNetworkUndefine,
    .networkCreate = remoteNetworkCreate,
    .networkDestroy = remoteNetworkDestroy,
    .networkDumpXML = remoteNetworkDumpXML,
    .networkGetBridgeName = remoteNetworkGetBridgeName,
    .networkGetAutostart = remoteNetworkGetAutostart,
    .networkSetAutostart = remoteNetworkSetAutostart,
};

D
Daniel Veillard 已提交
7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450
static virInterfaceDriver interface_driver = {
    .name = "remote",
    .open = remoteInterfaceOpen,
    .close = remoteInterfaceClose,
    .numOfInterfaces = remoteNumOfInterfaces,
    .listInterfaces = remoteListInterfaces,
    .interfaceLookupByName = remoteInterfaceLookupByName,
    .interfaceLookupByMACString = remoteInterfaceLookupByMACString,
    .interfaceGetXMLDesc = remoteInterfaceGetXMLDesc,
    .interfaceDefineXML = remoteInterfaceDefineXML,
    .interfaceUndefine = remoteInterfaceUndefine,
    .interfaceCreate = remoteInterfaceCreate,
    .interfaceDestroy = remoteInterfaceDestroy,
};

7451 7452 7453 7454 7455 7456 7457 7458
static virStorageDriver storage_driver = {
    .name = "remote",
    .open = remoteStorageOpen,
    .close = remoteStorageClose,
    .numOfPools = remoteNumOfStoragePools,
    .listPools = remoteListStoragePools,
    .numOfDefinedPools = remoteNumOfDefinedStoragePools,
    .listDefinedPools = remoteListDefinedStoragePools,
7459
    .findPoolSources = remoteFindStoragePoolSources,
7460
    .poolLookupByName = remoteStoragePoolLookupByName,
7461
    .poolLookupByUUID = remoteStoragePoolLookupByUUID,
7462 7463 7464
    .poolLookupByVolume = remoteStoragePoolLookupByVolume,
    .poolCreateXML = remoteStoragePoolCreateXML,
    .poolDefineXML = remoteStoragePoolDefineXML,
7465
    .poolBuild = remoteStoragePoolBuild,
7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481
    .poolUndefine = remoteStoragePoolUndefine,
    .poolCreate = remoteStoragePoolCreate,
    .poolDestroy = remoteStoragePoolDestroy,
    .poolDelete = remoteStoragePoolDelete,
    .poolRefresh = remoteStoragePoolRefresh,
    .poolGetInfo = remoteStoragePoolGetInfo,
    .poolGetXMLDesc = remoteStoragePoolDumpXML,
    .poolGetAutostart = remoteStoragePoolGetAutostart,
    .poolSetAutostart = remoteStoragePoolSetAutostart,
    .poolNumOfVolumes = remoteStoragePoolNumOfVolumes,
    .poolListVolumes = remoteStoragePoolListVolumes,

    .volLookupByName = remoteStorageVolLookupByName,
    .volLookupByKey = remoteStorageVolLookupByKey,
    .volLookupByPath = remoteStorageVolLookupByPath,
    .volCreateXML = remoteStorageVolCreateXML,
7482
    .volCreateXMLFrom = remoteStorageVolCreateXMLFrom,
7483 7484 7485 7486 7487 7488
    .volDelete = remoteStorageVolDelete,
    .volGetInfo = remoteStorageVolGetInfo,
    .volGetXMLDesc = remoteStorageVolDumpXML,
    .volGetPath = remoteStorageVolGetPath,
};

7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499
static virDeviceMonitor dev_monitor = {
    .name = "remote",
    .open = remoteDevMonOpen,
    .close = remoteDevMonClose,
    .numOfDevices = remoteNodeNumOfDevices,
    .listDevices = remoteNodeListDevices,
    .deviceLookupByName = remoteNodeDeviceLookupByName,
    .deviceDumpXML = remoteNodeDeviceDumpXML,
    .deviceGetParent = remoteNodeDeviceGetParent,
    .deviceNumOfCaps = remoteNodeDeviceNumOfCaps,
    .deviceListCaps = remoteNodeDeviceListCaps,
7500 7501
    .deviceCreateXML = remoteNodeDeviceCreateXML,
    .deviceDestroy = remoteNodeDeviceDestroy
7502 7503 7504
};


A
Atsushi SAKAI 已提交
7505
#ifdef WITH_LIBVIRTD
7506
static virStateDriver state_driver = {
7507
    .initialize = remoteStartup,
7508
};
A
Atsushi SAKAI 已提交
7509
#endif
7510 7511


7512
/** remoteRegister:
7513 7514
 *
 * Register driver with libvirt driver system.
7515 7516
 *
 * Returns -1 on error.
7517 7518 7519 7520 7521 7522
 */
int
remoteRegister (void)
{
    if (virRegisterDriver (&driver) == -1) return -1;
    if (virRegisterNetworkDriver (&network_driver) == -1) return -1;
D
Daniel Veillard 已提交
7523
    if (virRegisterInterfaceDriver (&interface_driver) == -1) return -1;
7524
    if (virRegisterStorageDriver (&storage_driver) == -1) return -1;
7525
    if (virRegisterDeviceMonitor (&dev_monitor) == -1) return -1;
A
Atsushi SAKAI 已提交
7526
#ifdef WITH_LIBVIRTD
7527
    if (virRegisterStateDriver (&state_driver) == -1) return -1;
A
Atsushi SAKAI 已提交
7528
#endif
7529 7530 7531

    return 0;
}