remote.c 220.8 KB
Newer Older
1
/*
2
 * remote.c: handlers for RPC method calls
3
 *
4
 * Copyright (C) 2007-2015 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16
 *
 * 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
17
 * License along with this library.  If not, see
O
Osier Yang 已提交
18
 * <http://www.gnu.org/licenses/>.
19 20 21 22 23 24
 *
 * Author: Richard W.M. Jones <rjones@redhat.com>
 */

#include <config.h>

25
#include "virerror.h"
26

27
#include "remote.h"
28
#include "libvirtd.h"
29 30
#include "libvirt_internal.h"
#include "datatypes.h"
31
#include "viralloc.h"
32
#include "virlog.h"
C
Chris Lalancette 已提交
33
#include "stream.h"
34
#include "viruuid.h"
35
#include "vircommand.h"
36
#include "intprops.h"
37
#include "virnetserverservice.h"
J
Jim Fehlig 已提交
38
#include "virnetserver.h"
39
#include "virfile.h"
40
#include "virtypedparam.h"
41
#include "virdbus.h"
42
#include "virprocess.h"
43 44
#include "remote_protocol.h"
#include "qemu_protocol.h"
45
#include "lxc_protocol.h"
46
#include "virstring.h"
47
#include "object_event.h"
48 49
#include "domain_conf.h"
#include "network_conf.h"
50
#include "virprobe.h"
51
#include "viraccessapicheck.h"
52
#include "viraccessapicheckqemu.h"
53
#include "virpolkit.h"
54
#include "virthreadjob.h"
55 56

#define VIR_FROM_THIS VIR_FROM_RPC
57

58 59
VIR_LOG_INIT("daemon.remote");

60
#if SIZEOF_LONG < 8
E
Eric Blake 已提交
61 62 63
# define HYPER_TO_TYPE(_type, _to, _from)                               \
    do {                                                                \
        if ((_from) != (_type)(_from)) {                                \
64 65 66
            virReportError(VIR_ERR_OVERFLOW,                            \
                           _("conversion from hyper to %s overflowed"), \
                           #_type);                                     \
E
Eric Blake 已提交
67 68 69
            goto cleanup;                                               \
        }                                                               \
        (_to) = (_from);                                                \
70 71 72 73 74 75 76 77 78
    } while (0)

# define HYPER_TO_LONG(_to, _from) HYPER_TO_TYPE(long, _to, _from)
# define HYPER_TO_ULONG(_to, _from) HYPER_TO_TYPE(unsigned long, _to, _from)
#else
# define HYPER_TO_LONG(_to, _from) (_to) = (_from)
# define HYPER_TO_ULONG(_to, _from) (_to) = (_from)
#endif

79 80 81 82
struct daemonClientEventCallback {
    virNetServerClientPtr client;
    int eventID;
    int callbackID;
83
    bool legacy;
84 85
};

86 87 88 89 90 91 92
static virDomainPtr get_nonnull_domain(virConnectPtr conn, remote_nonnull_domain domain);
static virNetworkPtr get_nonnull_network(virConnectPtr conn, remote_nonnull_network network);
static virInterfacePtr get_nonnull_interface(virConnectPtr conn, remote_nonnull_interface iface);
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);
static virSecretPtr get_nonnull_secret(virConnectPtr conn, remote_nonnull_secret secret);
static virNWFilterPtr get_nonnull_nwfilter(virConnectPtr conn, remote_nonnull_nwfilter nwfilter);
93
static virDomainSnapshotPtr get_nonnull_domain_snapshot(virDomainPtr dom, remote_nonnull_domain_snapshot snapshot);
94 95 96 97 98 99 100 101 102
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);
static void make_nonnull_interface(remote_nonnull_interface *interface_dst, virInterfacePtr interface_src);
static void make_nonnull_storage_pool(remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr pool_src);
static void make_nonnull_storage_vol(remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src);
static void make_nonnull_node_device(remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src);
static void make_nonnull_secret(remote_nonnull_secret *secret_dst, virSecretPtr secret_src);
static void make_nonnull_nwfilter(remote_nonnull_nwfilter *net_dst, virNWFilterPtr nwfilter_src);
static void make_nonnull_domain_snapshot(remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src);
103

104 105 106 107 108
static virTypedParameterPtr
remoteDeserializeTypedParameters(remote_typed_param *args_params_val,
                                 u_int args_params_len,
                                 int limit,
                                 int *nparams);
109

110 111 112 113 114 115 116
static int
remoteSerializeTypedParameters(virTypedParameterPtr params,
                               int nparams,
                               remote_typed_param **ret_params_val,
                               u_int *ret_params_len,
                               unsigned int flags);

117 118 119 120 121 122
static int
remoteSerializeDomainDiskErrors(virDomainDiskErrorPtr errors,
                                int nerrors,
                                remote_domain_disk_error **ret_errors_val,
                                u_int *ret_errors_len);

123 124
#include "remote_dispatch.h"
#include "qemu_dispatch.h"
125
#include "lxc_dispatch.h"
C
Chris Lalancette 已提交
126 127


128 129
/* Prototypes */
static void
130
remoteDispatchObjectEventSend(virNetServerClientPtr client,
131
                              virNetServerProgramPtr program,
132 133 134
                              int procnr,
                              xdrproc_t proc,
                              void *data);
135

136 137 138 139 140 141
static void
remoteEventCallbackFree(void *opaque)
{
    VIR_FREE(opaque);
}

142 143 144 145 146 147 148 149 150 151 152 153

static bool
remoteRelayDomainEventCheckACL(virNetServerClientPtr client,
                               virConnectPtr conn, virDomainPtr dom)
{
    virDomainDef def;
    virIdentityPtr identity = NULL;
    bool ret = false;

    /* For now, we just create a virDomainDef with enough contents to
     * satisfy what viraccessdriverpolkit.c references.  This is a bit
     * fragile, but I don't know of anything better.  */
154
    memset(&def, 0, sizeof(def));
155 156 157 158 159 160 161 162 163
    def.name = dom->name;
    memcpy(def.uuid, dom->uuid, VIR_UUID_BUFLEN);

    if (!(identity = virNetServerClientGetIdentity(client)))
        goto cleanup;
    if (virIdentitySetCurrent(identity) < 0)
        goto cleanup;
    ret = virConnectDomainEventRegisterAnyCheckACL(conn, &def);

164
 cleanup:
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
    ignore_value(virIdentitySetCurrent(NULL));
    virObjectUnref(identity);
    return ret;
}


static bool
remoteRelayNetworkEventCheckACL(virNetServerClientPtr client,
                                virConnectPtr conn, virNetworkPtr net)
{
    virNetworkDef def;
    virIdentityPtr identity = NULL;
    bool ret = false;

    /* For now, we just create a virNetworkDef with enough contents to
     * satisfy what viraccessdriverpolkit.c references.  This is a bit
     * fragile, but I don't know of anything better.  */
    def.name = net->name;
    memcpy(def.uuid, net->uuid, VIR_UUID_BUFLEN);

    if (!(identity = virNetServerClientGetIdentity(client)))
        goto cleanup;
    if (virIdentitySetCurrent(identity) < 0)
        goto cleanup;
    ret = virConnectNetworkEventRegisterAnyCheckACL(conn, &def);

191
 cleanup:
192 193 194 195 196 197
    ignore_value(virIdentitySetCurrent(NULL));
    virObjectUnref(identity);
    return ret;
}


198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
static bool
remoteRelayDomainQemuMonitorEventCheckACL(virNetServerClientPtr client,
                                          virConnectPtr conn, virDomainPtr dom)
{
    virDomainDef def;
    virIdentityPtr identity = NULL;
    bool ret = false;

    /* For now, we just create a virDomainDef with enough contents to
     * satisfy what viraccessdriverpolkit.c references.  This is a bit
     * fragile, but I don't know of anything better.  */
    def.name = dom->name;
    memcpy(def.uuid, dom->uuid, VIR_UUID_BUFLEN);

    if (!(identity = virNetServerClientGetIdentity(client)))
        goto cleanup;
    if (virIdentitySetCurrent(identity) < 0)
        goto cleanup;
    ret = virConnectDomainQemuMonitorEventRegisterCheckACL(conn, &def);

218
 cleanup:
219 220 221 222 223 224
    ignore_value(virIdentitySetCurrent(NULL));
    virObjectUnref(identity);
    return ret;
}


225 226 227 228 229 230
static int
remoteRelayDomainEventLifecycle(virConnectPtr conn,
                                virDomainPtr dom,
                                int event,
                                int detail,
                                void *opaque)
231
{
232
    daemonClientEventCallbackPtr callback = opaque;
233
    remote_domain_event_lifecycle_msg data;
234

235 236
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
237 238
        return -1;

239 240
    VIR_DEBUG("Relaying domain lifecycle event %d %d, callback %d legacy %d",
              event, detail, callback->callbackID, callback->legacy);
241

242
    /* build return data */
243
    memset(&data, 0, sizeof(data));
244
    make_nonnull_domain(&data.dom, dom);
245 246
    data.event = event;
    data.detail = detail;
247

248 249 250 251 252 253 254 255 256 257 258 259 260 261
    if (callback->legacy) {
        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE,
                                      (xdrproc_t)xdr_remote_domain_event_lifecycle_msg,
                                      &data);
    } else {
        remote_domain_event_callback_lifecycle_msg msg = { callback->callbackID,
                                                           data };

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_LIFECYCLE,
                                      (xdrproc_t)xdr_remote_domain_event_callback_lifecycle_msg,
                                      &msg);
    }
262

263 264
    return 0;
}
265

266 267 268 269
static int
remoteRelayDomainEventReboot(virConnectPtr conn,
                             virDomainPtr dom,
                             void *opaque)
270
{
271
    daemonClientEventCallbackPtr callback = opaque;
272 273
    remote_domain_event_reboot_msg data;

274 275
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
276 277
        return -1;

278 279
    VIR_DEBUG("Relaying domain reboot event %s %d, callback %d legacy %d",
              dom->name, dom->id, callback->callbackID, callback->legacy);
280 281

    /* build return data */
282
    memset(&data, 0, sizeof(data));
283
    make_nonnull_domain(&data.dom, dom);
284

285 286 287 288 289 290 291 292 293 294 295 296
    if (callback->legacy) {
        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_REBOOT,
                                      (xdrproc_t)xdr_remote_domain_event_reboot_msg, &data);
    } else {
        remote_domain_event_callback_reboot_msg msg = { callback->callbackID,
                                                        data };

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_REBOOT,
                                      (xdrproc_t)xdr_remote_domain_event_callback_reboot_msg, &msg);
    }
297 298 299 300

    return 0;
}

301

302 303 304 305 306
static int
remoteRelayDomainEventRTCChange(virConnectPtr conn,
                                virDomainPtr dom,
                                long long offset,
                                void *opaque)
307
{
308
    daemonClientEventCallbackPtr callback = opaque;
309 310
    remote_domain_event_rtc_change_msg data;

311 312
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
313 314
        return -1;

315 316 317
    VIR_DEBUG("Relaying domain rtc change event %s %d %lld, callback %d legacy %d",
              dom->name, dom->id, offset,
              callback->callbackID, callback->legacy);
318 319

    /* build return data */
320
    memset(&data, 0, sizeof(data));
321
    make_nonnull_domain(&data.dom, dom);
322 323
    data.offset = offset;

324 325 326 327 328 329 330 331 332 333 334 335
    if (callback->legacy) {
        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
                                      (xdrproc_t)xdr_remote_domain_event_rtc_change_msg, &data);
    } else {
        remote_domain_event_callback_rtc_change_msg msg = { callback->callbackID,
                                                            data };

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_RTC_CHANGE,
                                      (xdrproc_t)xdr_remote_domain_event_callback_rtc_change_msg, &msg);
    }
336 337 338 339 340

    return 0;
}


341 342 343 344 345
static int
remoteRelayDomainEventWatchdog(virConnectPtr conn,
                               virDomainPtr dom,
                               int action,
                               void *opaque)
346
{
347
    daemonClientEventCallbackPtr callback = opaque;
348 349
    remote_domain_event_watchdog_msg data;

350 351
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
352 353
        return -1;

354 355
    VIR_DEBUG("Relaying domain watchdog event %s %d %d, callback %d",
              dom->name, dom->id, action, callback->callbackID);
356 357

    /* build return data */
358
    memset(&data, 0, sizeof(data));
359
    make_nonnull_domain(&data.dom, dom);
360 361
    data.action = action;

362 363 364 365 366 367 368 369 370 371 372 373
    if (callback->legacy) {
        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_WATCHDOG,
                                      (xdrproc_t)xdr_remote_domain_event_watchdog_msg, &data);
    } else {
        remote_domain_event_callback_watchdog_msg msg = { callback->callbackID,
                                                          data };

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_WATCHDOG,
                                      (xdrproc_t)xdr_remote_domain_event_callback_watchdog_msg, &msg);
    }
374 375 376 377 378

    return 0;
}


379 380 381 382 383 384 385
static int
remoteRelayDomainEventIOError(virConnectPtr conn,
                              virDomainPtr dom,
                              const char *srcPath,
                              const char *devAlias,
                              int action,
                              void *opaque)
386
{
387
    daemonClientEventCallbackPtr callback = opaque;
388 389
    remote_domain_event_io_error_msg data;

390 391
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
392 393
        return -1;

394 395 396
    VIR_DEBUG("Relaying domain io error %s %d %s %s %d, callback %d",
              dom->name, dom->id, srcPath, devAlias, action,
              callback->callbackID);
397 398

    /* build return data */
399
    memset(&data, 0, sizeof(data));
400 401 402
    if (VIR_STRDUP(data.srcPath, srcPath) < 0 ||
        VIR_STRDUP(data.devAlias, devAlias) < 0)
        goto error;
403
    make_nonnull_domain(&data.dom, dom);
404 405
    data.action = action;

406 407 408 409 410 411 412 413 414 415 416 417
    if (callback->legacy) {
        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_IO_ERROR,
                                      (xdrproc_t)xdr_remote_domain_event_io_error_msg, &data);
    } else {
        remote_domain_event_callback_io_error_msg msg = { callback->callbackID,
                                                          data };

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_IO_ERROR,
                                      (xdrproc_t)xdr_remote_domain_event_callback_io_error_msg, &msg);
    }
418 419

    return 0;
420
 error:
E
Eric Blake 已提交
421 422
    VIR_FREE(data.srcPath);
    VIR_FREE(data.devAlias);
423
    return -1;
424 425 426
}


427 428 429 430 431 432 433 434
static int
remoteRelayDomainEventIOErrorReason(virConnectPtr conn,
                                    virDomainPtr dom,
                                    const char *srcPath,
                                    const char *devAlias,
                                    int action,
                                    const char *reason,
                                    void *opaque)
435
{
436
    daemonClientEventCallbackPtr callback = opaque;
437 438
    remote_domain_event_io_error_reason_msg data;

439 440
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
441 442
        return -1;

443 444 445
    VIR_DEBUG("Relaying domain io error %s %d %s %s %d %s, callback %d",
              dom->name, dom->id, srcPath, devAlias, action, reason,
              callback->callbackID);
446 447

    /* build return data */
448
    memset(&data, 0, sizeof(data));
449 450 451 452
    if (VIR_STRDUP(data.srcPath, srcPath) < 0 ||
        VIR_STRDUP(data.devAlias, devAlias) < 0 ||
        VIR_STRDUP(data.reason, reason) < 0)
        goto error;
453
    data.action = action;
454 455

    make_nonnull_domain(&data.dom, dom);
456

457 458 459 460 461 462 463 464 465 466 467 468
    if (callback->legacy) {
        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON,
                                      (xdrproc_t)xdr_remote_domain_event_io_error_reason_msg, &data);
    } else {
        remote_domain_event_callback_io_error_reason_msg msg = { callback->callbackID,
                                                                 data };

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_IO_ERROR_REASON,
                                      (xdrproc_t)xdr_remote_domain_event_callback_io_error_reason_msg, &msg);
    }
469 470

    return 0;
471

472
 error:
E
Eric Blake 已提交
473 474 475
    VIR_FREE(data.srcPath);
    VIR_FREE(data.devAlias);
    VIR_FREE(data.reason);
476
    return -1;
477 478 479
}


480 481 482 483 484 485 486 487 488
static int
remoteRelayDomainEventGraphics(virConnectPtr conn,
                               virDomainPtr dom,
                               int phase,
                               virDomainEventGraphicsAddressPtr local,
                               virDomainEventGraphicsAddressPtr remote,
                               const char *authScheme,
                               virDomainEventGraphicsSubjectPtr subject,
                               void *opaque)
489
{
490
    daemonClientEventCallbackPtr callback = opaque;
491
    remote_domain_event_graphics_msg data;
492
    size_t i;
493

494 495
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
496 497
        return -1;

498 499
    VIR_DEBUG("Relaying domain graphics event %s %d %d - %d %s %s  - %d %s %s - %s, callback %d",
              dom->name, dom->id, phase,
500 501
              local->family, local->service, local->node,
              remote->family, remote->service, remote->node,
502
              authScheme, callback->callbackID);
503

504
    VIR_DEBUG("Subject %d", subject->nidentity);
505
    for (i = 0; i < subject->nidentity; i++)
506
        VIR_DEBUG("  %s=%s", subject->identities[i].type, subject->identities[i].name);
507 508

    /* build return data */
509
    memset(&data, 0, sizeof(data));
510 511 512
    data.phase = phase;
    data.local.family = local->family;
    data.remote.family = remote->family;
513 514 515 516 517 518
    if (VIR_STRDUP(data.authScheme, authScheme) < 0 ||
        VIR_STRDUP(data.local.node, local->node) < 0 ||
        VIR_STRDUP(data.local.service, local->service) < 0 ||
        VIR_STRDUP(data.remote.node, remote->node) < 0 ||
        VIR_STRDUP(data.remote.service, remote->service) < 0)
        goto error;
519 520

    data.subject.subject_len = subject->nidentity;
521
    if (VIR_ALLOC_N(data.subject.subject_val, data.subject.subject_len) < 0)
522
        goto error;
523

524
    for (i = 0; i < data.subject.subject_len; i++) {
525 526 527
        if (VIR_STRDUP(data.subject.subject_val[i].type, subject->identities[i].type) < 0 ||
            VIR_STRDUP(data.subject.subject_val[i].name, subject->identities[i].name) < 0)
            goto error;
528
    }
529
    make_nonnull_domain(&data.dom, dom);
530

531 532 533 534 535 536 537 538 539 540 541 542
    if (callback->legacy) {
        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_GRAPHICS,
                                      (xdrproc_t)xdr_remote_domain_event_graphics_msg, &data);
    } else {
        remote_domain_event_callback_graphics_msg msg = { callback->callbackID,
                                                          data };

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_GRAPHICS,
                                      (xdrproc_t)xdr_remote_domain_event_callback_graphics_msg, &msg);
    }
543 544

    return 0;
545

546
 error:
E
Eric Blake 已提交
547 548 549 550 551
    VIR_FREE(data.authScheme);
    VIR_FREE(data.local.node);
    VIR_FREE(data.local.service);
    VIR_FREE(data.remote.node);
    VIR_FREE(data.remote.service);
552
    if (data.subject.subject_val != NULL) {
553
        for (i = 0; i < data.subject.subject_len; i++) {
E
Eric Blake 已提交
554 555
            VIR_FREE(data.subject.subject_val[i].type);
            VIR_FREE(data.subject.subject_val[i].name);
556
        }
E
Eric Blake 已提交
557
        VIR_FREE(data.subject.subject_val);
558 559
    }
    return -1;
560 561
}

562 563 564 565 566 567 568
static int
remoteRelayDomainEventBlockJob(virConnectPtr conn,
                               virDomainPtr dom,
                               const char *path,
                               int type,
                               int status,
                               void *opaque)
569
{
570
    daemonClientEventCallbackPtr callback = opaque;
571 572
    remote_domain_event_block_job_msg data;

573 574
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
575 576
        return -1;

577 578
    VIR_DEBUG("Relaying domain block job event %s %d %s %i, %i, callback %d",
              dom->name, dom->id, path, type, status, callback->callbackID);
579 580

    /* build return data */
581
    memset(&data, 0, sizeof(data));
582 583
    if (VIR_STRDUP(data.path, path) < 0)
        goto error;
584 585
    data.type = type;
    data.status = status;
586
    make_nonnull_domain(&data.dom, dom);
587

588 589 590 591 592 593 594 595 596 597 598 599
    if (callback->legacy) {
        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB,
                                      (xdrproc_t)xdr_remote_domain_event_block_job_msg, &data);
    } else {
        remote_domain_event_callback_block_job_msg msg = { callback->callbackID,
                                                           data };

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_BLOCK_JOB,
                                      (xdrproc_t)xdr_remote_domain_event_callback_block_job_msg, &msg);
    }
600 601

    return 0;
602
 error:
E
Eric Blake 已提交
603
    VIR_FREE(data.path);
604
    return -1;
605 606
}

607

608 609 610 611
static int
remoteRelayDomainEventControlError(virConnectPtr conn,
                                   virDomainPtr dom,
                                   void *opaque)
612
{
613
    daemonClientEventCallbackPtr callback = opaque;
614 615
    remote_domain_event_control_error_msg data;

616 617
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
618 619
        return -1;

620 621
    VIR_DEBUG("Relaying domain control error %s %d, callback %d",
              dom->name, dom->id, callback->callbackID);
622 623

    /* build return data */
624
    memset(&data, 0, sizeof(data));
625 626
    make_nonnull_domain(&data.dom, dom);

627 628 629 630 631 632 633 634 635 636 637 638
    if (callback->legacy) {
        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR,
                                      (xdrproc_t)xdr_remote_domain_event_control_error_msg, &data);
    } else {
        remote_domain_event_callback_control_error_msg msg = { callback->callbackID,
                                                               data };

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CONTROL_ERROR,
                                      (xdrproc_t)xdr_remote_domain_event_callback_control_error_msg, &msg);
    }
639 640 641 642 643

    return 0;
}


644 645 646 647 648 649 650 651
static int
remoteRelayDomainEventDiskChange(virConnectPtr conn,
                                 virDomainPtr dom,
                                 const char *oldSrcPath,
                                 const char *newSrcPath,
                                 const char *devAlias,
                                 int reason,
                                 void *opaque)
652
{
653
    daemonClientEventCallbackPtr callback = opaque;
654 655 656
    remote_domain_event_disk_change_msg data;
    char **oldSrcPath_p = NULL, **newSrcPath_p = NULL;

657 658
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
659 660
        return -1;

661 662 663
    VIR_DEBUG("Relaying domain %s %d disk change %s %s %s %d, callback %d",
              dom->name, dom->id, oldSrcPath, newSrcPath, devAlias, reason,
              callback->callbackID);
664 665

    /* build return data */
666
    memset(&data, 0, sizeof(data));
667 668
    if (oldSrcPath &&
        ((VIR_ALLOC(oldSrcPath_p) < 0) ||
669
         VIR_STRDUP(*oldSrcPath_p, oldSrcPath) < 0))
670
        goto error;
671 672 673

    if (newSrcPath &&
        ((VIR_ALLOC(newSrcPath_p) < 0) ||
674
         VIR_STRDUP(*newSrcPath_p, newSrcPath) < 0))
675
        goto error;
676 677 678

    data.oldSrcPath = oldSrcPath_p;
    data.newSrcPath = newSrcPath_p;
679 680
    if (VIR_STRDUP(data.devAlias, devAlias) < 0)
        goto error;
681 682 683 684
    data.reason = reason;

    make_nonnull_domain(&data.dom, dom);

685 686 687 688 689 690 691 692 693 694 695 696
    if (callback->legacy) {
        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE,
                                      (xdrproc_t)xdr_remote_domain_event_disk_change_msg, &data);
    } else {
        remote_domain_event_callback_disk_change_msg msg = { callback->callbackID,
                                                             data };

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DISK_CHANGE,
                                      (xdrproc_t)xdr_remote_domain_event_callback_disk_change_msg, &msg);
    }
697 698 699

    return 0;

700
 error:
M
Michal Privoznik 已提交
701 702
    VIR_FREE(oldSrcPath_p);
    VIR_FREE(newSrcPath_p);
703 704 705 706
    return -1;
}


707 708 709 710 711 712 713
static int
remoteRelayDomainEventTrayChange(virConnectPtr conn,
                                 virDomainPtr dom,
                                 const char *devAlias,
                                 int reason,
                                 void *opaque)
{
714
    daemonClientEventCallbackPtr callback = opaque;
715 716
    remote_domain_event_tray_change_msg data;

717 718
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
719 720
        return -1;

721 722
    VIR_DEBUG("Relaying domain %s %d tray change devAlias: %s reason: %d, callback %d",
              dom->name, dom->id, devAlias, reason, callback->callbackID);
723 724

    /* build return data */
725
    memset(&data, 0, sizeof(data));
726

727
    if (VIR_STRDUP(data.devAlias, devAlias) < 0)
728 729 730 731 732
        return -1;
    data.reason = reason;

    make_nonnull_domain(&data.dom, dom);

733 734 735 736 737 738 739 740 741 742 743 744
    if (callback->legacy) {
        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_TRAY_CHANGE,
                                      (xdrproc_t)xdr_remote_domain_event_tray_change_msg, &data);
    } else {
        remote_domain_event_callback_tray_change_msg msg = { callback->callbackID,
                                                             data };

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_TRAY_CHANGE,
                                      (xdrproc_t)xdr_remote_domain_event_callback_tray_change_msg, &msg);
    }
745 746 747 748

    return 0;
}

749 750 751
static int
remoteRelayDomainEventPMWakeup(virConnectPtr conn,
                               virDomainPtr dom,
E
Eric Blake 已提交
752
                               int reason,
753 754
                               void *opaque)
{
755
    daemonClientEventCallbackPtr callback = opaque;
O
Osier Yang 已提交
756 757
    remote_domain_event_pmwakeup_msg data;

758 759
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
O
Osier Yang 已提交
760 761
        return -1;

762 763
    VIR_DEBUG("Relaying domain %s %d system pmwakeup, callback %d",
              dom->name, dom->id, callback->callbackID);
O
Osier Yang 已提交
764 765

    /* build return data */
766
    memset(&data, 0, sizeof(data));
O
Osier Yang 已提交
767 768
    make_nonnull_domain(&data.dom, dom);

769 770 771 772 773 774
    if (callback->legacy) {
        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_PMWAKEUP,
                                      (xdrproc_t)xdr_remote_domain_event_pmwakeup_msg, &data);
    } else {
        remote_domain_event_callback_pmwakeup_msg msg = { callback->callbackID,
E
Eric Blake 已提交
775
                                                          reason, data };
776 777 778 779 780

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMWAKEUP,
                                      (xdrproc_t)xdr_remote_domain_event_callback_pmwakeup_msg, &msg);
    }
O
Osier Yang 已提交
781 782 783 784

    return 0;
}

785 786 787
static int
remoteRelayDomainEventPMSuspend(virConnectPtr conn,
                                virDomainPtr dom,
E
Eric Blake 已提交
788
                                int reason,
789 790
                                void *opaque)
{
791
    daemonClientEventCallbackPtr callback = opaque;
O
Osier Yang 已提交
792 793
    remote_domain_event_pmsuspend_msg data;

794 795
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
O
Osier Yang 已提交
796 797
        return -1;

798 799
    VIR_DEBUG("Relaying domain %s %d system pmsuspend, callback %d",
              dom->name, dom->id, callback->callbackID);
O
Osier Yang 已提交
800 801

    /* build return data */
802
    memset(&data, 0, sizeof(data));
O
Osier Yang 已提交
803 804
    make_nonnull_domain(&data.dom, dom);

805 806 807 808 809 810
    if (callback->legacy) {
        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND,
                                      (xdrproc_t)xdr_remote_domain_event_pmsuspend_msg, &data);
    } else {
        remote_domain_event_callback_pmsuspend_msg msg = { callback->callbackID,
E
Eric Blake 已提交
811
                                                           reason, data };
812 813 814 815 816

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMSUSPEND,
                                      (xdrproc_t)xdr_remote_domain_event_callback_pmsuspend_msg, &msg);
    }
O
Osier Yang 已提交
817 818 819 820

    return 0;
}

821
static int
822
remoteRelayDomainEventBalloonChange(virConnectPtr conn,
823 824 825 826
                                    virDomainPtr dom,
                                    unsigned long long actual,
                                    void *opaque)
{
827
    daemonClientEventCallbackPtr callback = opaque;
828 829
    remote_domain_event_balloon_change_msg data;

830 831
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
832 833
        return -1;

834 835
    VIR_DEBUG("Relaying domain balloon change event %s %d %lld, callback %d",
              dom->name, dom->id, actual, callback->callbackID);
836 837 838 839 840 841

    /* build return data */
    memset(&data, 0, sizeof(data));
    make_nonnull_domain(&data.dom, dom);
    data.actual = actual;

842 843 844 845 846 847 848 849 850 851 852 853
    if (callback->legacy) {
        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE,
                                      (xdrproc_t)xdr_remote_domain_event_balloon_change_msg, &data);
    } else {
        remote_domain_event_callback_balloon_change_msg msg = { callback->callbackID,
                                                                data };

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_BALLOON_CHANGE,
                                      (xdrproc_t)xdr_remote_domain_event_callback_balloon_change_msg, &msg);
    }
854 855 856 857 858

    return 0;
}


859 860 861
static int
remoteRelayDomainEventPMSuspendDisk(virConnectPtr conn,
                                    virDomainPtr dom,
E
Eric Blake 已提交
862
                                    int reason,
863 864
                                    void *opaque)
{
865
    daemonClientEventCallbackPtr callback = opaque;
866 867
    remote_domain_event_pmsuspend_disk_msg data;

868 869
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
870 871
        return -1;

872 873
    VIR_DEBUG("Relaying domain %s %d system pmsuspend-disk, callback %d",
              dom->name, dom->id, callback->callbackID);
874 875 876 877 878

    /* build return data */
    memset(&data, 0, sizeof(data));
    make_nonnull_domain(&data.dom, dom);

879 880 881 882 883 884
    if (callback->legacy) {
        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND_DISK,
                                      (xdrproc_t)xdr_remote_domain_event_pmsuspend_disk_msg, &data);
    } else {
        remote_domain_event_callback_pmsuspend_disk_msg msg = { callback->callbackID,
E
Eric Blake 已提交
885
                                                                reason, data };
886 887 888 889 890

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMSUSPEND_DISK,
                                      (xdrproc_t)xdr_remote_domain_event_callback_pmsuspend_disk_msg, &msg);
    }
891 892 893 894

    return 0;
}

895
static int
896
remoteRelayDomainEventDeviceRemoved(virConnectPtr conn,
897 898 899 900
                                    virDomainPtr dom,
                                    const char *devAlias,
                                    void *opaque)
{
901
    daemonClientEventCallbackPtr callback = opaque;
902 903
    remote_domain_event_device_removed_msg data;

904 905
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
906 907
        return -1;

908 909
    VIR_DEBUG("Relaying domain device removed event %s %d %s, callback %d",
              dom->name, dom->id, devAlias, callback->callbackID);
910 911 912 913 914 915 916 917 918

    /* build return data */
    memset(&data, 0, sizeof(data));

    if (VIR_STRDUP(data.devAlias, devAlias) < 0)
        return -1;

    make_nonnull_domain(&data.dom, dom);

919 920 921 922 923 924 925 926 927 928 929 930 931 932
    if (callback->legacy) {
        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED,
                                      (xdrproc_t)xdr_remote_domain_event_device_removed_msg,
                                      &data);
    } else {
        remote_domain_event_callback_device_removed_msg msg = { callback->callbackID,
                                                                data };

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVED,
                                      (xdrproc_t)xdr_remote_domain_event_callback_device_removed_msg,
                                      &msg);
    }
933 934 935 936

    return 0;
}

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
static int
remoteRelayDomainEventBlockJob2(virConnectPtr conn,
                                virDomainPtr dom,
                                const char *dst,
                                int type,
                                int status,
                                void *opaque)
{
    daemonClientEventCallbackPtr callback = opaque;
    remote_domain_event_block_job_2_msg data;

    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
        return -1;

    VIR_DEBUG("Relaying domain block job 2 event %s %d %s %i, %i, callback %d",
              dom->name, dom->id, dst, type, status, callback->callbackID);

    /* build return data */
    memset(&data, 0, sizeof(data));
    data.callbackID = callback->callbackID;
    if (VIR_STRDUP(data.dst, dst) < 0)
        goto error;
    data.type = type;
    data.status = status;
    make_nonnull_domain(&data.dom, dom);

    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                  REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_2,
                                  (xdrproc_t)xdr_remote_domain_event_block_job_2_msg, &data);

    return 0;
 error:
    VIR_FREE(data.dst);
    return -1;
}


976 977 978 979 980 981 982 983 984 985 986 987 988 989
static int
remoteRelayDomainEventTunable(virConnectPtr conn,
                              virDomainPtr dom,
                              virTypedParameterPtr params,
                              int nparams,
                              void *opaque)
{
    daemonClientEventCallbackPtr callback = opaque;
    remote_domain_event_callback_tunable_msg data;

    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
        return -1;

990 991
    VIR_DEBUG("Relaying domain tunable event %s %d, callback %d, params %p %d",
              dom->name, dom->id, callback->callbackID, params, nparams);
992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012

    /* build return data */
    memset(&data, 0, sizeof(data));
    data.callbackID = callback->callbackID;
    make_nonnull_domain(&data.dom, dom);

    if (remoteSerializeTypedParameters(params, nparams,
                                       &data.params.params_val,
                                       &data.params.params_len,
                                       VIR_TYPED_PARAM_STRING_OKAY) < 0)
        return -1;

    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                  REMOTE_PROC_DOMAIN_EVENT_CALLBACK_TUNABLE,
                                  (xdrproc_t)xdr_remote_domain_event_callback_tunable_msg,
                                  &data);

    return 0;
}


1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
static int
remoteRelayDomainEventAgentLifecycle(virConnectPtr conn,
                                     virDomainPtr dom,
                                     int state,
                                     int reason,
                                     void *opaque)
{
    daemonClientEventCallbackPtr callback = opaque;
    remote_domain_event_callback_agent_lifecycle_msg data;

    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
        return -1;

    VIR_DEBUG("Relaying domain agent lifecycle event %s %d, callback %d, "
              " state %d, reason %d",
              dom->name, dom->id, callback->callbackID, state, reason);

    /* build return data */
    memset(&data, 0, sizeof(data));
    data.callbackID = callback->callbackID;
    make_nonnull_domain(&data.dom, dom);

    data.state = state;
    data.reason = reason;

    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                  REMOTE_PROC_DOMAIN_EVENT_CALLBACK_AGENT_LIFECYCLE,
                                  (xdrproc_t)xdr_remote_domain_event_callback_agent_lifecycle_msg,
                                  &data);

    return 0;
}


1048
static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
1049
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
1050
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot),
1051
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventRTCChange),
1052
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventWatchdog),
1053
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOError),
1054
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventGraphics),
1055
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOErrorReason),
1056
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventControlError),
1057
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob),
1058
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDiskChange),
1059
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventTrayChange),
O
Osier Yang 已提交
1060
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMWakeup),
O
Osier Yang 已提交
1061
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspend),
1062
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBalloonChange),
1063
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspendDisk),
1064
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemoved),
1065
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob2),
1066
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventTunable),
1067
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventAgentLifecycle),
1068 1069 1070 1071
};

verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);

1072
static int
1073
remoteRelayNetworkEventLifecycle(virConnectPtr conn,
1074 1075 1076 1077
                                 virNetworkPtr net,
                                 int event,
                                 int detail,
                                 void *opaque)
1078
{
1079
    daemonClientEventCallbackPtr callback = opaque;
1080 1081
    remote_network_event_lifecycle_msg data;

1082 1083
    if (callback->callbackID < 0 ||
        !remoteRelayNetworkEventCheckACL(callback->client, conn, net))
1084 1085
        return -1;

1086 1087
    VIR_DEBUG("Relaying network lifecycle event %d, detail %d, callback %d",
              event, detail, callback->callbackID);
1088 1089 1090 1091

    /* build return data */
    memset(&data, 0, sizeof(data));
    make_nonnull_network(&data.net, net);
1092
    data.callbackID = callback->callbackID;
1093 1094 1095
    data.event = event;
    data.detail = detail;

1096
    remoteDispatchObjectEventSend(callback->client, remoteProgram,
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
                                  REMOTE_PROC_NETWORK_EVENT_LIFECYCLE,
                                  (xdrproc_t)xdr_remote_network_event_lifecycle_msg, &data);

    return 0;
}

static virConnectNetworkEventGenericCallback networkEventCallbacks[] = {
    VIR_NETWORK_EVENT_CALLBACK(remoteRelayNetworkEventLifecycle),
};

verify(ARRAY_CARDINALITY(networkEventCallbacks) == VIR_NETWORK_EVENT_ID_LAST);

1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
static void
remoteRelayDomainQemuMonitorEvent(virConnectPtr conn,
                                  virDomainPtr dom,
                                  const char *event,
                                  long long seconds,
                                  unsigned int micros,
                                  const char *details,
                                  void *opaque)
{
    daemonClientEventCallbackPtr callback = opaque;
    qemu_domain_monitor_event_msg data;
    char **details_p = NULL;

    if (callback->callbackID < 0 ||
        !remoteRelayDomainQemuMonitorEventCheckACL(callback->client, conn,
                                                   dom))
        return;

    VIR_DEBUG("Relaying qemu monitor event %s %s, callback %d",
              event, details, callback->callbackID);

    /* build return data */
    memset(&data, 0, sizeof(data));
    data.callbackID = callback->callbackID;
    if (VIR_STRDUP(data.event, event) < 0)
        goto error;
    data.seconds = seconds;
    data.micros = micros;
    if (details &&
        ((VIR_ALLOC(details_p) < 0) ||
         VIR_STRDUP(*details_p, details) < 0))
        goto error;
    data.details = details_p;
    make_nonnull_domain(&data.dom, dom);

    remoteDispatchObjectEventSend(callback->client, qemuProgram,
                                  QEMU_PROC_DOMAIN_MONITOR_EVENT,
                                  (xdrproc_t)xdr_qemu_domain_monitor_event_msg,
                                  &data);
    return;

1150
 error:
1151 1152 1153 1154
    VIR_FREE(data.event);
    VIR_FREE(details_p);
}

1155 1156 1157 1158 1159 1160 1161
/*
 * You must hold lock for at least the client
 * We don't free stuff here, merely disconnect the client's
 * network socket & resources.
 * We keep the libvirt connection open until any async
 * jobs have finished, then clean it up elsewhere
 */
1162
void remoteClientFreeFunc(void *data)
1163 1164 1165 1166 1167
{
    struct daemonClientPrivate *priv = data;

    /* Deregister event delivery callback */
    if (priv->conn) {
1168
        virIdentityPtr sysident = virIdentityGetSystem();
1169
        size_t i;
1170

1171 1172
        virIdentitySetCurrent(sysident);

1173 1174 1175 1176 1177
        for (i = 0; i < priv->ndomainEventCallbacks; i++) {
            int callbackID = priv->domainEventCallbacks[i]->callbackID;
            if (callbackID < 0) {
                VIR_WARN("unexpected incomplete domain callback %zu", i);
                continue;
1178
            }
1179 1180 1181 1182 1183
            VIR_DEBUG("Deregistering remote domain event relay %d",
                      callbackID);
            priv->domainEventCallbacks[i]->callbackID = -1;
            if (virConnectDomainEventDeregisterAny(priv->conn, callbackID) < 0)
                VIR_WARN("unexpected domain event deregister failure");
1184
        }
1185
        VIR_FREE(priv->domainEventCallbacks);
1186

1187 1188 1189 1190 1191
        for (i = 0; i < priv->nnetworkEventCallbacks; i++) {
            int callbackID = priv->networkEventCallbacks[i]->callbackID;
            if (callbackID < 0) {
                VIR_WARN("unexpected incomplete network callback %zu", i);
                continue;
1192
            }
1193 1194 1195 1196 1197 1198
            VIR_DEBUG("Deregistering remote network event relay %d",
                      callbackID);
            priv->networkEventCallbacks[i]->callbackID = -1;
            if (virConnectNetworkEventDeregisterAny(priv->conn,
                                                    callbackID) < 0)
                VIR_WARN("unexpected network event deregister failure");
1199
        }
1200
        VIR_FREE(priv->networkEventCallbacks);
1201

1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216
        for (i = 0; i < priv->nqemuEventCallbacks; i++) {
            int callbackID = priv->qemuEventCallbacks[i]->callbackID;
            if (callbackID < 0) {
                VIR_WARN("unexpected incomplete qemu monitor callback %zu", i);
                continue;
            }
            VIR_DEBUG("Deregistering remote qemu monitor event relay %d",
                      callbackID);
            priv->qemuEventCallbacks[i]->callbackID = -1;
            if (virConnectDomainQemuMonitorEventDeregister(priv->conn,
                                                           callbackID) < 0)
                VIR_WARN("unexpected qemu monitor event deregister failure");
        }
        VIR_FREE(priv->qemuEventCallbacks);

1217
        virConnectClose(priv->conn);
1218 1219 1220

        virIdentitySetCurrent(NULL);
        virObjectUnref(sysident);
1221 1222 1223 1224 1225 1226
    }

    VIR_FREE(priv);
}


1227 1228 1229 1230 1231 1232 1233
static void remoteClientCloseFunc(virNetServerClientPtr client)
{
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);

    daemonRemoveAllClientStreams(priv->streams);
}

1234

1235 1236
void *remoteClientInitHook(virNetServerClientPtr client,
                           void *opaque ATTRIBUTE_UNUSED)
1237 1238 1239
{
    struct daemonClientPrivate *priv;

1240
    if (VIR_ALLOC(priv) < 0)
1241
        return NULL;
1242 1243 1244

    if (virMutexInit(&priv->lock) < 0) {
        VIR_FREE(priv);
1245
        virReportSystemError(errno, "%s", _("unable to init mutex"));
1246
        return NULL;
1247 1248
    }

1249
    virNetServerClientSetCloseHook(client, remoteClientCloseFunc);
1250
    return priv;
1251 1252
}

1253 1254 1255
/*----- Functions. -----*/

static int
1256 1257 1258 1259 1260
remoteDispatchConnectOpen(virNetServerPtr server,
                          virNetServerClientPtr client,
                          virNetMessagePtr msg ATTRIBUTE_UNUSED,
                          virNetMessageErrorPtr rerr,
                          struct remote_connect_open_args *args)
1261 1262
{
    const char *name;
1263
    unsigned int flags;
1264
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
1265
    int rv = -1;
1266

1267 1268 1269 1270
    VIR_DEBUG("priv=%p conn=%p", priv, priv->conn);
    virMutexLock(&priv->lock);
    /* Already opened? */
    if (priv->conn) {
1271
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection already open"));
1272 1273 1274
        goto cleanup;
    }

1275
    if (virNetServerKeepAliveRequired(server) && !priv->keepalive_supported) {
1276 1277
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("keepalive support is required to connect"));
1278 1279 1280
        goto cleanup;
    }

1281 1282 1283 1284 1285 1286
    name = args->name ? *args->name : NULL;

    /* If this connection arrived on a readonly socket, force
     * the connection to be readonly.
     */
    flags = args->flags;
1287 1288
    if (virNetServerClientGetReadonly(client))
        flags |= VIR_CONNECT_RO;
1289

1290
    priv->conn =
1291
        flags & VIR_CONNECT_RO
1292 1293
        ? virConnectOpenReadOnly(name)
        : virConnectOpen(name);
1294

1295
    if (priv->conn == NULL)
1296 1297 1298
        goto cleanup;

    rv = 0;
1299

1300
 cleanup:
1301
    if (rv < 0)
1302 1303
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
1304
    return rv;
1305 1306 1307 1308
}


static int
1309 1310 1311 1312
remoteDispatchConnectClose(virNetServerPtr server ATTRIBUTE_UNUSED,
                           virNetServerClientPtr client ATTRIBUTE_UNUSED,
                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
                           virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED)
1313
{
1314
    virNetServerClientDelayedClose(client);
1315
    return 0;
1316 1317
}

1318

1319
static int
1320 1321
remoteDispatchDomainGetSchedulerType(virNetServerPtr server ATTRIBUTE_UNUSED,
                                     virNetServerClientPtr client ATTRIBUTE_UNUSED,
1322
                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
1323
                                     virNetMessageErrorPtr rerr,
1324 1325
                                     remote_domain_get_scheduler_type_args *args,
                                     remote_domain_get_scheduler_type_ret *ret)
1326
{
1327
    virDomainPtr dom = NULL;
1328 1329
    char *type;
    int nparams;
1330
    int rv = -1;
1331 1332
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
1333

1334
    if (!priv->conn) {
1335
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
1336
        goto cleanup;
1337 1338
    }

1339
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
1340
        goto cleanup;
1341

1342
    if (!(type = virDomainGetSchedulerType(dom, &nparams)))
1343
        goto cleanup;
1344 1345 1346

    ret->type = type;
    ret->nparams = nparams;
1347 1348
    rv = 0;

1349
 cleanup:
1350
    if (rv < 0)
1351
        virNetMessageSaveError(rerr);
1352
    virObjectUnref(dom);
1353
    return rv;
1354 1355
}

1356 1357
/* Helper to serialize typed parameters. This also filters out any string
 * parameters that must not be returned to older clients.  */
1358 1359 1360
static int
remoteSerializeTypedParameters(virTypedParameterPtr params,
                               int nparams,
1361
                               remote_typed_param **ret_params_val,
1362 1363
                               u_int *ret_params_len,
                               unsigned int flags)
1364
{
1365 1366
    size_t i;
    size_t j;
1367 1368 1369 1370
    int rv = -1;
    remote_typed_param *val;

    *ret_params_len = nparams;
1371
    if (VIR_ALLOC_N(val, nparams) < 0)
1372 1373
        goto cleanup;

1374
    for (i = 0, j = 0; i < nparams; ++i) {
1375 1376 1377 1378 1379
        /* virDomainGetCPUStats can return a sparse array; also, we
         * can't pass back strings to older clients.  */
        if (!params[i].type ||
            (!(flags & VIR_TYPED_PARAM_STRING_OKAY) &&
             params[i].type == VIR_TYPED_PARAM_STRING)) {
1380 1381 1382 1383
            --*ret_params_len;
            continue;
        }

1384
        /* remoteDispatchClientRequest will free this: */
1385
        if (VIR_STRDUP(val[j].field, params[i].field) < 0)
1386
            goto cleanup;
1387
        val[j].value.type = params[i].type;
1388
        switch (params[i].type) {
1389
        case VIR_TYPED_PARAM_INT:
1390
            val[j].value.remote_typed_param_value_u.i = params[i].value.i;
1391 1392
            break;
        case VIR_TYPED_PARAM_UINT:
1393
            val[j].value.remote_typed_param_value_u.ui = params[i].value.ui;
1394 1395
            break;
        case VIR_TYPED_PARAM_LLONG:
1396
            val[j].value.remote_typed_param_value_u.l = params[i].value.l;
1397 1398
            break;
        case VIR_TYPED_PARAM_ULLONG:
1399
            val[j].value.remote_typed_param_value_u.ul = params[i].value.ul;
1400 1401
            break;
        case VIR_TYPED_PARAM_DOUBLE:
1402
            val[j].value.remote_typed_param_value_u.d = params[i].value.d;
1403 1404
            break;
        case VIR_TYPED_PARAM_BOOLEAN:
1405 1406 1407
            val[j].value.remote_typed_param_value_u.b = params[i].value.b;
            break;
        case VIR_TYPED_PARAM_STRING:
1408
            if (VIR_STRDUP(val[j].value.remote_typed_param_value_u.s, params[i].value.s) < 0)
1409
                goto cleanup;
1410 1411
            break;
        default:
1412 1413
            virReportError(VIR_ERR_RPC, _("unknown parameter type: %d"),
                           params[i].type);
1414 1415
            goto cleanup;
        }
1416
        j++;
1417 1418 1419 1420 1421 1422
    }

    *ret_params_val = val;
    val = NULL;
    rv = 0;

1423
 cleanup:
1424
    if (val) {
1425
        for (i = 0; i < nparams; i++) {
1426
            VIR_FREE(val[i].field);
1427
            if (val[i].value.type == VIR_TYPED_PARAM_STRING)
1428 1429
                VIR_FREE(val[i].value.remote_typed_param_value_u.s);
        }
1430 1431 1432 1433 1434 1435 1436
        VIR_FREE(val);
    }
    return rv;
}

/* Helper to deserialize typed parameters. */
static virTypedParameterPtr
1437 1438
remoteDeserializeTypedParameters(remote_typed_param *args_params_val,
                                 u_int args_params_len,
1439 1440 1441
                                 int limit,
                                 int *nparams)
{
1442
    size_t i = 0;
1443 1444 1445 1446
    int rv = -1;
    virTypedParameterPtr params = NULL;

    /* Check the length of the returned list carefully. */
1447
    if (limit && args_params_len > limit) {
1448
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
1449 1450
        goto cleanup;
    }
1451
    if (VIR_ALLOC_N(params, args_params_len) < 0)
1452 1453 1454 1455 1456 1457 1458 1459
        goto cleanup;

    *nparams = args_params_len;

    /* Deserialise the result. */
    for (i = 0; i < args_params_len; ++i) {
        if (virStrcpyStatic(params[i].field,
                            args_params_val[i].field) == NULL) {
1460 1461 1462
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Parameter %s too big for destination"),
                           args_params_val[i].field);
1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490
            goto cleanup;
        }
        params[i].type = args_params_val[i].value.type;
        switch (params[i].type) {
        case VIR_TYPED_PARAM_INT:
            params[i].value.i =
                args_params_val[i].value.remote_typed_param_value_u.i;
            break;
        case VIR_TYPED_PARAM_UINT:
            params[i].value.ui =
                args_params_val[i].value.remote_typed_param_value_u.ui;
            break;
        case VIR_TYPED_PARAM_LLONG:
            params[i].value.l =
                args_params_val[i].value.remote_typed_param_value_u.l;
            break;
        case VIR_TYPED_PARAM_ULLONG:
            params[i].value.ul =
                args_params_val[i].value.remote_typed_param_value_u.ul;
            break;
        case VIR_TYPED_PARAM_DOUBLE:
            params[i].value.d =
                args_params_val[i].value.remote_typed_param_value_u.d;
            break;
        case VIR_TYPED_PARAM_BOOLEAN:
            params[i].value.b =
                args_params_val[i].value.remote_typed_param_value_u.b;
            break;
1491
        case VIR_TYPED_PARAM_STRING:
1492 1493
            if (VIR_STRDUP(params[i].value.s,
                           args_params_val[i].value.remote_typed_param_value_u.s) < 0)
1494 1495
                goto cleanup;
            break;
1496
        default:
1497 1498
            virReportError(VIR_ERR_INTERNAL_ERROR, _("unknown parameter type: %d"),
                           params[i].type);
1499 1500 1501 1502 1503 1504
            goto cleanup;
        }
    }

    rv = 0;

1505
 cleanup:
1506
    if (rv < 0) {
1507 1508
        virTypedParamsFree(params, i);
        params = NULL;
1509
    }
1510 1511 1512
    return params;
}

1513
static int
1514 1515
remoteDispatchDomainGetSchedulerParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
                                           virNetServerClientPtr client ATTRIBUTE_UNUSED,
1516
                                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
1517
                                           virNetMessageErrorPtr rerr,
1518 1519
                                           remote_domain_get_scheduler_parameters_args *args,
                                           remote_domain_get_scheduler_parameters_ret *ret)
1520
{
1521
    virDomainPtr dom = NULL;
1522
    virTypedParameterPtr params = NULL;
1523
    int nparams = 0;
1524
    int rv = -1;
1525 1526
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
1527

1528
    if (!priv->conn) {
1529
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
1530
        goto cleanup;
1531 1532
    }

1533
    if (args->nparams > REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX) {
1534
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
1535
        goto cleanup;
1536
    }
1537
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
1538
        goto cleanup;
1539
    nparams = args->nparams;
1540

1541
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
1542
        goto cleanup;
1543

1544
    if (virDomainGetSchedulerParameters(dom, params, &nparams) < 0)
1545
        goto cleanup;
1546

1547
    if (remoteSerializeTypedParameters(params, nparams,
1548
                                       &ret->params.params_val,
1549 1550
                                       &ret->params.params_len,
                                       0) < 0)
1551 1552 1553 1554
        goto cleanup;

    rv = 0;

1555
 cleanup:
1556
    if (rv < 0)
1557
        virNetMessageSaveError(rerr);
1558
    virTypedParamsFree(params, nparams);
1559
    virObjectUnref(dom);
1560 1561 1562
    return rv;
}

1563 1564 1565 1566 1567 1568 1569 1570 1571 1572
static int
remoteDispatchConnectListAllDomains(virNetServerPtr server ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client,
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                    virNetMessageErrorPtr rerr,
                                    remote_connect_list_all_domains_args *args,
                                    remote_connect_list_all_domains_ret *ret)
{
    virDomainPtr *doms = NULL;
    int ndomains = 0;
1573
    size_t i;
1574 1575 1576 1577
    int rv = -1;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
1578
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
1579 1580 1581 1582 1583 1584 1585 1586
        goto cleanup;
    }

    if ((ndomains = virConnectListAllDomains(priv->conn,
                                             args->need_results ? &doms : NULL,
                                             args->flags)) < 0)
        goto cleanup;

1587 1588 1589 1590 1591 1592 1593
    if (ndomains > REMOTE_DOMAIN_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many domains '%d' for limit '%d'"),
                       ndomains, REMOTE_DOMAIN_LIST_MAX);
        goto cleanup;
    }

1594
    if (doms && ndomains) {
1595
        if (VIR_ALLOC_N(ret->domains.domains_val, ndomains) < 0)
1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610
            goto cleanup;

        ret->domains.domains_len = ndomains;

        for (i = 0; i < ndomains; i++)
            make_nonnull_domain(ret->domains.domains_val + i, doms[i]);
    } else {
        ret->domains.domains_len = 0;
        ret->domains.domains_val = NULL;
    }

    ret->ret = ndomains;

    rv = 0;

1611
 cleanup:
1612 1613
    if (rv < 0)
        virNetMessageSaveError(rerr);
1614
    if (doms && ndomains > 0)
1615
        for (i = 0; i < ndomains; i++)
1616
            virObjectUnref(doms[i]);
1617
    VIR_FREE(doms);
1618 1619 1620
    return rv;
}

1621
static int
1622 1623
remoteDispatchDomainGetSchedulerParametersFlags(virNetServerPtr server ATTRIBUTE_UNUSED,
                                                virNetServerClientPtr client ATTRIBUTE_UNUSED,
1624
                                                virNetMessagePtr msg ATTRIBUTE_UNUSED,
1625
                                                virNetMessageErrorPtr rerr,
1626 1627 1628 1629 1630
                                                remote_domain_get_scheduler_parameters_flags_args *args,
                                                remote_domain_get_scheduler_parameters_flags_ret *ret)
{
    virDomainPtr dom = NULL;
    virTypedParameterPtr params = NULL;
1631
    int nparams = 0;
1632
    int rv = -1;
1633 1634
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
1635

1636
    if (!priv->conn) {
1637
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
1638 1639 1640
        goto cleanup;
    }

1641
    if (args->nparams > REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX) {
1642
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
1643 1644
        goto cleanup;
    }
1645
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
1646
        goto cleanup;
1647
    nparams = args->nparams;
1648

1649
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
1650 1651 1652 1653 1654 1655 1656
        goto cleanup;

    if (virDomainGetSchedulerParametersFlags(dom, params, &nparams,
                                             args->flags) < 0)
        goto cleanup;

    if (remoteSerializeTypedParameters(params, nparams,
1657
                                       &ret->params.params_val,
1658 1659
                                       &ret->params.params_len,
                                       args->flags) < 0)
1660
        goto cleanup;
1661

1662
    rv = 0;
1663

1664
 cleanup:
1665
    if (rv < 0)
1666
        virNetMessageSaveError(rerr);
1667
    virTypedParamsFree(params, nparams);
1668
    virObjectUnref(dom);
1669
    return rv;
1670 1671
}

1672
static int
1673 1674
remoteDispatchDomainMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED,
                                virNetServerClientPtr client ATTRIBUTE_UNUSED,
1675
                                virNetMessagePtr msg ATTRIBUTE_UNUSED,
1676
                                virNetMessageErrorPtr rerr,
1677 1678
                                remote_domain_memory_stats_args *args,
                                remote_domain_memory_stats_ret *ret)
1679
{
1680
    virDomainPtr dom = NULL;
1681
    virDomainMemoryStatPtr stats = NULL;
1682 1683
    int nr_stats;
    size_t i;
1684
    int rv = -1;
1685 1686
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
1687

1688
    if (!priv->conn) {
1689
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
1690
        goto cleanup;
1691 1692
    }

1693
    if (args->maxStats > REMOTE_DOMAIN_MEMORY_STATS_MAX) {
1694 1695
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("maxStats > REMOTE_DOMAIN_MEMORY_STATS_MAX"));
1696
        goto cleanup;
1697 1698
    }

1699
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
1700
        goto cleanup;
1701 1702

    /* Allocate stats array for making dispatch call */
1703
    if (VIR_ALLOC_N(stats, args->maxStats) < 0)
1704
        goto cleanup;
1705

1706
    nr_stats = virDomainMemoryStats(dom, stats, args->maxStats, args->flags);
1707
    if (nr_stats < 0)
1708
        goto cleanup;
1709 1710

    /* Allocate return buffer */
1711
    if (VIR_ALLOC_N(ret->stats.stats_val, args->maxStats) < 0)
1712
        goto cleanup;
1713 1714 1715 1716 1717 1718 1719

    /* Copy the stats into the xdr return structure */
    for (i = 0; i < nr_stats; i++) {
        ret->stats.stats_val[i].tag = stats[i].tag;
        ret->stats.stats_val[i].val = stats[i].val;
    }
    ret->stats.stats_len = nr_stats;
1720 1721
    rv = 0;

1722
 cleanup:
1723
    if (rv < 0)
1724
        virNetMessageSaveError(rerr);
1725
    virObjectUnref(dom);
1726
    VIR_FREE(stats);
1727
    return rv;
1728 1729
}

1730
static int
1731 1732
remoteDispatchDomainBlockPeek(virNetServerPtr server ATTRIBUTE_UNUSED,
                              virNetServerClientPtr client ATTRIBUTE_UNUSED,
1733
                              virNetMessagePtr msg ATTRIBUTE_UNUSED,
1734
                              virNetMessageErrorPtr rerr,
1735 1736
                              remote_domain_block_peek_args *args,
                              remote_domain_block_peek_ret *ret)
1737
{
1738
    virDomainPtr dom = NULL;
1739 1740 1741 1742
    char *path;
    unsigned long long offset;
    size_t size;
    unsigned int flags;
1743
    int rv = -1;
1744 1745
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
1746

1747
    if (!priv->conn) {
1748
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
1749
        goto cleanup;
1750 1751
    }

1752
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
1753
        goto cleanup;
1754 1755 1756 1757 1758 1759
    path = args->path;
    offset = args->offset;
    size = args->size;
    flags = args->flags;

    if (size > REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX) {
1760 1761
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("size > maximum buffer size"));
1762
        goto cleanup;
1763 1764 1765
    }

    ret->buffer.buffer_len = size;
1766
    if (VIR_ALLOC_N(ret->buffer.buffer_val, size) < 0)
1767
        goto cleanup;
1768

1769
    if (virDomainBlockPeek(dom, path, offset, size,
1770
                           ret->buffer.buffer_val, flags) < 0)
1771
        goto cleanup;
1772

1773 1774
    rv = 0;

1775
 cleanup:
1776
    if (rv < 0) {
1777
        virNetMessageSaveError(rerr);
1778 1779
        VIR_FREE(ret->buffer.buffer_val);
    }
1780
    virObjectUnref(dom);
1781
    return rv;
1782 1783
}

1784 1785 1786
static int
remoteDispatchDomainBlockStatsFlags(virNetServerPtr server ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
1787
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
1788 1789 1790 1791 1792 1793 1794
                                    virNetMessageErrorPtr rerr,
                                    remote_domain_block_stats_flags_args *args,
                                    remote_domain_block_stats_flags_ret *ret)
{
    virTypedParameterPtr params = NULL;
    virDomainPtr dom = NULL;
    const char *path = args->path;
1795
    int nparams = 0;
1796 1797 1798 1799 1800 1801
    unsigned int flags;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
1802
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
1803 1804 1805 1806 1807 1808 1809
        goto cleanup;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;
    flags = args->flags;

1810
    if (args->nparams > REMOTE_DOMAIN_BLOCK_STATS_PARAMETERS_MAX) {
1811
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
1812 1813
        goto cleanup;
    }
1814
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
1815
        goto cleanup;
1816
    nparams = args->nparams;
1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831

    if (virDomainBlockStatsFlags(dom, path, params, &nparams, flags) < 0)
        goto cleanup;

    /* In this case, we need to send back the number of parameters
     * supported
     */
    if (args->nparams == 0) {
        ret->nparams = nparams;
        goto success;
    }

    /* Serialise the block stats. */
    if (remoteSerializeTypedParameters(params, nparams,
                                       &ret->params.params_val,
1832 1833
                                       &ret->params.params_len,
                                       args->flags) < 0)
1834 1835
        goto cleanup;

1836
 success:
1837 1838
    rv = 0;

1839
 cleanup:
1840
    if (rv < 0)
1841
        virNetMessageSaveError(rerr);
1842
    virTypedParamsFree(params, nparams);
1843
    virObjectUnref(dom);
1844 1845 1846
    return rv;
}

R
Richard W.M. Jones 已提交
1847
static int
1848 1849
remoteDispatchDomainMemoryPeek(virNetServerPtr server ATTRIBUTE_UNUSED,
                               virNetServerClientPtr client ATTRIBUTE_UNUSED,
1850
                               virNetMessagePtr msg ATTRIBUTE_UNUSED,
1851
                               virNetMessageErrorPtr rerr,
1852 1853
                               remote_domain_memory_peek_args *args,
                               remote_domain_memory_peek_ret *ret)
R
Richard W.M. Jones 已提交
1854
{
1855
    virDomainPtr dom = NULL;
R
Richard W.M. Jones 已提交
1856 1857 1858
    unsigned long long offset;
    size_t size;
    unsigned int flags;
1859
    int rv = -1;
1860 1861
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
R
Richard W.M. Jones 已提交
1862

1863
    if (!priv->conn) {
1864
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
1865
        goto cleanup;
1866 1867
    }

1868
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
1869
        goto cleanup;
R
Richard W.M. Jones 已提交
1870 1871 1872 1873 1874
    offset = args->offset;
    size = args->size;
    flags = args->flags;

    if (size > REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX) {
1875 1876
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("size > maximum buffer size"));
1877
        goto cleanup;
R
Richard W.M. Jones 已提交
1878 1879 1880
    }

    ret->buffer.buffer_len = size;
1881
    if (VIR_ALLOC_N(ret->buffer.buffer_val, size) < 0)
1882
        goto cleanup;
R
Richard W.M. Jones 已提交
1883

1884
    if (virDomainMemoryPeek(dom, offset, size,
1885
                            ret->buffer.buffer_val, flags) < 0)
1886
        goto cleanup;
R
Richard W.M. Jones 已提交
1887

1888 1889
    rv = 0;

1890
 cleanup:
1891
    if (rv < 0) {
1892
        virNetMessageSaveError(rerr);
1893 1894
        VIR_FREE(ret->buffer.buffer_val);
    }
1895
    virObjectUnref(dom);
1896
    return rv;
R
Richard W.M. Jones 已提交
1897 1898
}

1899
static int
1900 1901
remoteDispatchDomainGetSecurityLabel(virNetServerPtr server ATTRIBUTE_UNUSED,
                                     virNetServerClientPtr client ATTRIBUTE_UNUSED,
1902
                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
1903
                                     virNetMessageErrorPtr rerr,
1904 1905
                                     remote_domain_get_security_label_args *args,
                                     remote_domain_get_security_label_ret *ret)
1906
{
1907 1908
    virDomainPtr dom = NULL;
    virSecurityLabelPtr seclabel = NULL;
1909
    int rv = -1;
1910 1911
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
1912

1913
    if (!priv->conn) {
1914
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
1915
        goto cleanup;
1916 1917
    }

1918
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
1919 1920
        goto cleanup;

1921
    if (VIR_ALLOC(seclabel) < 0)
1922 1923 1924 1925 1926 1927
        goto cleanup;

    if (virDomainGetSecurityLabel(dom, seclabel) < 0)
        goto cleanup;

    ret->label.label_len = strlen(seclabel->label) + 1;
1928
    if (VIR_ALLOC_N(ret->label.label_val, ret->label.label_len) < 0)
1929
        goto cleanup;
1930 1931
    strcpy(ret->label.label_val, seclabel->label);
    ret->enforcing = seclabel->enforcing;
1932

1933 1934
    rv = 0;

1935
 cleanup:
1936
    if (rv < 0)
1937
        virNetMessageSaveError(rerr);
1938
    virObjectUnref(dom);
1939
    VIR_FREE(seclabel);
1940
    return rv;
1941 1942
}

M
Marcelo Cerri 已提交
1943 1944 1945 1946 1947 1948 1949 1950 1951 1952
static int
remoteDispatchDomainGetSecurityLabelList(virNetServerPtr server ATTRIBUTE_UNUSED,
                                         virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                         virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                         virNetMessageErrorPtr rerr,
                                         remote_domain_get_security_label_list_args *args,
                                         remote_domain_get_security_label_list_ret *ret)
{
    virDomainPtr dom = NULL;
    virSecurityLabelPtr seclabels = NULL;
1953 1954
    int len, rv = -1;
    size_t i;
M
Marcelo Cerri 已提交
1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if ((len = virDomainGetSecurityLabelList(dom, &seclabels)) < 0) {
        ret->ret = len;
        ret->labels.labels_len = 0;
        ret->labels.labels_val = NULL;
        goto done;
    }

1973
    if (VIR_ALLOC_N(ret->labels.labels_val, len) < 0)
M
Marcelo Cerri 已提交
1974 1975 1976 1977 1978
        goto cleanup;

    for (i = 0; i < len; i++) {
        size_t label_len = strlen(seclabels[i].label) + 1;
        remote_domain_get_security_label_ret *cur = &ret->labels.labels_val[i];
1979
        if (VIR_ALLOC_N(cur->label.label_val, label_len) < 0)
M
Marcelo Cerri 已提交
1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990
            goto cleanup;
        if (virStrcpy(cur->label.label_val, seclabels[i].label, label_len) == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("failed to copy security label"));
            goto cleanup;
        }
        cur->label.label_len = label_len;
        cur->enforcing = seclabels[i].enforcing;
    }
    ret->labels.labels_len = ret->ret = len;

1991
 done:
M
Marcelo Cerri 已提交
1992 1993
    rv = 0;

1994
 cleanup:
M
Marcelo Cerri 已提交
1995 1996
    if (rv < 0)
        virNetMessageSaveError(rerr);
1997
    virObjectUnref(dom);
M
Marcelo Cerri 已提交
1998 1999 2000 2001
    VIR_FREE(seclabels);
    return rv;
}

2002
static int
2003 2004
remoteDispatchNodeGetSecurityModel(virNetServerPtr server ATTRIBUTE_UNUSED,
                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
2005
                                   virNetMessagePtr msg ATTRIBUTE_UNUSED,
2006
                                   virNetMessageErrorPtr rerr,
2007
                                   remote_node_get_security_model_ret *ret)
2008
{
2009
    virSecurityModel secmodel;
2010
    int rv = -1;
2011 2012
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2013

2014
    if (!priv->conn) {
2015
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2016
        goto cleanup;
2017 2018
    }

2019
    memset(&secmodel, 0, sizeof(secmodel));
2020
    if (virNodeGetSecurityModel(priv->conn, &secmodel) < 0)
2021 2022 2023
        goto cleanup;

    ret->model.model_len = strlen(secmodel.model) + 1;
2024
    if (VIR_ALLOC_N(ret->model.model_val, ret->model.model_len) < 0)
2025 2026 2027 2028
        goto cleanup;
    strcpy(ret->model.model_val, secmodel.model);

    ret->doi.doi_len = strlen(secmodel.doi) + 1;
2029
    if (VIR_ALLOC_N(ret->doi.doi_val, ret->doi.doi_len) < 0)
2030
        goto cleanup;
2031
    strcpy(ret->doi.doi_val, secmodel.doi);
2032

2033 2034
    rv = 0;

2035
 cleanup:
2036
    if (rv < 0)
2037
        virNetMessageSaveError(rerr);
2038
    return rv;
2039 2040
}

2041
static int
2042 2043
remoteDispatchDomainGetVcpuPinInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
2044
                                   virNetMessagePtr msg ATTRIBUTE_UNUSED,
2045
                                   virNetMessageErrorPtr rerr,
E
Eric Blake 已提交
2046 2047
                                   remote_domain_get_vcpu_pin_info_args *args,
                                   remote_domain_get_vcpu_pin_info_ret *ret)
2048 2049 2050 2051 2052
{
    virDomainPtr dom = NULL;
    unsigned char *cpumaps = NULL;
    int num;
    int rv = -1;
2053 2054
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2055

2056
    if (!priv->conn) {
2057
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2058 2059 2060
        goto cleanup;
    }

2061
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
2062 2063 2064
        goto cleanup;

    if (args->ncpumaps > REMOTE_VCPUINFO_MAX) {
2065
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("ncpumaps > REMOTE_VCPUINFO_MAX"));
2066 2067 2068 2069 2070
        goto cleanup;
    }

    if (INT_MULTIPLY_OVERFLOW(args->ncpumaps, args->maplen) ||
        args->ncpumaps * args->maplen > REMOTE_CPUMAPS_MAX) {
2071
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo * maplen > REMOTE_CPUMAPS_MAX"));
2072 2073 2074 2075 2076 2077
        goto cleanup;
    }

    /* Allocate buffers to take the results. */
    if (args->maplen > 0 &&
        VIR_ALLOC_N(cpumaps, args->ncpumaps * args->maplen) < 0)
2078
        goto cleanup;
2079

E
Eric Blake 已提交
2080
    if ((num = virDomainGetVcpuPinInfo(dom,
2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093
                                       args->ncpumaps,
                                       cpumaps,
                                       args->maplen,
                                       args->flags)) < 0)
        goto cleanup;

    ret->num = num;
    /* Don't need to allocate/copy the cpumaps if we make the reasonable
     * assumption that unsigned char and char are the same size.
     * Note that remoteDispatchClientRequest will free.
     */
    ret->cpumaps.cpumaps_len = args->ncpumaps * args->maplen;
    ret->cpumaps.cpumaps_val = (char *) cpumaps;
2094 2095 2096 2097
    cpumaps = NULL;

    rv = 0;

2098
 cleanup:
2099 2100 2101
    if (rv < 0)
        virNetMessageSaveError(rerr);
    VIR_FREE(cpumaps);
2102
    virObjectUnref(dom);
2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133
    return rv;
}

static int
remoteDispatchDomainPinEmulator(virNetServerPtr server ATTRIBUTE_UNUSED,
                                virNetServerClientPtr client,
                                virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                virNetMessageErrorPtr rerr,
                                remote_domain_pin_emulator_args *args)
{
    int rv = -1;
    virDomainPtr dom = NULL;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if (virDomainPinEmulator(dom,
                             (unsigned char *) args->cpumap.cpumap_val,
                             args->cpumap.cpumap_len,
                             args->flags) < 0)
        goto cleanup;

    rv = 0;

2134
 cleanup:
2135 2136
    if (rv < 0)
        virNetMessageSaveError(rerr);
2137
    virObjectUnref(dom);
2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167
    return rv;
}


static int
remoteDispatchDomainGetEmulatorPinInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
                                       virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                       virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                       virNetMessageErrorPtr rerr,
                                       remote_domain_get_emulator_pin_info_args *args,
                                       remote_domain_get_emulator_pin_info_ret *ret)
{
    virDomainPtr dom = NULL;
    unsigned char *cpumaps = NULL;
    int r;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    /* Allocate buffers to take the results */
    if (args->maplen > 0 &&
        VIR_ALLOC_N(cpumaps, args->maplen) < 0)
2168
        goto cleanup;
2169 2170 2171 2172 2173 2174 2175 2176 2177 2178

    if ((r = virDomainGetEmulatorPinInfo(dom,
                                         cpumaps,
                                         args->maplen,
                                         args->flags)) < 0)
        goto cleanup;

    ret->ret = r;
    ret->cpumaps.cpumaps_len = args->maplen;
    ret->cpumaps.cpumaps_val = (char *) cpumaps;
2179 2180 2181 2182
    cpumaps = NULL;

    rv = 0;

2183
 cleanup:
2184
    if (rv < 0)
2185
        virNetMessageSaveError(rerr);
2186
    VIR_FREE(cpumaps);
2187
    virObjectUnref(dom);
2188 2189 2190
    return rv;
}

2191
static int
2192 2193
remoteDispatchDomainGetVcpus(virNetServerPtr server ATTRIBUTE_UNUSED,
                             virNetServerClientPtr client ATTRIBUTE_UNUSED,
2194
                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
2195
                             virNetMessageErrorPtr rerr,
2196 2197
                             remote_domain_get_vcpus_args *args,
                             remote_domain_get_vcpus_ret *ret)
2198
{
2199
    virDomainPtr dom = NULL;
2200 2201
    virVcpuInfoPtr info = NULL;
    unsigned char *cpumaps = NULL;
2202 2203
    int info_len;
    size_t i;
2204
    int rv = -1;
2205 2206
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2207

2208
    if (!priv->conn) {
2209
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2210
        goto cleanup;
2211 2212
    }

2213
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
2214
        goto cleanup;
2215

2216
    if (args->maxinfo > REMOTE_VCPUINFO_MAX) {
2217
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo > REMOTE_VCPUINFO_MAX"));
2218
        goto cleanup;
2219
    }
2220

2221 2222
    if (INT_MULTIPLY_OVERFLOW(args->maxinfo, args->maplen) ||
        args->maxinfo * args->maplen > REMOTE_CPUMAPS_MAX) {
2223
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo * maplen > REMOTE_CPUMAPS_MAX"));
2224 2225 2226 2227 2228
        goto cleanup;
    }

    /* Allocate buffers to take the results. */
    if (VIR_ALLOC_N(info, args->maxinfo) < 0)
2229
        goto cleanup;
2230 2231
    if (args->maplen > 0 &&
        VIR_ALLOC_N(cpumaps, args->maxinfo * args->maplen) < 0)
2232
        goto cleanup;
2233 2234 2235 2236 2237 2238 2239 2240 2241

    if ((info_len = virDomainGetVcpus(dom,
                                      info, args->maxinfo,
                                      cpumaps, args->maplen)) < 0)
        goto cleanup;

    /* Allocate the return buffer for info. */
    ret->info.info_len = info_len;
    if (VIR_ALLOC_N(ret->info.info_val, info_len) < 0)
2242
        goto cleanup;
2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259

    for (i = 0; i < info_len; ++i) {
        ret->info.info_val[i].number = info[i].number;
        ret->info.info_val[i].state = info[i].state;
        ret->info.info_val[i].cpu_time = info[i].cpuTime;
        ret->info.info_val[i].cpu = info[i].cpu;
    }

    /* Don't need to allocate/copy the cpumaps if we make the reasonable
     * assumption that unsigned char and char are the same size.
     * Note that remoteDispatchClientRequest will free.
     */
    ret->cpumaps.cpumaps_len = args->maxinfo * args->maplen;
    ret->cpumaps.cpumaps_val = (char *) cpumaps;
    cpumaps = NULL;

    rv = 0;
2260

2261
 cleanup:
2262
    if (rv < 0) {
2263
        virNetMessageSaveError(rerr);
2264 2265 2266 2267
        VIR_FREE(ret->info.info_val);
    }
    VIR_FREE(cpumaps);
    VIR_FREE(info);
2268
    virObjectUnref(dom);
2269
    return rv;
2270 2271
}

2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337
static int
remoteDispatchDomainGetIOThreadsInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
                                     virNetServerClientPtr client,
                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                     virNetMessageErrorPtr rerr,
                                     remote_domain_get_iothreads_info_args *args,
                                     remote_domain_get_iothreads_info_ret *ret)
{
    int rv = -1;
    size_t i;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
    virDomainIOThreadInfoPtr *info = NULL;
    virDomainPtr dom = NULL;
    remote_domain_iothread_info *dst;
    int ninfo = 0;

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if ((ninfo = virDomainGetIOThreadsInfo(dom, &info, args->flags)) < 0)
        goto cleanup;

    if (ninfo > REMOTE_IOTHREADS_INFO_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many IOThreads in info: %d for limit %d"),
                       ninfo, REMOTE_IOTHREADS_INFO_MAX);
        goto cleanup;
    }

    if (ninfo) {
        if (VIR_ALLOC_N(ret->info.info_val, ninfo) < 0)
            goto cleanup;

        ret->info.info_len = ninfo;

        for (i = 0; i < ninfo; i++) {
            dst = &ret->info.info_val[i];
            dst->iothread_id = info[i]->iothread_id;

            /* No need to allocate/copy the cpumap if we make the reasonable
             * assumption that unsigned char and char are the same size.
             */
            dst->cpumap.cpumap_len = info[i]->cpumaplen;
            dst->cpumap.cpumap_val = (char *)info[i]->cpumap;
            info[i]->cpumap = NULL;
        }
    } else {
        ret->info.info_len = 0;
        ret->info.info_val = NULL;
    }

    ret->ret = ninfo;

    rv = 0;

 cleanup:
    if (rv < 0)
        virNetMessageSaveError(rerr);
    virObjectUnref(dom);
    if (ninfo >= 0)
        for (i = 0; i < ninfo; i++)
2338
            virDomainIOThreadInfoFree(info[i]);
2339 2340 2341 2342 2343
    VIR_FREE(info);

    return rv;
}

2344
static int
2345 2346
remoteDispatchDomainMigratePrepare(virNetServerPtr server ATTRIBUTE_UNUSED,
                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
2347
                                   virNetMessagePtr msg ATTRIBUTE_UNUSED,
2348
                                   virNetMessageErrorPtr rerr,
2349 2350
                                   remote_domain_migrate_prepare_args *args,
                                   remote_domain_migrate_prepare_ret *ret)
2351
{
2352 2353 2354 2355 2356
    char *cookie = NULL;
    int cookielen = 0;
    char *uri_in;
    char **uri_out;
    char *dname;
2357
    int rv = -1;
2358 2359
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2360

2361
    if (!priv->conn) {
2362
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2363
        goto cleanup;
2364 2365
    }

2366 2367 2368 2369
    uri_in = args->uri_in == NULL ? NULL : *args->uri_in;
    dname = args->dname == NULL ? NULL : *args->dname;

    /* Wacky world of XDR ... */
2370
    if (VIR_ALLOC(uri_out) < 0)
2371
        goto cleanup;
2372

2373
    if (virDomainMigratePrepare(priv->conn, &cookie, &cookielen,
2374 2375
                                uri_in, uri_out,
                                args->flags, dname, args->resource) < 0)
2376
        goto cleanup;
2377

2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388
    /* remoteDispatchClientRequest will free cookie, uri_out and
     * the string if there is one.
     */
    ret->cookie.cookie_len = cookielen;
    ret->cookie.cookie_val = cookie;
    if (*uri_out == NULL) {
        ret->uri_out = NULL;
    } else {
        ret->uri_out = uri_out;
        uri_out = NULL;
    }
2389

2390
    rv = 0;
2391

2392
 cleanup:
2393
    if (rv < 0)
2394
        virNetMessageSaveError(rerr);
2395
    VIR_FREE(uri_out);
2396
    return rv;
2397 2398
}

2399
static int
2400 2401
remoteDispatchDomainMigratePrepare2(virNetServerPtr server ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
2402
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
2403
                                    virNetMessageErrorPtr rerr,
2404 2405
                                    remote_domain_migrate_prepare2_args *args,
                                    remote_domain_migrate_prepare2_ret *ret)
2406
{
2407 2408 2409 2410 2411
    char *cookie = NULL;
    int cookielen = 0;
    char *uri_in;
    char **uri_out;
    char *dname;
2412
    int rv = -1;
2413 2414
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2415

2416
    if (!priv->conn) {
2417
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2418
        goto cleanup;
2419 2420
    }

2421 2422
    uri_in = args->uri_in == NULL ? NULL : *args->uri_in;
    dname = args->dname == NULL ? NULL : *args->dname;
2423

2424
    /* Wacky world of XDR ... */
2425
    if (VIR_ALLOC(uri_out) < 0)
2426
        goto cleanup;
2427

2428
    if (virDomainMigratePrepare2(priv->conn, &cookie, &cookielen,
2429 2430 2431
                                 uri_in, uri_out,
                                 args->flags, dname, args->resource,
                                 args->dom_xml) < 0)
2432
        goto cleanup;
2433

2434 2435 2436 2437 2438 2439
    /* remoteDispatchClientRequest will free cookie, uri_out and
     * the string if there is one.
     */
    ret->cookie.cookie_len = cookielen;
    ret->cookie.cookie_val = cookie;
    ret->uri_out = *uri_out == NULL ? NULL : uri_out;
2440

2441 2442
    rv = 0;

2443
 cleanup:
2444
    if (rv < 0) {
2445
        virNetMessageSaveError(rerr);
2446 2447
        VIR_FREE(uri_out);
    }
2448
    return rv;
2449 2450
}

C
Chris Lalancette 已提交
2451
static int
2452 2453
remoteDispatchDomainGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
                                        virNetServerClientPtr client ATTRIBUTE_UNUSED,
2454
                                        virNetMessagePtr msg ATTRIBUTE_UNUSED,
2455 2456 2457
                                        virNetMessageErrorPtr rerr,
                                        remote_domain_get_memory_parameters_args *args,
                                        remote_domain_get_memory_parameters_ret *ret)
C
Chris Lalancette 已提交
2458
{
2459
    virDomainPtr dom = NULL;
2460
    virTypedParameterPtr params = NULL;
2461
    int nparams = 0;
2462
    unsigned int flags;
2463
    int rv = -1;
2464 2465
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2466

2467
    if (!priv->conn) {
2468
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2469
        goto cleanup;
2470
    }
C
Chris Lalancette 已提交
2471

2472
    flags = args->flags;
C
Chris Lalancette 已提交
2473

2474
    if (args->nparams > REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX) {
2475
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
2476 2477
        goto cleanup;
    }
2478
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
2479
        goto cleanup;
2480
    nparams = args->nparams;
C
Chris Lalancette 已提交
2481

2482
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
2483
        goto cleanup;
C
Chris Lalancette 已提交
2484

2485
    if (virDomainGetMemoryParameters(dom, params, &nparams, flags) < 0)
2486
        goto cleanup;
C
Chris Lalancette 已提交
2487

2488 2489 2490 2491 2492 2493
    /* In this case, we need to send back the number of parameters
     * supported
     */
    if (args->nparams == 0) {
        ret->nparams = nparams;
        goto success;
2494 2495
    }

2496
    if (remoteSerializeTypedParameters(params, nparams,
2497
                                       &ret->params.params_val,
2498 2499
                                       &ret->params.params_len,
                                       args->flags) < 0)
2500
        goto cleanup;
2501

2502
 success:
2503 2504
    rv = 0;

2505
 cleanup:
2506
    if (rv < 0)
2507
        virNetMessageSaveError(rerr);
2508
    virTypedParamsFree(params, nparams);
2509
    virObjectUnref(dom);
2510
    return rv;
2511 2512
}

2513 2514 2515 2516 2517 2518 2519 2520 2521 2522
static int
remoteDispatchDomainGetNumaParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
                                      virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                      virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                      virNetMessageErrorPtr rerr,
                                      remote_domain_get_numa_parameters_args *args,
                                      remote_domain_get_numa_parameters_ret *ret)
{
    virDomainPtr dom = NULL;
    virTypedParameterPtr params = NULL;
2523
    int nparams = 0;
2524 2525 2526 2527 2528 2529
    unsigned int flags;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
2530
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2531 2532 2533 2534 2535
        goto cleanup;
    }

    flags = args->flags;

2536
    if (args->nparams > REMOTE_DOMAIN_NUMA_PARAMETERS_MAX) {
2537
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
2538 2539
        goto cleanup;
    }
2540
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
2541
        goto cleanup;
2542
    nparams = args->nparams;
2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if (virDomainGetNumaParameters(dom, params, &nparams, flags) < 0)
        goto cleanup;

    /* In this case, we need to send back the number of parameters
     * supported
     */
    if (args->nparams == 0) {
        ret->nparams = nparams;
        goto success;
    }

    if (remoteSerializeTypedParameters(params, nparams,
                                       &ret->params.params_val,
                                       &ret->params.params_len,
                                       flags) < 0)
        goto cleanup;

2564
 success:
2565 2566
    rv = 0;

2567
 cleanup:
2568 2569
    if (rv < 0)
        virNetMessageSaveError(rerr);
2570
    virTypedParamsFree(params, nparams);
2571
    virObjectUnref(dom);
2572 2573 2574
    return rv;
}

2575
static int
2576 2577
remoteDispatchDomainGetBlkioParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
                                       virNetServerClientPtr client ATTRIBUTE_UNUSED,
2578
                                       virNetMessagePtr msg ATTRIBUTE_UNUSED,
2579 2580 2581
                                       virNetMessageErrorPtr rerr,
                                       remote_domain_get_blkio_parameters_args *args,
                                       remote_domain_get_blkio_parameters_ret *ret)
2582
{
2583
    virDomainPtr dom = NULL;
2584
    virTypedParameterPtr params = NULL;
2585
    int nparams = 0;
2586
    unsigned int flags;
2587
    int rv = -1;
2588 2589
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2590

2591
    if (!priv->conn) {
2592
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2593
        goto cleanup;
2594 2595
    }

2596 2597
    flags = args->flags;

2598
    if (args->nparams > REMOTE_DOMAIN_BLKIO_PARAMETERS_MAX) {
2599
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
2600
        goto cleanup;
2601
    }
2602
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
2603
        goto cleanup;
2604
    nparams = args->nparams;
2605

2606
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
2607
        goto cleanup;
2608

2609
    if (virDomainGetBlkioParameters(dom, params, &nparams, flags) < 0)
2610
        goto cleanup;
2611

2612 2613 2614 2615 2616 2617 2618 2619
    /* In this case, we need to send back the number of parameters
     * supported
     */
    if (args->nparams == 0) {
        ret->nparams = nparams;
        goto success;
    }

2620
    if (remoteSerializeTypedParameters(params, nparams,
2621
                                       &ret->params.params_val,
2622 2623
                                       &ret->params.params_len,
                                       args->flags) < 0)
2624
        goto cleanup;
2625

2626
 success:
2627
    rv = 0;
2628

2629
 cleanup:
2630
    if (rv < 0)
2631
        virNetMessageSaveError(rerr);
2632
    virTypedParamsFree(params, nparams);
2633
    virObjectUnref(dom);
2634
    return rv;
2635 2636
}

2637
static int
2638 2639
remoteDispatchNodeGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED,
                              virNetServerClientPtr client ATTRIBUTE_UNUSED,
2640
                              virNetMessagePtr msg ATTRIBUTE_UNUSED,
2641 2642 2643
                              virNetMessageErrorPtr rerr,
                              remote_node_get_cpu_stats_args *args,
                              remote_node_get_cpu_stats_ret *ret)
2644
{
2645
    virNodeCPUStatsPtr params = NULL;
2646
    size_t i;
2647
    int cpuNum = args->cpuNum;
2648
    int nparams = 0;
2649 2650
    unsigned int flags;
    int rv = -1;
2651 2652
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2653

2654
    if (!priv->conn) {
2655
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2656 2657 2658 2659 2660
        goto cleanup;
    }

    flags = args->flags;

2661
    if (args->nparams > REMOTE_NODE_CPU_STATS_MAX) {
2662
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
2663 2664
        goto cleanup;
    }
2665
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
2666
        goto cleanup;
2667
    nparams = args->nparams;
2668

2669
    if (virNodeGetCPUStats(priv->conn, cpuNum, params, &nparams, flags) < 0)
2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682
        goto cleanup;

    /* In this case, we need to send back the number of stats
     * supported
     */
    if (args->nparams == 0) {
        ret->nparams = nparams;
        goto success;
    }

    /* Serialise the memory parameters. */
    ret->params.params_len = nparams;
    if (VIR_ALLOC_N(ret->params.params_val, nparams) < 0)
2683
        goto cleanup;
2684 2685 2686

    for (i = 0; i < nparams; ++i) {
        /* remoteDispatchClientRequest will free this: */
2687 2688
        if (VIR_STRDUP(ret->params.params_val[i].field, params[i].field) < 0)
            goto cleanup;
2689 2690 2691 2692

        ret->params.params_val[i].value = params[i].value;
    }

2693
 success:
2694 2695
    rv = 0;

2696
 cleanup:
2697
    if (rv < 0) {
2698
        virNetMessageSaveError(rerr);
2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709
        if (ret->params.params_val) {
            for (i = 0; i < nparams; i++)
                VIR_FREE(ret->params.params_val[i].field);
            VIR_FREE(ret->params.params_val);
        }
    }
    VIR_FREE(params);
    return rv;
}

static int
2710 2711
remoteDispatchNodeGetMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED,
                                 virNetServerClientPtr client ATTRIBUTE_UNUSED,
2712
                                 virNetMessagePtr msg ATTRIBUTE_UNUSED,
2713 2714 2715
                                 virNetMessageErrorPtr rerr,
                                 remote_node_get_memory_stats_args *args,
                                 remote_node_get_memory_stats_ret *ret)
2716
{
2717
    virNodeMemoryStatsPtr params = NULL;
2718
    size_t i;
2719
    int cellNum = args->cellNum;
2720
    int nparams = 0;
2721 2722
    unsigned int flags;
    int rv = -1;
2723 2724
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2725

2726
    if (!priv->conn) {
2727
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2728 2729 2730 2731 2732
        goto cleanup;
    }

    flags = args->flags;

2733
    if (args->nparams > REMOTE_NODE_MEMORY_STATS_MAX) {
2734
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
2735 2736
        goto cleanup;
    }
2737
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
2738
        goto cleanup;
2739
    nparams = args->nparams;
2740

2741
    if (virNodeGetMemoryStats(priv->conn, cellNum, params, &nparams, flags) < 0)
2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754
        goto cleanup;

    /* In this case, we need to send back the number of parameters
     * supported
     */
    if (args->nparams == 0) {
        ret->nparams = nparams;
        goto success;
    }

    /* Serialise the memory parameters. */
    ret->params.params_len = nparams;
    if (VIR_ALLOC_N(ret->params.params_val, nparams) < 0)
2755
        goto cleanup;
2756 2757 2758

    for (i = 0; i < nparams; ++i) {
        /* remoteDispatchClientRequest will free this: */
2759 2760
        if (VIR_STRDUP(ret->params.params_val[i].field, params[i].field) < 0)
            goto cleanup;
2761 2762 2763 2764

        ret->params.params_val[i].value = params[i].value;
    }

2765
 success:
2766 2767
    rv = 0;

2768
 cleanup:
2769
    if (rv < 0) {
2770
        virNetMessageSaveError(rerr);
2771 2772 2773 2774 2775 2776 2777 2778 2779 2780
        if (ret->params.params_val) {
            for (i = 0; i < nparams; i++)
                VIR_FREE(ret->params.params_val[i].field);
            VIR_FREE(ret->params.params_val);
        }
    }
    VIR_FREE(params);
    return rv;
}

2781 2782 2783
static int
remoteDispatchDomainGetBlockJobInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
2784
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795
                                    virNetMessageErrorPtr rerr,
                                    remote_domain_get_block_job_info_args *args,
                                    remote_domain_get_block_job_info_ret *ret)
{
    virDomainPtr dom = NULL;
    virDomainBlockJobInfo tmp;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
2796
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813
        goto cleanup;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    rv = virDomainGetBlockJobInfo(dom, args->path, &tmp, args->flags);
    if (rv <= 0)
        goto cleanup;

    ret->type = tmp.type;
    ret->bandwidth = tmp.bandwidth;
    ret->cur = tmp.cur;
    ret->end = tmp.end;
    ret->found = 1;
    rv = 0;

2814
 cleanup:
2815 2816
    if (rv < 0)
        virNetMessageSaveError(rerr);
2817
    virObjectUnref(dom);
2818 2819 2820
    return rv;
}

2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831
static int
remoteDispatchDomainGetBlockIoTune(virNetServerPtr server ATTRIBUTE_UNUSED,
                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                   virNetMessagePtr hdr ATTRIBUTE_UNUSED,
                                   virNetMessageErrorPtr rerr,
                                   remote_domain_get_block_io_tune_args *args,
                                   remote_domain_get_block_io_tune_ret *ret)
{
    virDomainPtr dom = NULL;
    int rv = -1;
    virTypedParameterPtr params = NULL;
2832
    int nparams = 0;
2833 2834 2835 2836
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
2837
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2838 2839 2840
        goto cleanup;
    }

2841
    if (args->nparams > REMOTE_DOMAIN_BLOCK_IO_TUNE_PARAMETERS_MAX) {
2842
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
2843 2844 2845
        goto cleanup;
    }

2846
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
2847
        goto cleanup;
2848
    nparams = args->nparams;
2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if (virDomainGetBlockIoTune(dom, args->disk ? *args->disk : NULL,
                                params, &nparams, args->flags) < 0)
        goto cleanup;

    /* In this case, we need to send back the number of parameters
     * supported
     */
    if (args->nparams == 0) {
        ret->nparams = nparams;
        goto success;
    }

    /* Serialise the block I/O tuning parameters. */
    if (remoteSerializeTypedParameters(params, nparams,
                                       &ret->params.params_val,
                                       &ret->params.params_len,
                                       args->flags) < 0)
        goto cleanup;

2872
 success:
2873 2874
    rv = 0;

2875
 cleanup:
2876 2877
    if (rv < 0)
        virNetMessageSaveError(rerr);
2878
    virTypedParamsFree(params, nparams);
2879
    virObjectUnref(dom);
2880 2881
    return rv;
}
2882

D
Daniel Veillard 已提交
2883 2884
/*-------------------------------------------------------------*/

2885
static int
2886
remoteDispatchAuthList(virNetServerPtr server,
2887
                       virNetServerClientPtr client,
2888
                       virNetMessagePtr msg ATTRIBUTE_UNUSED,
2889
                       virNetMessageErrorPtr rerr,
2890
                       remote_auth_list_ret *ret)
2891
{
2892
    int rv = -1;
2893 2894
    int auth = virNetServerClientGetAuth(client);
    uid_t callerUid;
2895
    gid_t callerGid;
2896
    pid_t callerPid;
2897
    unsigned long long timestamp;
2898 2899 2900 2901 2902 2903

    /* If the client is root then we want to bypass the
     * policykit auth to avoid root being denied if
     * some piece of polkit isn't present/running
     */
    if (auth == VIR_NET_SERVER_SERVICE_AUTH_POLKIT) {
2904
        if (virNetServerClientGetUNIXIdentity(client, &callerUid, &callerGid,
2905
                                              &callerPid, &timestamp) < 0) {
2906 2907 2908 2909
            /* Don't do anything on error - it'll be validated at next
             * phase of auth anyway */
            virResetLastError();
        } else if (callerUid == 0) {
2910 2911
            char *ident;
            if (virAsprintf(&ident, "pid:%lld,uid:%d",
2912
                            (long long) callerPid, (int) callerUid) < 0)
J
Jim Fehlig 已提交
2913 2914
                goto cleanup;
            VIR_INFO("Bypass polkit auth for privileged client %s", ident);
2915
            virNetServerClientSetAuth(client, 0);
2916
            virNetServerTrackCompletedAuth(server);
2917
            auth = VIR_NET_SERVER_SERVICE_AUTH_NONE;
J
Jim Fehlig 已提交
2918
            VIR_FREE(ident);
2919 2920
        }
    }
2921

2922
    ret->types.types_len = 1;
2923
    if (VIR_ALLOC_N(ret->types.types_val, ret->types.types_len) < 0)
2924
        goto cleanup;
2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938

    switch (auth) {
    case VIR_NET_SERVER_SERVICE_AUTH_NONE:
        ret->types.types_val[0] = REMOTE_AUTH_NONE;
        break;
    case VIR_NET_SERVER_SERVICE_AUTH_POLKIT:
        ret->types.types_val[0] = REMOTE_AUTH_POLKIT;
        break;
    case VIR_NET_SERVER_SERVICE_AUTH_SASL:
        ret->types.types_val[0] = REMOTE_AUTH_SASL;
        break;
    default:
        ret->types.types_val[0] = REMOTE_AUTH_NONE;
    }
2939

2940 2941
    rv = 0;

2942
 cleanup:
2943
    if (rv < 0)
2944
        virNetMessageSaveError(rerr);
2945
    return rv;
2946 2947 2948
}


2949
#ifdef WITH_SASL
2950 2951
/*
 * Initializes the SASL session in prepare for authentication
2952
 * and gives the client a list of allowed mechanisms to choose
2953 2954
 */
static int
2955 2956
remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED,
                           virNetServerClientPtr client,
2957
                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
2958
                           virNetMessageErrorPtr rerr,
2959
                           remote_auth_sasl_init_ret *ret)
2960
{
2961 2962 2963
    virNetSASLSessionPtr sasl = NULL;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2964

2965
    virMutexLock(&priv->lock);
2966

2967 2968 2969
    VIR_DEBUG("Initialize SASL auth %d", virNetServerClientGetFD(client));
    if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
        priv->sasl != NULL) {
2970
        VIR_ERROR(_("client tried invalid SASL init request"));
2971
        goto authfail;
2972 2973
    }

2974 2975 2976 2977 2978
    sasl = virNetSASLSessionNewServer(saslCtxt,
                                      "libvirt",
                                      virNetServerClientLocalAddrString(client),
                                      virNetServerClientRemoteAddrString(client));
    if (!sasl)
2979
        goto authfail;
2980

2981
# if WITH_GNUTLS
2982
    /* Inform SASL that we've got an external SSF layer from TLS */
2983 2984 2985 2986
    if (virNetServerClientHasTLSSession(client)) {
        int ssf;

        if ((ssf = virNetServerClientGetTLSKeySize(client)) < 0)
2987
            goto authfail;
2988 2989 2990 2991 2992

        ssf *= 8; /* key size is bytes, sasl wants bits */

        VIR_DEBUG("Setting external SSF %d", ssf);
        if (virNetSASLSessionExtKeySize(sasl, ssf) < 0)
2993
            goto authfail;
2994
    }
2995
# endif
2996

2997
    if (virNetServerClientIsSecure(client))
2998
        /* If we've got TLS or UNIX domain sock, we don't care about SSF */
2999 3000
        virNetSASLSessionSecProps(sasl, 0, 0, true);
    else
3001
        /* Plain TCP, better get an SSF layer */
3002 3003 3004 3005
        virNetSASLSessionSecProps(sasl,
                                  56,  /* Good enough to require kerberos */
                                  100000,  /* Arbitrary big number */
                                  false); /* No anonymous */
3006

3007
    if (!(ret->mechlist = virNetSASLSessionListMechanisms(sasl)))
3008
        goto authfail;
3009
    VIR_DEBUG("Available mechanisms for client: '%s'", ret->mechlist);
3010

3011 3012
    priv->sasl = sasl;
    virMutexUnlock(&priv->lock);
3013
    return 0;
3014

3015
 authfail:
3016
    virResetLastError();
3017 3018
    virReportError(VIR_ERR_AUTH_FAILED, "%s",
                   _("authentication failed"));
3019
    virNetMessageSaveError(rerr);
3020 3021 3022
    PROBE(RPC_SERVER_CLIENT_AUTH_FAIL,
          "client=%p auth=%d",
          client, REMOTE_AUTH_SASL);
3023
    virObjectUnref(sasl);
3024
    virMutexUnlock(&priv->lock);
3025
    return -1;
3026 3027
}

3028
/*
3029 3030
 * Returns 0 if ok, -1 on error, -2 if rejected
 */
3031
static int
3032 3033
remoteSASLFinish(virNetServerPtr server,
                 virNetServerClientPtr client)
3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048
{
    const char *identity;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
    int ssf;

    /* TLS or UNIX domain sockets trivially OK */
    if (!virNetServerClientIsSecure(client)) {
        if ((ssf = virNetSASLSessionGetKeySize(priv->sasl)) < 0)
            goto error;

        VIR_DEBUG("negotiated an SSF of %d", ssf);
        if (ssf < 56) { /* 56 is good for Kerberos */
            VIR_ERROR(_("negotiated SSF %d was not strong enough"), ssf);
            return -2;
        }
3049
    }
3050 3051

    if (!(identity = virNetSASLSessionGetIdentity(priv->sasl)))
3052
        return -2;
3053

3054 3055
    if (!virNetSASLContextCheckIdentity(saslCtxt, identity))
        return -2;
3056

3057
    virNetServerClientSetAuth(client, 0);
3058
    virNetServerTrackCompletedAuth(server);
3059
    virNetServerClientSetSASLSession(client, priv->sasl);
3060

3061
    VIR_DEBUG("Authentication successful %d", virNetServerClientGetFD(client));
3062

3063 3064 3065
    PROBE(RPC_SERVER_CLIENT_AUTH_ALLOW,
          "client=%p auth=%d identity=%s",
          client, REMOTE_AUTH_SASL, identity);
3066

3067
    virObjectUnref(priv->sasl);
3068
    priv->sasl = NULL;
3069

3070
    return 0;
3071

3072
 error:
3073 3074
    return -1;
}
3075

3076 3077 3078 3079
/*
 * This starts the SASL authentication negotiation.
 */
static int
3080
remoteDispatchAuthSaslStart(virNetServerPtr server,
3081
                            virNetServerClientPtr client,
3082
                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
3083
                            virNetMessageErrorPtr rerr,
3084 3085
                            remote_auth_sasl_start_args *args,
                            remote_auth_sasl_start_ret *ret)
3086 3087
{
    const char *serverout;
3088
    size_t serveroutlen;
3089
    int err;
3090 3091 3092
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3093
    const char *identity;
3094

3095
    virMutexLock(&priv->lock);
3096

3097 3098 3099
    VIR_DEBUG("Start SASL auth %d", virNetServerClientGetFD(client));
    if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
        priv->sasl == NULL) {
3100
        VIR_ERROR(_("client tried invalid SASL start request"));
3101
        goto authfail;
3102 3103
    }

3104 3105
    VIR_DEBUG("Using SASL mechanism %s. Data %d bytes, nil: %d",
              args->mech, args->data.data_len, args->nil);
3106 3107 3108 3109 3110 3111 3112 3113 3114
    err = virNetSASLSessionServerStart(priv->sasl,
                                       args->mech,
                                       /* NB, distinction of NULL vs "" is *critical* in SASL */
                                       args->nil ? NULL : args->data.data_val,
                                       args->data.data_len,
                                       &serverout,
                                       &serveroutlen);
    if (err != VIR_NET_SASL_COMPLETE &&
        err != VIR_NET_SASL_CONTINUE)
3115
        goto authfail;
3116

3117
    if (serveroutlen > REMOTE_AUTH_SASL_DATA_MAX) {
3118
        VIR_ERROR(_("sasl start reply data too long %d"), (int)serveroutlen);
3119
        goto authfail;
3120 3121 3122 3123
    }

    /* NB, distinction of NULL vs "" is *critical* in SASL */
    if (serverout) {
3124 3125
        if (VIR_ALLOC_N(ret->data.data_val, serveroutlen) < 0)
            goto authfail;
3126 3127 3128 3129 3130 3131 3132
        memcpy(ret->data.data_val, serverout, serveroutlen);
    } else {
        ret->data.data_val = NULL;
    }
    ret->nil = serverout ? 0 : 1;
    ret->data.data_len = serveroutlen;

3133
    VIR_DEBUG("SASL return data %d bytes, nil; %d", ret->data.data_len, ret->nil);
3134
    if (err == VIR_NET_SASL_CONTINUE) {
3135 3136
        ret->complete = 0;
    } else {
3137
        /* Check username whitelist ACL */
3138
        if ((err = remoteSASLFinish(server, client)) < 0) {
3139 3140 3141 3142 3143
            if (err == -2)
                goto authdeny;
            else
                goto authfail;
        }
3144

3145 3146 3147
        ret->complete = 1;
    }

3148
    virMutexUnlock(&priv->lock);
3149
    return 0;
3150

3151
 authfail:
3152 3153 3154
    PROBE(RPC_SERVER_CLIENT_AUTH_FAIL,
          "client=%p auth=%d",
          client, REMOTE_AUTH_SASL);
3155 3156
    goto error;

3157
 authdeny:
3158
    identity = virNetSASLSessionGetIdentity(priv->sasl);
3159 3160 3161
    PROBE(RPC_SERVER_CLIENT_AUTH_DENY,
          "client=%p auth=%d identity=%s",
          client, REMOTE_AUTH_SASL, identity);
3162 3163
    goto error;

3164
 error:
3165
    virObjectUnref(priv->sasl);
3166 3167
    priv->sasl = NULL;
    virResetLastError();
3168 3169
    virReportError(VIR_ERR_AUTH_FAILED, "%s",
                   _("authentication failed"));
3170 3171 3172
    if (rv < 0)
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
3173
    return -1;
3174 3175 3176 3177
}


static int
3178
remoteDispatchAuthSaslStep(virNetServerPtr server,
3179
                           virNetServerClientPtr client,
3180
                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
3181
                           virNetMessageErrorPtr rerr,
3182 3183
                           remote_auth_sasl_step_args *args,
                           remote_auth_sasl_step_ret *ret)
3184 3185
{
    const char *serverout;
3186
    size_t serveroutlen;
3187
    int err;
3188 3189 3190
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3191
    const char *identity;
3192

3193 3194 3195 3196 3197
    virMutexLock(&priv->lock);

    VIR_DEBUG("Step SASL auth %d", virNetServerClientGetFD(client));
    if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
        priv->sasl == NULL) {
3198
        VIR_ERROR(_("client tried invalid SASL start request"));
3199
        goto authfail;
3200 3201
    }

3202
    VIR_DEBUG("Step using SASL Data %d bytes, nil: %d",
3203
              args->data.data_len, args->nil);
3204 3205 3206 3207 3208 3209 3210 3211
    err = virNetSASLSessionServerStep(priv->sasl,
                                      /* NB, distinction of NULL vs "" is *critical* in SASL */
                                      args->nil ? NULL : args->data.data_val,
                                      args->data.data_len,
                                      &serverout,
                                      &serveroutlen);
    if (err != VIR_NET_SASL_COMPLETE &&
        err != VIR_NET_SASL_CONTINUE)
3212
        goto authfail;
3213 3214

    if (serveroutlen > REMOTE_AUTH_SASL_DATA_MAX) {
3215
        VIR_ERROR(_("sasl step reply data too long %d"),
3216
                  (int)serveroutlen);
3217
        goto authfail;
3218 3219 3220 3221
    }

    /* NB, distinction of NULL vs "" is *critical* in SASL */
    if (serverout) {
3222 3223
        if (VIR_ALLOC_N(ret->data.data_val, serveroutlen) < 0)
            goto authfail;
3224 3225 3226 3227 3228 3229 3230
        memcpy(ret->data.data_val, serverout, serveroutlen);
    } else {
        ret->data.data_val = NULL;
    }
    ret->nil = serverout ? 0 : 1;
    ret->data.data_len = serveroutlen;

3231
    VIR_DEBUG("SASL return data %d bytes, nil; %d", ret->data.data_len, ret->nil);
3232
    if (err == VIR_NET_SASL_CONTINUE) {
3233 3234
        ret->complete = 0;
    } else {
3235
        /* Check username whitelist ACL */
3236
        if ((err = remoteSASLFinish(server, client)) < 0) {
3237 3238 3239 3240 3241
            if (err == -2)
                goto authdeny;
            else
                goto authfail;
        }
3242

3243 3244 3245
        ret->complete = 1;
    }

3246
    virMutexUnlock(&priv->lock);
3247
    return 0;
3248

3249
 authfail:
3250 3251 3252
    PROBE(RPC_SERVER_CLIENT_AUTH_FAIL,
          "client=%p auth=%d",
          client, REMOTE_AUTH_SASL);
3253 3254
    goto error;

3255
 authdeny:
3256
    identity = virNetSASLSessionGetIdentity(priv->sasl);
3257 3258 3259
    PROBE(RPC_SERVER_CLIENT_AUTH_DENY,
          "client=%p auth=%d identity=%s",
          client, REMOTE_AUTH_SASL, identity);
3260 3261
    goto error;

3262
 error:
3263
    virObjectUnref(priv->sasl);
3264 3265
    priv->sasl = NULL;
    virResetLastError();
3266 3267
    virReportError(VIR_ERR_AUTH_FAILED, "%s",
                   _("authentication failed"));
3268 3269 3270
    if (rv < 0)
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
3271 3272
    return -1;
}
3273 3274 3275 3276
#else
static int
remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED,
                           virNetServerClientPtr client ATTRIBUTE_UNUSED,
3277
                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
3278 3279 3280 3281
                           virNetMessageErrorPtr rerr,
                           remote_auth_sasl_init_ret *ret ATTRIBUTE_UNUSED)
{
    VIR_WARN("Client tried unsupported SASL auth");
3282 3283
    virReportError(VIR_ERR_AUTH_FAILED, "%s",
                   _("authentication failed"));
3284 3285 3286 3287 3288 3289
    virNetMessageSaveError(rerr);
    return -1;
}
static int
remoteDispatchAuthSaslStart(virNetServerPtr server ATTRIBUTE_UNUSED,
                            virNetServerClientPtr client ATTRIBUTE_UNUSED,
3290
                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
3291 3292 3293 3294 3295
                            virNetMessageErrorPtr rerr,
                            remote_auth_sasl_start_args *args ATTRIBUTE_UNUSED,
                            remote_auth_sasl_start_ret *ret ATTRIBUTE_UNUSED)
{
    VIR_WARN("Client tried unsupported SASL auth");
3296 3297
    virReportError(VIR_ERR_AUTH_FAILED, "%s",
                   _("authentication failed"));
3298 3299 3300 3301 3302 3303
    virNetMessageSaveError(rerr);
    return -1;
}
static int
remoteDispatchAuthSaslStep(virNetServerPtr server ATTRIBUTE_UNUSED,
                           virNetServerClientPtr client ATTRIBUTE_UNUSED,
3304
                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
3305 3306 3307 3308 3309
                           virNetMessageErrorPtr rerr,
                           remote_auth_sasl_step_args *args ATTRIBUTE_UNUSED,
                           remote_auth_sasl_step_ret *ret ATTRIBUTE_UNUSED)
{
    VIR_WARN("Client tried unsupported SASL auth");
3310 3311
    virReportError(VIR_ERR_AUTH_FAILED, "%s",
                   _("authentication failed"));
3312 3313 3314 3315
    virNetMessageSaveError(rerr);
    return -1;
}
#endif
3316 3317 3318



3319
static int
3320
remoteDispatchAuthPolkit(virNetServerPtr server,
3321
                         virNetServerClientPtr client,
3322
                         virNetMessagePtr msg ATTRIBUTE_UNUSED,
3323
                         virNetMessageErrorPtr rerr,
3324
                         remote_auth_polkit_ret *ret)
3325
{
3326
    pid_t callerPid = -1;
3327
    gid_t callerGid = -1;
3328
    uid_t callerUid = -1;
3329
    unsigned long long timestamp;
3330
    const char *action;
3331
    char *ident = NULL;
3332 3333
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3334
    int rv;
3335

3336 3337
    virMutexLock(&priv->lock);
    action = virNetServerClientGetReadonly(client) ?
3338 3339 3340
        "org.libvirt.unix.monitor" :
        "org.libvirt.unix.manage";

3341 3342
    VIR_DEBUG("Start PolicyKit auth %d", virNetServerClientGetFD(client));
    if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_POLKIT) {
3343
        VIR_ERROR(_("client tried invalid PolicyKit init request"));
3344 3345 3346
        goto authfail;
    }

3347
    if (virNetServerClientGetUNIXIdentity(client, &callerUid, &callerGid,
3348
                                          &callerPid, &timestamp) < 0) {
3349 3350 3351
        goto authfail;
    }

3352 3353 3354 3355 3356 3357
    if (timestamp == 0) {
        VIR_WARN("Failing polkit auth due to missing client (pid=%lld) start time",
                 (long long)callerPid);
        goto authfail;
    }

3358 3359
    VIR_INFO("Checking PID %lld running as %d",
             (long long) callerPid, callerUid);
3360

3361 3362 3363 3364 3365 3366 3367
    rv = virPolkitCheckAuth(action,
                            callerPid,
                            timestamp,
                            callerUid,
                            NULL,
                            true);
    if (rv == -1)
3368
        goto authfail;
3369
    else if (rv == -2)
3370
        goto authdeny;
3371

3372 3373 3374
    PROBE(RPC_SERVER_CLIENT_AUTH_ALLOW,
          "client=%p auth=%d identity=%s",
          client, REMOTE_AUTH_POLKIT, ident);
3375 3376
    VIR_INFO("Policy allowed action %s from pid %lld, uid %d",
             action, (long long) callerPid, callerUid);
3377 3378
    ret->complete = 1;

3379
    virNetServerClientSetAuth(client, 0);
3380
    virNetServerTrackCompletedAuth(server);
3381
    virMutexUnlock(&priv->lock);
3382

3383
    return 0;
3384

3385
 error:
3386
    virNetMessageSaveError(rerr);
J
Jim Fehlig 已提交
3387
    virMutexUnlock(&priv->lock);
3388 3389
    return -1;

3390
 authfail:
3391 3392 3393
    PROBE(RPC_SERVER_CLIENT_AUTH_FAIL,
          "client=%p auth=%d",
          client, REMOTE_AUTH_POLKIT);
3394
    goto error;
3395

3396
 authdeny:
3397 3398 3399
    PROBE(RPC_SERVER_CLIENT_AUTH_DENY,
          "client=%p auth=%d identity=%s",
          client, REMOTE_AUTH_POLKIT, ident);
3400
    goto error;
3401 3402
}

3403

3404 3405 3406
/***************************************************************
 *     NODE INFO APIS
 **************************************************************/
3407

3408
static int
3409 3410
remoteDispatchNodeDeviceGetParent(virNetServerPtr server ATTRIBUTE_UNUSED,
                                  virNetServerClientPtr client ATTRIBUTE_UNUSED,
3411
                                  virNetMessagePtr msg ATTRIBUTE_UNUSED,
3412
                                  virNetMessageErrorPtr rerr,
3413 3414
                                  remote_node_device_get_parent_args *args,
                                  remote_node_device_get_parent_ret *ret)
3415
{
3416 3417
    virNodeDevicePtr dev = NULL;
    const char *parent = NULL;
3418
    int rv = -1;
3419 3420
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3421

3422
    if (!priv->conn) {
3423
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
3424
        goto cleanup;
3425 3426
    }

3427
    if (!(dev = virNodeDeviceLookupByName(priv->conn, args->name)))
3428 3429
        goto cleanup;

3430 3431 3432 3433 3434 3435 3436
    parent = virNodeDeviceGetParent(dev);

    if (parent == NULL) {
        ret->parent = NULL;
    } else {
        /* remoteDispatchClientRequest will free this. */
        char **parent_p;
3437
        if (VIR_ALLOC(parent_p) < 0)
3438
            goto cleanup;
3439
        if (VIR_STRDUP(*parent_p, parent) < 0) {
3440 3441 3442 3443 3444 3445
            VIR_FREE(parent_p);
            goto cleanup;
        }
        ret->parent = parent_p;
    }

3446 3447
    rv = 0;

3448
 cleanup:
3449
    if (rv < 0)
3450
        virNetMessageSaveError(rerr);
3451
    virObjectUnref(dev);
3452
    return rv;
3453 3454
}

3455 3456 3457 3458 3459

/***************************
 * Register / deregister events
 ***************************/
static int
3460
remoteDispatchConnectDomainEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
3461
                                         virNetServerClientPtr client,
3462 3463 3464
                                         virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                         virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                         remote_connect_domain_event_register_ret *ret ATTRIBUTE_UNUSED)
O
Osier Yang 已提交
3465
{
3466
    int callbackID;
3467
    int rv = -1;
3468 3469
    daemonClientEventCallbackPtr callback = NULL;
    daemonClientEventCallbackPtr ref;
3470 3471
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
O
Osier Yang 已提交
3472

3473
    if (!priv->conn) {
3474
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
3475
        goto cleanup;
3476 3477
    }

3478 3479
    virMutexLock(&priv->lock);

3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490
    /* If we call register first, we could append a complete callback
     * to our array, but on OOM append failure, we'd have to then hope
     * deregister works to undo our register.  So instead we append an
     * incomplete callback to our array, then register, then fix up
     * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
     * success, we use 'ref' to save a copy of the pointer.  */
    if (VIR_ALLOC(callback) < 0)
        goto cleanup;
    callback->client = client;
    callback->eventID = VIR_DOMAIN_EVENT_ID_LIFECYCLE;
    callback->callbackID = -1;
3491
    callback->legacy = true;
3492 3493 3494 3495
    ref = callback;
    if (VIR_APPEND_ELEMENT(priv->domainEventCallbacks,
                           priv->ndomainEventCallbacks,
                           callback) < 0)
3496
        goto cleanup;
O
Osier Yang 已提交
3497

3498
    if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
3499 3500 3501
                                                       NULL,
                                                       VIR_DOMAIN_EVENT_ID_LIFECYCLE,
                                                       VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
3502 3503 3504 3505 3506
                                                       ref,
                                                       remoteEventCallbackFree)) < 0) {
        VIR_SHRINK_N(priv->domainEventCallbacks,
                     priv->ndomainEventCallbacks, 1);
        callback = ref;
3507
        goto cleanup;
3508
    }
O
Osier Yang 已提交
3509

3510
    ref->callbackID = callbackID;
3511

3512 3513
    rv = 0;

3514
 cleanup:
3515
    VIR_FREE(callback);
3516
    if (rv < 0)
3517 3518
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
3519
    return rv;
O
Osier Yang 已提交
3520 3521
}

3522
static int
3523
remoteDispatchConnectDomainEventDeregister(virNetServerPtr server ATTRIBUTE_UNUSED,
3524
                                           virNetServerClientPtr client,
3525 3526 3527
                                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                           virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                           remote_connect_domain_event_deregister_ret *ret ATTRIBUTE_UNUSED)
3528
{
3529
    int callbackID = -1;
3530
    int rv = -1;
3531
    size_t i;
3532 3533
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3534

3535
    if (!priv->conn) {
3536
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
3537
        goto cleanup;
3538 3539
    }

3540 3541
    virMutexLock(&priv->lock);

3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552
    for (i = 0; i < priv->ndomainEventCallbacks; i++) {
        if (priv->domainEventCallbacks[i]->eventID == VIR_DOMAIN_EVENT_ID_LIFECYCLE) {
            callbackID = priv->domainEventCallbacks[i]->callbackID;
            break;
        }
    }

    if (callbackID < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("domain event %d not registered"),
                       VIR_DOMAIN_EVENT_ID_LIFECYCLE);
3553
        goto cleanup;
3554
    }
3555

3556
    if (virConnectDomainEventDeregisterAny(priv->conn, callbackID) < 0)
3557
        goto cleanup;
3558

3559 3560
    VIR_DELETE_ELEMENT(priv->domainEventCallbacks, i,
                       priv->ndomainEventCallbacks);
3561

3562 3563
    rv = 0;

3564
 cleanup:
3565
    if (rv < 0)
3566 3567
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
3568 3569 3570 3571
    return rv;
}

static void
3572
remoteDispatchObjectEventSend(virNetServerClientPtr client,
3573
                              virNetServerProgramPtr program,
3574 3575 3576 3577
                              int procnr,
                              xdrproc_t proc,
                              void *data)
{
3578
    virNetMessagePtr msg;
3579

3580
    if (!(msg = virNetMessageNew(false)))
3581
        goto cleanup;
3582

3583 3584 3585 3586 3587 3588
    msg->header.prog = virNetServerProgramGetID(program);
    msg->header.vers = virNetServerProgramGetVersion(program);
    msg->header.proc = procnr;
    msg->header.type = VIR_NET_MESSAGE;
    msg->header.serial = 1;
    msg->header.status = VIR_NET_OK;
3589

3590
    if (virNetMessageEncodeHeader(msg) < 0)
3591 3592
        goto cleanup;

3593 3594
    if (virNetMessageEncodePayload(msg, proc, data) < 0)
        goto cleanup;
3595

3596 3597
    VIR_DEBUG("Queue event %d %zu", procnr, msg->bufferLength);
    virNetServerClientSendMessage(client, msg);
3598

3599
    xdr_free(proc, data);
3600 3601
    return;

3602
 cleanup:
3603
    virNetMessageFree(msg);
3604
    xdr_free(proc, data);
3605 3606
}

3607
static int
3608 3609
remoteDispatchSecretGetValue(virNetServerPtr server ATTRIBUTE_UNUSED,
                             virNetServerClientPtr client ATTRIBUTE_UNUSED,
3610
                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
3611
                             virNetMessageErrorPtr rerr,
3612 3613
                             remote_secret_get_value_args *args,
                             remote_secret_get_value_ret *ret)
3614
{
3615 3616 3617
    virSecretPtr secret = NULL;
    size_t value_size;
    unsigned char *value;
3618
    int rv = -1;
3619 3620
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3621

3622
    if (!priv->conn) {
3623
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
3624
        goto cleanup;
3625 3626
    }

3627
    if (!(secret = get_nonnull_secret(priv->conn, args->secret)))
3628
        goto cleanup;
3629

3630
    if (!(value = virSecretGetValue(secret, &value_size, args->flags)))
3631
        goto cleanup;
3632

3633 3634 3635
    ret->value.value_len = value_size;
    ret->value.value_val = (char *)value;

3636 3637
    rv = 0;

3638
 cleanup:
3639
    if (rv < 0)
3640
        virNetMessageSaveError(rerr);
3641
    virObjectUnref(secret);
3642
    return rv;
3643 3644
}

3645
static int
3646 3647
remoteDispatchDomainGetState(virNetServerPtr server ATTRIBUTE_UNUSED,
                             virNetServerClientPtr client ATTRIBUTE_UNUSED,
3648
                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
3649
                             virNetMessageErrorPtr rerr,
3650 3651 3652 3653 3654
                             remote_domain_get_state_args *args,
                             remote_domain_get_state_ret *ret)
{
    virDomainPtr dom = NULL;
    int rv = -1;
3655 3656
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3657

3658
    if (!priv->conn) {
3659
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
3660 3661 3662
        goto cleanup;
    }

3663
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
3664 3665 3666 3667 3668 3669 3670
        goto cleanup;

    if (virDomainGetState(dom, &ret->state, &ret->reason, args->flags) < 0)
        goto cleanup;

    rv = 0;

3671
 cleanup:
3672
    if (rv < 0)
3673
        virNetMessageSaveError(rerr);
3674
    virObjectUnref(dom);
3675 3676 3677
    return rv;
}

3678 3679 3680 3681 3682 3683

/* Due to back-compat reasons, two RPC calls map to the same libvirt
 * API of virConnectDomainEventRegisterAny.  A client should only use
 * the new call if they have probed
 * VIR_DRV_SUPPORTS_FEATURE(VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK),
 * and must not mix the two styles.  */
3684
static int
3685
remoteDispatchConnectDomainEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
3686
                                            virNetServerClientPtr client,
3687 3688 3689
                                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                            virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                            remote_connect_domain_event_register_any_args *args)
3690 3691
{
    int callbackID;
3692
    int rv = -1;
3693 3694
    daemonClientEventCallbackPtr callback = NULL;
    daemonClientEventCallbackPtr ref;
3695 3696
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3697

3698
    if (!priv->conn) {
3699
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
3700
        goto cleanup;
3701 3702
    }

3703 3704
    virMutexLock(&priv->lock);

3705 3706 3707 3708
    /* We intentionally do not use VIR_DOMAIN_EVENT_ID_LAST here; any
     * new domain events added after this point should only use the
     * modern callback style of RPC.  */
    if (args->eventID > VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED ||
3709
        args->eventID < 0) {
3710 3711
        virReportError(VIR_ERR_INTERNAL_ERROR, _("unsupported event ID %d"),
                       args->eventID);
3712
        goto cleanup;
3713 3714
    }

3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725
    /* If we call register first, we could append a complete callback
     * to our array, but on OOM append failure, we'd have to then hope
     * deregister works to undo our register.  So instead we append an
     * incomplete callback to our array, then register, then fix up
     * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
     * success, we use 'ref' to save a copy of the pointer.  */
    if (VIR_ALLOC(callback) < 0)
        goto cleanup;
    callback->client = client;
    callback->eventID = args->eventID;
    callback->callbackID = -1;
3726
    callback->legacy = true;
3727 3728 3729 3730
    ref = callback;
    if (VIR_APPEND_ELEMENT(priv->domainEventCallbacks,
                           priv->ndomainEventCallbacks,
                           callback) < 0)
3731
        goto cleanup;
3732

3733
    if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
3734 3735 3736
                                                       NULL,
                                                       args->eventID,
                                                       domainEventCallbacks[args->eventID],
3737 3738 3739 3740 3741
                                                       ref,
                                                       remoteEventCallbackFree)) < 0) {
        VIR_SHRINK_N(priv->domainEventCallbacks,
                     priv->ndomainEventCallbacks, 1);
        callback = ref;
3742
        goto cleanup;
3743
    }
3744

3745
    ref->callbackID = callbackID;
3746

3747 3748
    rv = 0;

3749
 cleanup:
3750
    VIR_FREE(callback);
3751
    if (rv < 0)
3752 3753
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
3754
    return rv;
3755 3756 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
static int
remoteDispatchConnectDomainEventCallbackRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
                                                    virNetServerClientPtr client,
                                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                                    virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                                    remote_connect_domain_event_callback_register_any_args *args,
                                                    remote_connect_domain_event_callback_register_any_ret *ret)
{
    int callbackID;
    int rv = -1;
    daemonClientEventCallbackPtr callback = NULL;
    daemonClientEventCallbackPtr ref;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
    virDomainPtr dom = NULL;

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    virMutexLock(&priv->lock);

    if (args->dom &&
        !(dom = get_nonnull_domain(priv->conn, *args->dom)))
        goto cleanup;

3785
    if (args->eventID >= VIR_DOMAIN_EVENT_ID_LAST || args->eventID < 0) {
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
        virReportError(VIR_ERR_INTERNAL_ERROR, _("unsupported event ID %d"),
                       args->eventID);
        goto cleanup;
    }

    /* If we call register first, we could append a complete callback
     * to our array, but on OOM append failure, we'd have to then hope
     * deregister works to undo our register.  So instead we append an
     * incomplete callback to our array, then register, then fix up
     * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
     * success, we use 'ref' to save a copy of the pointer.  */
    if (VIR_ALLOC(callback) < 0)
        goto cleanup;
    callback->client = client;
    callback->eventID = args->eventID;
    callback->callbackID = -1;
    ref = callback;
    if (VIR_APPEND_ELEMENT(priv->domainEventCallbacks,
                           priv->ndomainEventCallbacks,
                           callback) < 0)
        goto cleanup;

    if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
                                                       dom,
                                                       args->eventID,
                                                       domainEventCallbacks[args->eventID],
                                                       ref,
                                                       remoteEventCallbackFree)) < 0) {
        VIR_SHRINK_N(priv->domainEventCallbacks,
                     priv->ndomainEventCallbacks, 1);
        callback = ref;
        goto cleanup;
    }

    ref->callbackID = callbackID;
    ret->callbackID = callbackID;

    rv = 0;

3825
 cleanup:
3826 3827 3828
    VIR_FREE(callback);
    if (rv < 0)
        virNetMessageSaveError(rerr);
3829
    virObjectUnref(dom);
3830 3831 3832 3833 3834
    virMutexUnlock(&priv->lock);
    return rv;
}


3835
static int
3836
remoteDispatchConnectDomainEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
3837
                                              virNetServerClientPtr client,
3838 3839 3840
                                              virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                              virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                              remote_connect_domain_event_deregister_any_args *args)
3841 3842
{
    int callbackID = -1;
3843
    int rv = -1;
3844
    size_t i;
3845 3846
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3847

3848
    if (!priv->conn) {
3849
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
3850
        goto cleanup;
3851 3852
    }

3853 3854
    virMutexLock(&priv->lock);

3855 3856 3857 3858
    /* We intentionally do not use VIR_DOMAIN_EVENT_ID_LAST here; any
     * new domain events added after this point should only use the
     * modern callback style of RPC.  */
    if (args->eventID > VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED ||
3859
        args->eventID < 0) {
3860 3861
        virReportError(VIR_ERR_INTERNAL_ERROR, _("unsupported event ID %d"),
                       args->eventID);
3862
        goto cleanup;
3863 3864
    }

3865 3866 3867 3868 3869 3870
    for (i = 0; i < priv->ndomainEventCallbacks; i++) {
        if (priv->domainEventCallbacks[i]->eventID == args->eventID) {
            callbackID = priv->domainEventCallbacks[i]->callbackID;
            break;
        }
    }
3871
    if (callbackID < 0) {
3872 3873
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("domain event %d not registered"), args->eventID);
3874
        goto cleanup;
3875 3876
    }

3877
    if (virConnectDomainEventDeregisterAny(priv->conn, callbackID) < 0)
3878
        goto cleanup;
3879

3880 3881
    VIR_DELETE_ELEMENT(priv->domainEventCallbacks, i,
                       priv->ndomainEventCallbacks);
3882

3883 3884
    rv = 0;

3885
 cleanup:
3886
    if (rv < 0)
3887 3888
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
3889
    return rv;
3890 3891
}

3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930

static int
remoteDispatchConnectDomainEventCallbackDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
                                                      virNetServerClientPtr client,
                                                      virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                                      virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                                      remote_connect_domain_event_callback_deregister_any_args *args)
{
    int rv = -1;
    size_t i;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    virMutexLock(&priv->lock);

    for (i = 0; i < priv->ndomainEventCallbacks; i++) {
        if (priv->domainEventCallbacks[i]->callbackID == args->callbackID)
            break;
    }
    if (i == priv->ndomainEventCallbacks) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("domain event callback %d not registered"),
                       args->callbackID);
        goto cleanup;
    }

    if (virConnectDomainEventDeregisterAny(priv->conn, args->callbackID) < 0)
        goto cleanup;

    VIR_DELETE_ELEMENT(priv->domainEventCallbacks, i,
                       priv->ndomainEventCallbacks);

    rv = 0;

3931
 cleanup:
3932 3933 3934 3935 3936 3937 3938
    if (rv < 0)
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
    return rv;
}


C
Chris Lalancette 已提交
3939
static int
3940 3941 3942 3943 3944 3945
qemuDispatchDomainMonitorCommand(virNetServerPtr server ATTRIBUTE_UNUSED,
                                 virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                 virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                 virNetMessageErrorPtr rerr,
                                 qemu_domain_monitor_command_args *args,
                                 qemu_domain_monitor_command_ret *ret)
C
Chris Lalancette 已提交
3946
{
3947
    virDomainPtr dom = NULL;
3948
    int rv = -1;
3949 3950
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
C
Chris Lalancette 已提交
3951

3952
    if (!priv->conn) {
3953
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
3954
        goto cleanup;
3955 3956
    }

3957
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
3958
        goto cleanup;
C
Chris Lalancette 已提交
3959

3960
    if (virDomainQemuMonitorCommand(dom, args->cmd, &ret->result,
3961
                                    args->flags) < 0)
3962
        goto cleanup;
C
Chris Lalancette 已提交
3963

3964
    rv = 0;
C
Chris Lalancette 已提交
3965

3966
 cleanup:
3967
    if (rv < 0)
3968
        virNetMessageSaveError(rerr);
3969
    virObjectUnref(dom);
3970
    return rv;
C
Chris Lalancette 已提交
3971 3972
}

3973

3974
static int
3975 3976
remoteDispatchDomainMigrateBegin3(virNetServerPtr server ATTRIBUTE_UNUSED,
                                  virNetServerClientPtr client ATTRIBUTE_UNUSED,
3977
                                  virNetMessagePtr msg ATTRIBUTE_UNUSED,
3978
                                  virNetMessageErrorPtr rerr,
3979 3980 3981 3982 3983 3984
                                  remote_domain_migrate_begin3_args *args,
                                  remote_domain_migrate_begin3_ret *ret)
{
    char *xml = NULL;
    virDomainPtr dom = NULL;
    char *dname;
3985
    char *xmlin;
3986 3987 3988
    char *cookieout = NULL;
    int cookieoutlen = 0;
    int rv = -1;
3989 3990
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3991

3992
    if (!priv->conn) {
3993
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
3994 3995 3996
        goto cleanup;
    }

3997
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
3998 3999
        goto cleanup;

4000
    xmlin = args->xmlin == NULL ? NULL : *args->xmlin;
4001 4002
    dname = args->dname == NULL ? NULL : *args->dname;

4003
    if (!(xml = virDomainMigrateBegin3(dom, xmlin,
4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016
                                       &cookieout, &cookieoutlen,
                                       args->flags, dname, args->resource)))
        goto cleanup;

    /* remoteDispatchClientRequest will free cookie and
     * the xml string if there is one.
     */
    ret->cookie_out.cookie_out_len = cookieoutlen;
    ret->cookie_out.cookie_out_val = cookieout;
    ret->xml = xml;

    rv = 0;

4017
 cleanup:
4018
    if (rv < 0)
4019
        virNetMessageSaveError(rerr);
4020
    virObjectUnref(dom);
4021 4022 4023 4024 4025
    return rv;
}


static int
4026 4027
remoteDispatchDomainMigratePrepare3(virNetServerPtr server ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
4028
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
4029
                                    virNetMessageErrorPtr rerr,
4030 4031 4032 4033 4034 4035 4036 4037 4038
                                    remote_domain_migrate_prepare3_args *args,
                                    remote_domain_migrate_prepare3_ret *ret)
{
    char *cookieout = NULL;
    int cookieoutlen = 0;
    char *uri_in;
    char **uri_out;
    char *dname;
    int rv = -1;
4039 4040
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
4041

4042
    if (!priv->conn) {
4043
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4044 4045 4046 4047 4048 4049 4050
        goto cleanup;
    }

    uri_in = args->uri_in == NULL ? NULL : *args->uri_in;
    dname = args->dname == NULL ? NULL : *args->dname;

    /* Wacky world of XDR ... */
4051
    if (VIR_ALLOC(uri_out) < 0)
4052 4053
        goto cleanup;

4054
    if (virDomainMigratePrepare3(priv->conn,
4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071
                                 args->cookie_in.cookie_in_val,
                                 args->cookie_in.cookie_in_len,
                                 &cookieout, &cookieoutlen,
                                 uri_in, uri_out,
                                 args->flags, dname, args->resource,
                                 args->dom_xml) < 0)
        goto cleanup;

    /* remoteDispatchClientRequest will free cookie, uri_out and
     * the string if there is one.
     */
    ret->cookie_out.cookie_out_len = cookieoutlen;
    ret->cookie_out.cookie_out_val = cookieout;
    ret->uri_out = *uri_out == NULL ? NULL : uri_out;

    rv = 0;

4072
 cleanup:
4073
    if (rv < 0) {
4074
        virNetMessageSaveError(rerr);
4075 4076 4077 4078 4079
        VIR_FREE(uri_out);
    }
    return rv;
}

4080

4081
static int
4082 4083
remoteDispatchDomainMigratePerform3(virNetServerPtr server ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
4084
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
4085
                                    virNetMessageErrorPtr rerr,
4086 4087 4088 4089
                                    remote_domain_migrate_perform3_args *args,
                                    remote_domain_migrate_perform3_ret *ret)
{
    virDomainPtr dom = NULL;
4090
    char *xmlin;
4091
    char *dname;
4092 4093
    char *uri;
    char *dconnuri;
4094 4095 4096
    char *cookieout = NULL;
    int cookieoutlen = 0;
    int rv = -1;
4097 4098
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
4099

4100
    if (!priv->conn) {
4101
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4102 4103 4104
        goto cleanup;
    }

4105
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
4106 4107
        goto cleanup;

4108
    xmlin = args->xmlin == NULL ? NULL : *args->xmlin;
4109
    dname = args->dname == NULL ? NULL : *args->dname;
4110 4111
    uri = args->uri == NULL ? NULL : *args->uri;
    dconnuri = args->dconnuri == NULL ? NULL : *args->dconnuri;
4112

4113
    if (virDomainMigratePerform3(dom, xmlin,
4114 4115 4116
                                 args->cookie_in.cookie_in_val,
                                 args->cookie_in.cookie_in_len,
                                 &cookieout, &cookieoutlen,
4117
                                 dconnuri, uri,
4118 4119 4120 4121 4122 4123 4124 4125 4126 4127
                                 args->flags, dname, args->resource) < 0)
        goto cleanup;

    /* remoteDispatchClientRequest will free cookie
     */
    ret->cookie_out.cookie_out_len = cookieoutlen;
    ret->cookie_out.cookie_out_val = cookieout;

    rv = 0;

4128
 cleanup:
4129
    if (rv < 0)
4130
        virNetMessageSaveError(rerr);
4131
    virObjectUnref(dom);
4132 4133 4134 4135 4136
    return rv;
}


static int
4137 4138
remoteDispatchDomainMigrateFinish3(virNetServerPtr server ATTRIBUTE_UNUSED,
                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
4139
                                   virNetMessagePtr msg ATTRIBUTE_UNUSED,
4140
                                   virNetMessageErrorPtr rerr,
4141 4142 4143 4144 4145 4146
                                   remote_domain_migrate_finish3_args *args,
                                   remote_domain_migrate_finish3_ret *ret)
{
    virDomainPtr dom = NULL;
    char *cookieout = NULL;
    int cookieoutlen = 0;
4147 4148
    char *uri;
    char *dconnuri;
4149
    int rv = -1;
4150 4151
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
4152

4153
    if (!priv->conn) {
4154
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4155 4156 4157
        goto cleanup;
    }

4158 4159 4160
    uri = args->uri == NULL ? NULL : *args->uri;
    dconnuri = args->dconnuri == NULL ? NULL : *args->dconnuri;

4161
    if (!(dom = virDomainMigrateFinish3(priv->conn, args->dname,
4162 4163 4164 4165 4166 4167
                                        args->cookie_in.cookie_in_val,
                                        args->cookie_in.cookie_in_len,
                                        &cookieout, &cookieoutlen,
                                        dconnuri, uri,
                                        args->flags,
                                        args->cancelled)))
4168 4169
        goto cleanup;

4170
    make_nonnull_domain(&ret->dom, dom);
4171 4172 4173 4174 4175 4176 4177 4178

    /* remoteDispatchClientRequest will free cookie
     */
    ret->cookie_out.cookie_out_len = cookieoutlen;
    ret->cookie_out.cookie_out_val = cookieout;

    rv = 0;

4179
 cleanup:
4180
    if (rv < 0) {
4181
        virNetMessageSaveError(rerr);
4182 4183
        VIR_FREE(cookieout);
    }
4184
    virObjectUnref(dom);
4185 4186 4187 4188 4189
    return rv;
}


static int
4190 4191
remoteDispatchDomainMigrateConfirm3(virNetServerPtr server ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
4192
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
4193 4194
                                    virNetMessageErrorPtr rerr,
                                    remote_domain_migrate_confirm3_args *args)
4195 4196 4197
{
    virDomainPtr dom = NULL;
    int rv = -1;
4198 4199
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
4200

4201
    if (!priv->conn) {
4202
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4203 4204 4205
        goto cleanup;
    }

4206
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
4207 4208 4209 4210 4211 4212 4213 4214 4215 4216
        goto cleanup;

    if (virDomainMigrateConfirm3(dom,
                                 args->cookie_in.cookie_in_val,
                                 args->cookie_in.cookie_in_len,
                                 args->flags, args->cancelled) < 0)
        goto cleanup;

    rv = 0;

4217
 cleanup:
4218
    if (rv < 0)
4219
        virNetMessageSaveError(rerr);
4220
    virObjectUnref(dom);
4221 4222 4223 4224
    return rv;
}


4225 4226 4227 4228 4229 4230
static int remoteDispatchConnectSupportsFeature(virNetServerPtr server ATTRIBUTE_UNUSED,
                                                virNetServerClientPtr client,
                                                virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                                virNetMessageErrorPtr rerr,
                                                remote_connect_supports_feature_args *args,
                                                remote_connect_supports_feature_ret *ret)
4231 4232 4233 4234 4235 4236
{
    int rv = -1;
    int supported;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

4237 4238 4239 4240 4241 4242 4243 4244 4245 4246
    /* This feature is checked before opening the connection, thus we must
     * check it first.
     */
    if (args->feature == VIR_DRV_FEATURE_PROGRAM_KEEPALIVE) {
        if (virNetServerClientStartKeepAlive(client) < 0)
            goto cleanup;
        supported = 1;
        goto done;
    }

4247
    if (!priv->conn) {
4248
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4249 4250 4251 4252 4253
        goto cleanup;
    }

    switch (args->feature) {
    case VIR_DRV_FEATURE_FD_PASSING:
4254
    case VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK:
4255 4256 4257 4258
        supported = 1;
        break;

    default:
4259
        if ((supported = virConnectSupportsFeature(priv->conn, args->feature)) < 0)
4260 4261 4262 4263
            goto cleanup;
        break;
    }

4264
 done:
4265 4266 4267
    ret->supported = supported;
    rv = 0;

4268
 cleanup:
4269 4270 4271 4272 4273 4274
    if (rv < 0)
        virNetMessageSaveError(rerr);
    return rv;
}


4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288
static int
remoteDispatchDomainOpenGraphics(virNetServerPtr server ATTRIBUTE_UNUSED,
                                 virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                 virNetMessagePtr msg,
                                 virNetMessageErrorPtr rerr,
                                 remote_domain_open_graphics_args *args)
{
    virDomainPtr dom = NULL;
    int rv = -1;
    int fd = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
4289
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306
        goto cleanup;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if ((fd = virNetMessageDupFD(msg, 0)) < 0)
        goto cleanup;

    if (virDomainOpenGraphics(dom,
                              args->idx,
                              fd,
                              args->flags) < 0)
        goto cleanup;

    rv = 0;

4307
 cleanup:
4308 4309 4310
    VIR_FORCE_CLOSE(fd);
    if (rv < 0)
        virNetMessageSaveError(rerr);
4311
    virObjectUnref(dom);
4312 4313 4314
    return rv;
}

4315

4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336
static int
remoteDispatchDomainOpenGraphicsFd(virNetServerPtr server ATTRIBUTE_UNUSED,
                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                   virNetMessagePtr msg,
                                   virNetMessageErrorPtr rerr,
                                   remote_domain_open_graphics_fd_args *args)
{
    virDomainPtr dom = NULL;
    int rv = -1;
    int fd = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

4337 4338 4339
    if ((fd = virDomainOpenGraphicsFD(dom,
                                      args->idx,
                                      args->flags)) < 0)
4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350
        goto cleanup;

    if (virNetMessageAddFD(msg, fd) < 0)
        goto cleanup;

    /* return 1 here to let virNetServerProgramDispatchCall know
     * we are passing a FD */
    rv = 1;

 cleanup:
    VIR_FORCE_CLOSE(fd);
4351
    if (rv < 0)
4352 4353
        virNetMessageSaveError(rerr);

4354
    virObjectUnref(dom);
4355 4356
    return rv;
}
4357 4358


4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369
static int
remoteDispatchDomainGetInterfaceParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
                                           virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                           virNetMessageErrorPtr rerr,
                                           remote_domain_get_interface_parameters_args *args,
                                           remote_domain_get_interface_parameters_ret *ret)
{
    virDomainPtr dom = NULL;
    virTypedParameterPtr params = NULL;
    const char *device = args->device;
4370
    int nparams = 0;
4371 4372 4373 4374 4375 4376
    unsigned int flags;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
4377
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4378 4379 4380 4381 4382
        goto cleanup;
    }

    flags = args->flags;

4383
    if (args->nparams > REMOTE_DOMAIN_INTERFACE_PARAMETERS_MAX) {
4384
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
4385 4386
        goto cleanup;
    }
4387
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
4388
        goto cleanup;
4389
    nparams = args->nparams;
4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if (virDomainGetInterfaceParameters(dom, device, params, &nparams, flags) < 0)
        goto cleanup;

    /* In this case, we need to send back the number of parameters
     * supported
     */
    if (args->nparams == 0) {
        ret->nparams = nparams;
        goto success;
    }

    if (remoteSerializeTypedParameters(params, nparams,
                                       &ret->params.params_val,
                                       &ret->params.params_len,
                                       flags) < 0)
        goto cleanup;

4411
 success:
4412 4413
    rv = 0;

4414
 cleanup:
4415 4416
    if (rv < 0)
        virNetMessageSaveError(rerr);
4417
    virTypedParamsFree(params, nparams);
4418
    virObjectUnref(dom);
4419 4420
    return rv;
}
4421

4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437
static int
remoteDispatchDomainGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED,
                                virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                virNetMessagePtr hdr ATTRIBUTE_UNUSED,
                                virNetMessageErrorPtr rerr,
                                remote_domain_get_cpu_stats_args *args,
                                remote_domain_get_cpu_stats_ret *ret)
{
    virDomainPtr dom = NULL;
    struct daemonClientPrivate *priv;
    virTypedParameterPtr params = NULL;
    int rv = -1;
    int percpu_len = 0;

    priv = virNetServerClientGetPrivateData(client);
    if (!priv->conn) {
4438
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4439 4440 4441 4442
        goto cleanup;
    }

    if (args->nparams > REMOTE_NODE_CPU_STATS_MAX) {
4443
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
4444 4445 4446
        goto cleanup;
    }
    if (args->ncpus > REMOTE_DOMAIN_GET_CPU_STATS_NCPUS_MAX) {
4447
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("ncpus too large"));
4448 4449 4450 4451
        goto cleanup;
    }

    if (args->nparams > 0 &&
4452
        VIR_ALLOC_N(params, args->ncpus * args->nparams) < 0)
4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472
        goto cleanup;

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    percpu_len = virDomainGetCPUStats(dom, params, args->nparams,
                                      args->start_cpu, args->ncpus,
                                      args->flags);
    if (percpu_len < 0)
        goto cleanup;
    /* If nparams == 0, the function returns a single value */
    if (args->nparams == 0)
        goto success;

    if (remoteSerializeTypedParameters(params, args->nparams * args->ncpus,
                                       &ret->params.params_val,
                                       &ret->params.params_len,
                                       args->flags) < 0)
        goto cleanup;

4473
 success:
4474 4475
    rv = 0;
    ret->nparams = percpu_len;
4476
    if (args->nparams && !(args->flags & VIR_TYPED_PARAM_STRING_OKAY)) {
4477
        size_t i;
4478 4479 4480 4481 4482 4483

        for (i = 0; i < percpu_len; i++) {
            if (params[i].type == VIR_TYPED_PARAM_STRING)
                ret->nparams--;
        }
    }
4484

4485
 cleanup:
4486 4487
    if (rv < 0)
         virNetMessageSaveError(rerr);
4488
    virTypedParamsFree(params, args->ncpus * args->nparams);
4489
    virObjectUnref(dom);
4490 4491 4492
    return rv;
}

4493 4494 4495 4496 4497 4498 4499
static int
remoteDispatchDomainGetDiskErrors(virNetServerPtr server ATTRIBUTE_UNUSED,
                                  virNetServerClientPtr client,
                                  virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                  virNetMessageErrorPtr rerr,
                                  remote_domain_get_disk_errors_args *args,
                                  remote_domain_get_disk_errors_ret *ret)
4500 4501 4502 4503
{
    int rv = -1;
    virDomainPtr dom = NULL;
    virDomainDiskErrorPtr errors = NULL;
4504
    int len = 0;
4505 4506 4507 4508
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
4509
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4510 4511 4512 4513 4514 4515 4516
        goto cleanup;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if (args->maxerrors > REMOTE_DOMAIN_DISK_ERRORS_MAX) {
4517 4518
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("maxerrors too large"));
4519 4520 4521 4522
        goto cleanup;
    }

    if (args->maxerrors &&
4523
        VIR_ALLOC_N(errors, args->maxerrors) < 0)
4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539
        goto cleanup;

    if ((len = virDomainGetDiskErrors(dom, errors,
                                      args->maxerrors,
                                      args->flags)) < 0)
        goto cleanup;

    ret->nerrors = len;
    if (errors &&
        remoteSerializeDomainDiskErrors(errors, len,
                                        &ret->errors.errors_val,
                                        &ret->errors.errors_len) < 0)
        goto cleanup;

    rv = 0;

4540
 cleanup:
4541 4542
    if (rv < 0)
        virNetMessageSaveError(rerr);
4543
    virObjectUnref(dom);
4544
    if (errors && len > 0) {
4545
        size_t i;
4546 4547 4548 4549 4550 4551 4552
        for (i = 0; i < len; i++)
            VIR_FREE(errors[i].disk);
    }
    VIR_FREE(errors);
    return rv;
}

4553 4554 4555 4556 4557 4558 4559 4560 4561 4562
static int
remoteDispatchDomainListAllSnapshots(virNetServerPtr server ATTRIBUTE_UNUSED,
                                     virNetServerClientPtr client,
                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                     virNetMessageErrorPtr rerr,
                                     remote_domain_list_all_snapshots_args *args,
                                     remote_domain_list_all_snapshots_ret *ret)
{
    virDomainSnapshotPtr *snaps = NULL;
    int nsnaps = 0;
4563
    size_t i;
4564 4565 4566 4567 4568
    int rv = -1;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
    virDomainPtr dom = NULL;

    if (!priv->conn) {
4569
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580
        goto cleanup;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if ((nsnaps = virDomainListAllSnapshots(dom,
                                            args->need_results ? &snaps : NULL,
                                            args->flags)) < 0)
        goto cleanup;

4581 4582 4583 4584 4585 4586 4587
    if (nsnaps > REMOTE_DOMAIN_SNAPSHOT_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many domain snapshots '%d' for limit '%d'"),
                       nsnaps, REMOTE_DOMAIN_SNAPSHOT_LIST_MAX);
        goto cleanup;
    }

4588
    if (snaps && nsnaps) {
4589
        if (VIR_ALLOC_N(ret->snapshots.snapshots_val, nsnaps) < 0)
4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604
            goto cleanup;

        ret->snapshots.snapshots_len = nsnaps;

        for (i = 0; i < nsnaps; i++)
            make_nonnull_domain_snapshot(ret->snapshots.snapshots_val + i,
                                         snaps[i]);
    } else {
        ret->snapshots.snapshots_len = 0;
        ret->snapshots.snapshots_val = NULL;
    }

    ret->ret = nsnaps;
    rv = 0;

4605
 cleanup:
4606 4607
    if (rv < 0)
        virNetMessageSaveError(rerr);
4608
    virObjectUnref(dom);
4609
    if (snaps && nsnaps > 0)
4610
        for (i = 0; i < nsnaps; i++)
4611
            virObjectUnref(snaps[i]);
4612
    VIR_FREE(snaps);
4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625
    return rv;
}

static int
remoteDispatchDomainSnapshotListAllChildren(virNetServerPtr server ATTRIBUTE_UNUSED,
                                            virNetServerClientPtr client,
                                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                            virNetMessageErrorPtr rerr,
                                            remote_domain_snapshot_list_all_children_args *args,
                                            remote_domain_snapshot_list_all_children_ret *ret)
{
    virDomainSnapshotPtr *snaps = NULL;
    int nsnaps = 0;
4626
    size_t i;
4627 4628 4629 4630 4631 4632
    int rv = -1;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
    virDomainPtr dom = NULL;
    virDomainSnapshotPtr snapshot = NULL;

    if (!priv->conn) {
4633
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647
        goto cleanup;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->snapshot.dom)))
        goto cleanup;

    if (!(snapshot = get_nonnull_domain_snapshot(dom, args->snapshot)))
        goto cleanup;

    if ((nsnaps = virDomainSnapshotListAllChildren(snapshot,
                                                   args->need_results ? &snaps : NULL,
                                                   args->flags)) < 0)
        goto cleanup;

4648 4649 4650 4651 4652 4653 4654
    if (nsnaps > REMOTE_DOMAIN_SNAPSHOT_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many domain snapshots '%d' for limit '%d'"),
                       nsnaps, REMOTE_DOMAIN_SNAPSHOT_LIST_MAX);
        goto cleanup;
    }

4655
    if (snaps && nsnaps) {
4656
        if (VIR_ALLOC_N(ret->snapshots.snapshots_val, nsnaps) < 0)
4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671
            goto cleanup;

        ret->snapshots.snapshots_len = nsnaps;

        for (i = 0; i < nsnaps; i++)
            make_nonnull_domain_snapshot(ret->snapshots.snapshots_val + i,
                                         snaps[i]);
    } else {
        ret->snapshots.snapshots_len = 0;
        ret->snapshots.snapshots_val = NULL;
    }

    ret->ret = nsnaps;
    rv = 0;

4672
 cleanup:
4673 4674
    if (rv < 0)
        virNetMessageSaveError(rerr);
4675
    virObjectUnref(snapshot);
4676
    virObjectUnref(dom);
4677
    if (snaps && nsnaps > 0)
4678
        for (i = 0; i < nsnaps; i++)
4679
            virObjectUnref(snaps[i]);
4680
    VIR_FREE(snaps);
4681 4682 4683
    return rv;
}

4684 4685 4686 4687 4688 4689 4690 4691 4692 4693
static int
remoteDispatchConnectListAllStoragePools(virNetServerPtr server ATTRIBUTE_UNUSED,
                                         virNetServerClientPtr client,
                                         virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                         virNetMessageErrorPtr rerr,
                                         remote_connect_list_all_storage_pools_args *args,
                                         remote_connect_list_all_storage_pools_ret *ret)
{
    virStoragePoolPtr *pools = NULL;
    int npools = 0;
4694
    size_t i;
4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707
    int rv = -1;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if ((npools = virConnectListAllStoragePools(priv->conn,
                                                args->need_results ? &pools : NULL,
                                                args->flags)) < 0)
        goto cleanup;

4708 4709 4710 4711 4712 4713 4714
    if (npools > REMOTE_STORAGE_POOL_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many storage pools '%d' for limit '%d'"),
                       npools, REMOTE_STORAGE_POOL_LIST_MAX);
        goto cleanup;
    }

4715
    if (pools && npools) {
4716
        if (VIR_ALLOC_N(ret->pools.pools_val, npools) < 0)
4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731
            goto cleanup;

        ret->pools.pools_len = npools;

        for (i = 0; i < npools; i++)
            make_nonnull_storage_pool(ret->pools.pools_val + i, pools[i]);
    } else {
        ret->pools.pools_len = 0;
        ret->pools.pools_val = NULL;
    }

    ret->ret = npools;

    rv = 0;

4732
 cleanup:
4733 4734
    if (rv < 0)
        virNetMessageSaveError(rerr);
4735
    if (pools && npools > 0)
4736
        for (i = 0; i < npools; i++)
4737
            virObjectUnref(pools[i]);
4738
    VIR_FREE(pools);
4739 4740 4741
    return rv;
}

4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752
static int
remoteDispatchStoragePoolListAllVolumes(virNetServerPtr server ATTRIBUTE_UNUSED,
                                        virNetServerClientPtr client,
                                        virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                        virNetMessageErrorPtr rerr,
                                        remote_storage_pool_list_all_volumes_args *args,
                                        remote_storage_pool_list_all_volumes_ret *ret)
{
    virStorageVolPtr *vols = NULL;
    virStoragePoolPtr pool = NULL;
    int nvols = 0;
4753
    size_t i;
4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769
    int rv = -1;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if (!(pool = get_nonnull_storage_pool(priv->conn, args->pool)))
        goto cleanup;

    if ((nvols = virStoragePoolListAllVolumes(pool,
                                              args->need_results ? &vols : NULL,
                                              args->flags)) < 0)
        goto cleanup;

4770 4771 4772 4773 4774 4775 4776
    if (nvols > REMOTE_STORAGE_VOL_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many storage volumes '%d' for limit '%d'"),
                       nvols, REMOTE_STORAGE_VOL_LIST_MAX);
        goto cleanup;
    }

4777
    if (vols && nvols) {
4778
        if (VIR_ALLOC_N(ret->vols.vols_val, nvols) < 0)
4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793
            goto cleanup;

        ret->vols.vols_len = nvols;

        for (i = 0; i < nvols; i++)
            make_nonnull_storage_vol(ret->vols.vols_val + i, vols[i]);
    } else {
        ret->vols.vols_len = 0;
        ret->vols.vols_val = NULL;
    }

    ret->ret = nvols;

    rv = 0;

4794
 cleanup:
4795 4796
    if (rv < 0)
        virNetMessageSaveError(rerr);
4797
    if (vols && nvols > 0)
4798
        for (i = 0; i < nvols; i++)
4799
            virObjectUnref(vols[i]);
4800
    VIR_FREE(vols);
4801
    virObjectUnref(pool);
4802 4803 4804
    return rv;
}

4805 4806 4807 4808 4809 4810 4811 4812 4813 4814
static int
remoteDispatchConnectListAllNetworks(virNetServerPtr server ATTRIBUTE_UNUSED,
                                     virNetServerClientPtr client,
                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                     virNetMessageErrorPtr rerr,
                                     remote_connect_list_all_networks_args *args,
                                     remote_connect_list_all_networks_ret *ret)
{
    virNetworkPtr *nets = NULL;
    int nnets = 0;
4815
    size_t i;
4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828
    int rv = -1;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if ((nnets = virConnectListAllNetworks(priv->conn,
                                           args->need_results ? &nets : NULL,
                                           args->flags)) < 0)
        goto cleanup;

4829 4830 4831 4832 4833 4834 4835
    if (nnets > REMOTE_NETWORK_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many networks '%d' for limit '%d'"),
                       nnets, REMOTE_NETWORK_LIST_MAX);
        goto cleanup;
    }

4836
    if (nets && nnets) {
4837
        if (VIR_ALLOC_N(ret->nets.nets_val, nnets) < 0)
4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852
            goto cleanup;

        ret->nets.nets_len = nnets;

        for (i = 0; i < nnets; i++)
            make_nonnull_network(ret->nets.nets_val + i, nets[i]);
    } else {
        ret->nets.nets_len = 0;
        ret->nets.nets_val = NULL;
    }

    ret->ret = nnets;

    rv = 0;

4853
 cleanup:
4854 4855
    if (rv < 0)
        virNetMessageSaveError(rerr);
4856
    if (nets && nnets > 0)
4857
        for (i = 0; i < nnets; i++)
4858
            virObjectUnref(nets[i]);
4859
    VIR_FREE(nets);
4860 4861 4862
    return rv;
}

4863 4864 4865 4866 4867 4868 4869 4870 4871 4872
static int
remoteDispatchConnectListAllInterfaces(virNetServerPtr server ATTRIBUTE_UNUSED,
                                       virNetServerClientPtr client,
                                       virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                       virNetMessageErrorPtr rerr,
                                       remote_connect_list_all_interfaces_args *args,
                                       remote_connect_list_all_interfaces_ret *ret)
{
    virInterfacePtr *ifaces = NULL;
    int nifaces = 0;
4873
    size_t i;
4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886
    int rv = -1;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if ((nifaces = virConnectListAllInterfaces(priv->conn,
                                               args->need_results ? &ifaces : NULL,
                                               args->flags)) < 0)
        goto cleanup;

4887 4888 4889 4890 4891 4892 4893
    if (nifaces > REMOTE_INTERFACE_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many interfaces '%d' for limit '%d'"),
                       nifaces, REMOTE_INTERFACE_LIST_MAX);
        goto cleanup;
    }

4894
    if (ifaces && nifaces) {
4895
        if (VIR_ALLOC_N(ret->ifaces.ifaces_val, nifaces) < 0)
4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910
            goto cleanup;

        ret->ifaces.ifaces_len = nifaces;

        for (i = 0; i < nifaces; i++)
            make_nonnull_interface(ret->ifaces.ifaces_val + i, ifaces[i]);
    } else {
        ret->ifaces.ifaces_len = 0;
        ret->ifaces.ifaces_val = NULL;
    }

    ret->ret = nifaces;

    rv = 0;

4911
 cleanup:
4912 4913
    if (rv < 0)
        virNetMessageSaveError(rerr);
4914
    if (ifaces && nifaces > 0)
4915
        for (i = 0; i < nifaces; i++)
4916
            virObjectUnref(ifaces[i]);
4917
    VIR_FREE(ifaces);
4918 4919 4920
    return rv;
}

4921 4922 4923 4924 4925 4926 4927 4928 4929 4930
static int
remoteDispatchConnectListAllNodeDevices(virNetServerPtr server ATTRIBUTE_UNUSED,
                                        virNetServerClientPtr client,
                                        virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                        virNetMessageErrorPtr rerr,
                                        remote_connect_list_all_node_devices_args *args,
                                        remote_connect_list_all_node_devices_ret *ret)
{
    virNodeDevicePtr *devices = NULL;
    int ndevices = 0;
4931
    size_t i;
4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944
    int rv = -1;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if ((ndevices = virConnectListAllNodeDevices(priv->conn,
                                                 args->need_results ? &devices : NULL,
                                                 args->flags)) < 0)
        goto cleanup;

4945 4946 4947 4948 4949 4950 4951
    if (ndevices > REMOTE_NODE_DEVICE_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many node devices '%d' for limit '%d'"),
                       ndevices, REMOTE_NODE_DEVICE_LIST_MAX);
        goto cleanup;
    }

4952
    if (devices && ndevices) {
4953
        if (VIR_ALLOC_N(ret->devices.devices_val, ndevices) < 0)
4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968
            goto cleanup;

        ret->devices.devices_len = ndevices;

        for (i = 0; i < ndevices; i++)
            make_nonnull_node_device(ret->devices.devices_val + i, devices[i]);
    } else {
        ret->devices.devices_len = 0;
        ret->devices.devices_val = NULL;
    }

    ret->ret = ndevices;

    rv = 0;

4969
 cleanup:
4970 4971
    if (rv < 0)
        virNetMessageSaveError(rerr);
4972
    if (devices && ndevices > 0)
4973
        for (i = 0; i < ndevices; i++)
4974
            virObjectUnref(devices[i]);
4975
    VIR_FREE(devices);
4976 4977
    return rv;
}
4978

4979 4980 4981 4982 4983 4984 4985 4986 4987 4988
static int
remoteDispatchConnectListAllNWFilters(virNetServerPtr server ATTRIBUTE_UNUSED,
                                      virNetServerClientPtr client,
                                      virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                      virNetMessageErrorPtr rerr,
                                      remote_connect_list_all_nwfilters_args *args,
                                      remote_connect_list_all_nwfilters_ret *ret)
{
    virNWFilterPtr *filters = NULL;
    int nfilters = 0;
4989
    size_t i;
4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002
    int rv = -1;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if ((nfilters = virConnectListAllNWFilters(priv->conn,
                                               args->need_results ? &filters : NULL,
                                               args->flags)) < 0)
        goto cleanup;

5003 5004 5005 5006 5007 5008 5009
    if (nfilters > REMOTE_NWFILTER_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many network filters '%d' for limit '%d'"),
                       nfilters, REMOTE_NWFILTER_LIST_MAX);
        goto cleanup;
    }

5010
    if (filters && nfilters) {
5011
        if (VIR_ALLOC_N(ret->filters.filters_val, nfilters) < 0)
5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026
            goto cleanup;

        ret->filters.filters_len = nfilters;

        for (i = 0; i < nfilters; i++)
            make_nonnull_nwfilter(ret->filters.filters_val + i, filters[i]);
    } else {
        ret->filters.filters_len = 0;
        ret->filters.filters_val = NULL;
    }

    ret->ret = nfilters;

    rv = 0;

5027
 cleanup:
5028 5029
    if (rv < 0)
        virNetMessageSaveError(rerr);
5030
    if (filters && nfilters > 0)
5031
        for (i = 0; i < nfilters; i++)
5032
            virObjectUnref(filters[i]);
5033
    VIR_FREE(filters);
5034 5035 5036
    return rv;
}

5037 5038 5039 5040 5041 5042 5043 5044 5045 5046
static int
remoteDispatchConnectListAllSecrets(virNetServerPtr server ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client,
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                    virNetMessageErrorPtr rerr,
                                    remote_connect_list_all_secrets_args *args,
                                    remote_connect_list_all_secrets_ret *ret)
{
    virSecretPtr *secrets = NULL;
    int nsecrets = 0;
5047
    size_t i;
5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060
    int rv = -1;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if ((nsecrets = virConnectListAllSecrets(priv->conn,
                                             args->need_results ? &secrets : NULL,
                                             args->flags)) < 0)
        goto cleanup;

5061 5062 5063 5064 5065 5066 5067
    if (nsecrets > REMOTE_SECRET_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many secrets '%d' for limit '%d'"),
                       nsecrets, REMOTE_SECRET_LIST_MAX);
        goto cleanup;
    }

5068
    if (secrets && nsecrets) {
5069
        if (VIR_ALLOC_N(ret->secrets.secrets_val, nsecrets) < 0)
5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084
            goto cleanup;

        ret->secrets.secrets_len = nsecrets;

        for (i = 0; i < nsecrets; i++)
            make_nonnull_secret(ret->secrets.secrets_val + i, secrets[i]);
    } else {
        ret->secrets.secrets_len = 0;
        ret->secrets.secrets_val = NULL;
    }

    ret->ret = nsecrets;

    rv = 0;

5085
 cleanup:
5086 5087
    if (rv < 0)
        virNetMessageSaveError(rerr);
5088
    if (secrets && nsecrets > 0)
5089
        for (i = 0; i < nsecrets; i++)
5090
            virObjectUnref(secrets[i]);
5091
    VIR_FREE(secrets);
5092 5093 5094
    return rv;
}

5095 5096 5097 5098 5099 5100 5101 5102 5103
static int
remoteDispatchNodeGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
                                      virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                      virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                      virNetMessageErrorPtr rerr,
                                      remote_node_get_memory_parameters_args *args,
                                      remote_node_get_memory_parameters_ret *ret)
{
    virTypedParameterPtr params = NULL;
5104
    int nparams = 0;
5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116
    unsigned int flags;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    flags = args->flags;

5117
    if (args->nparams > REMOTE_NODE_MEMORY_PARAMETERS_MAX) {
5118 5119 5120
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
        goto cleanup;
    }
5121
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
5122
        goto cleanup;
5123
    nparams = args->nparams;
5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141

    if (virNodeGetMemoryParameters(priv->conn, params, &nparams, flags) < 0)
        goto cleanup;

    /* In this case, we need to send back the number of parameters
     * supported
     */
    if (args->nparams == 0) {
        ret->nparams = nparams;
        goto success;
    }

    if (remoteSerializeTypedParameters(params, nparams,
                                       &ret->params.params_val,
                                       &ret->params.params_len,
                                       args->flags) < 0)
        goto cleanup;

5142
 success:
5143 5144
    rv = 0;

5145
 cleanup:
5146 5147
    if (rv < 0)
        virNetMessageSaveError(rerr);
5148
    virTypedParamsFree(params, nparams);
5149 5150 5151
    return rv;
}

5152 5153 5154 5155 5156 5157 5158 5159 5160
static int
remoteDispatchNodeGetCPUMap(virNetServerPtr server ATTRIBUTE_UNUSED,
                            virNetServerClientPtr client ATTRIBUTE_UNUSED,
                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
                            virNetMessageErrorPtr rerr,
                            remote_node_get_cpu_map_args *args,
                            remote_node_get_cpu_map_ret *ret)
{
    unsigned char *cpumap = NULL;
5161
    unsigned int online = 0;
5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174
    unsigned int flags;
    int cpunum;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    flags = args->flags;

5175 5176
    cpunum = virNodeGetCPUMap(priv->conn, args->need_map ? &cpumap : NULL,
                              args->need_online ? &online : NULL, flags);
5177 5178 5179 5180
    if (cpunum < 0)
        goto cleanup;

    /* 'serialize' return cpumap */
5181
    if (args->need_map) {
5182 5183 5184 5185 5186 5187 5188 5189 5190 5191
        ret->cpumap.cpumap_len = VIR_CPU_MAPLEN(cpunum);
        ret->cpumap.cpumap_val = (char *) cpumap;
        cpumap = NULL;
    }

    ret->online = online;
    ret->ret = cpunum;

    rv = 0;

5192
 cleanup:
5193 5194 5195 5196 5197 5198
    if (rv < 0)
        virNetMessageSaveError(rerr);
    VIR_FREE(cpumap);
    return rv;
}

5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231
static int
lxcDispatchDomainOpenNamespace(virNetServerPtr server ATTRIBUTE_UNUSED,
                               virNetServerClientPtr client ATTRIBUTE_UNUSED,
                               virNetMessagePtr msg ATTRIBUTE_UNUSED,
                               virNetMessageErrorPtr rerr,
                               lxc_domain_open_namespace_args *args)
{
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
    int *fdlist = NULL;
    int ret;
    virDomainPtr dom = NULL;
    size_t i;

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    ret = virDomainLxcOpenNamespace(dom,
                                    &fdlist,
                                    args->flags);
    if (ret < 0)
        goto cleanup;

    /* We shouldn't have received any from the client,
     * but in case they're playing games with us, prevent
     * a resource leak
     */
5232
    for (i = 0; i < msg->nfds; i++)
5233 5234 5235 5236 5237 5238 5239 5240 5241
        VIR_FORCE_CLOSE(msg->fds[i]);
    VIR_FREE(msg->fds);
    msg->nfds = 0;

    msg->fds = fdlist;
    msg->nfds = ret;

    rv = 1;

5242
 cleanup:
5243 5244
    if (rv < 0)
        virNetMessageSaveError(rerr);
5245
    virObjectUnref(dom);
5246 5247 5248
    return rv;
}

5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275
static int
remoteDispatchDomainGetJobStats(virNetServerPtr server ATTRIBUTE_UNUSED,
                                virNetServerClientPtr client,
                                virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                virNetMessageErrorPtr rerr,
                                remote_domain_get_job_stats_args *args,
                                remote_domain_get_job_stats_ret *ret)
{
    virDomainPtr dom = NULL;
    virTypedParameterPtr params = NULL;
    int nparams = 0;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if (virDomainGetJobStats(dom, &ret->type, &params,
                             &nparams, args->flags) < 0)
        goto cleanup;

5276 5277 5278 5279 5280 5281 5282
    if (nparams > REMOTE_DOMAIN_JOB_STATS_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many job stats '%d' for limit '%d'"),
                       nparams, REMOTE_DOMAIN_JOB_STATS_MAX);
        goto cleanup;
    }

5283 5284 5285 5286 5287 5288 5289 5290
    if (remoteSerializeTypedParameters(params, nparams,
                                       &ret->params.params_val,
                                       &ret->params.params_len,
                                       0) < 0)
        goto cleanup;

    rv = 0;

5291
 cleanup:
5292 5293 5294
    if (rv < 0)
        virNetMessageSaveError(rerr);
    virTypedParamsFree(params, nparams);
5295
    virObjectUnref(dom);
5296 5297 5298
    return rv;
}

5299
static int
5300 5301 5302 5303 5304 5305
remoteDispatchDomainMigrateBegin3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
                                        virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                        virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                        virNetMessageErrorPtr rerr,
                                        remote_domain_migrate_begin3_params_args *args,
                                        remote_domain_migrate_begin3_params_ret *ret)
5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321
{
    char *xml = NULL;
    virDomainPtr dom = NULL;
    virTypedParameterPtr params = NULL;
    int nparams = 0;
    char *cookieout = NULL;
    int cookieoutlen = 0;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

5322 5323 5324 5325 5326 5327 5328
    if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many migration parameters '%d' for limit '%d'"),
                       args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
        goto cleanup;
    }

5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if (!(params = remoteDeserializeTypedParameters(args->params.params_val,
                                                    args->params.params_len,
                                                    0, &nparams)))
        goto cleanup;

    if (!(xml = virDomainMigrateBegin3Params(dom, params, nparams,
                                             &cookieout, &cookieoutlen,
                                             args->flags)))
        goto cleanup;

    ret->cookie_out.cookie_out_len = cookieoutlen;
    ret->cookie_out.cookie_out_val = cookieout;
    ret->xml = xml;

    rv = 0;

5348
 cleanup:
5349 5350 5351
    virTypedParamsFree(params, nparams);
    if (rv < 0)
        virNetMessageSaveError(rerr);
5352
    virObjectUnref(dom);
5353 5354 5355 5356
    return rv;
}

static int
5357 5358 5359 5360 5361 5362
remoteDispatchDomainMigratePrepare3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
                                          virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                          virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                          virNetMessageErrorPtr rerr,
                                          remote_domain_migrate_prepare3_params_args *args,
                                          remote_domain_migrate_prepare3_params_ret *ret)
5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377
{
    virTypedParameterPtr params = NULL;
    int nparams = 0;
    char *cookieout = NULL;
    int cookieoutlen = 0;
    char **uri_out;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

5378 5379 5380 5381 5382 5383 5384
    if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many migration parameters '%d' for limit '%d'"),
                       args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
        goto cleanup;
    }

5385 5386 5387 5388 5389 5390
    if (!(params = remoteDeserializeTypedParameters(args->params.params_val,
                                                    args->params.params_len,
                                                    0, &nparams)))
        goto cleanup;

    /* Wacky world of XDR ... */
5391
    if (VIR_ALLOC(uri_out) < 0)
5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406
        goto cleanup;

    if (virDomainMigratePrepare3Params(priv->conn, params, nparams,
                                       args->cookie_in.cookie_in_val,
                                       args->cookie_in.cookie_in_len,
                                       &cookieout, &cookieoutlen,
                                       uri_out, args->flags) < 0)
        goto cleanup;

    ret->cookie_out.cookie_out_len = cookieoutlen;
    ret->cookie_out.cookie_out_val = cookieout;
    ret->uri_out = !*uri_out ? NULL : uri_out;

    rv = 0;

5407
 cleanup:
5408 5409 5410 5411 5412 5413 5414 5415 5416
    virTypedParamsFree(params, nparams);
    if (rv < 0) {
        virNetMessageSaveError(rerr);
        VIR_FREE(uri_out);
    }
    return rv;
}

static int
5417 5418 5419 5420 5421 5422
remoteDispatchDomainMigratePrepareTunnel3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
                                                virNetServerClientPtr client,
                                                virNetMessagePtr msg,
                                                virNetMessageErrorPtr rerr,
                                                remote_domain_migrate_prepare_tunnel3_params_args *args,
                                                remote_domain_migrate_prepare_tunnel3_params_ret *ret)
5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438
{
    virTypedParameterPtr params = NULL;
    int nparams = 0;
    char *cookieout = NULL;
    int cookieoutlen = 0;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
    virStreamPtr st = NULL;
    daemonClientStreamPtr stream = NULL;

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

5439 5440 5441 5442 5443 5444 5445
    if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many migration parameters '%d' for limit '%d'"),
                       args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
        goto cleanup;
    }

5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469
    if (!(params = remoteDeserializeTypedParameters(args->params.params_val,
                                                    args->params.params_len,
                                                    0, &nparams)))
        goto cleanup;

    if (!(st = virStreamNew(priv->conn, VIR_STREAM_NONBLOCK)) ||
        !(stream = daemonCreateClientStream(client, st, remoteProgram,
                                            &msg->header)))
        goto cleanup;

    if (virDomainMigratePrepareTunnel3Params(priv->conn, st, params, nparams,
                                             args->cookie_in.cookie_in_val,
                                             args->cookie_in.cookie_in_len,
                                             &cookieout, &cookieoutlen,
                                             args->flags) < 0)
        goto cleanup;

    if (daemonAddClientStream(client, stream, false) < 0)
        goto cleanup;

    ret->cookie_out.cookie_out_val = cookieout;
    ret->cookie_out.cookie_out_len = cookieoutlen;
    rv = 0;

5470
 cleanup:
5471 5472 5473 5474 5475 5476 5477 5478
    virTypedParamsFree(params, nparams);
    if (rv < 0) {
        virNetMessageSaveError(rerr);
        VIR_FREE(cookieout);
        if (stream) {
            virStreamAbort(st);
            daemonFreeClientStream(client, stream);
        } else {
5479
            virObjectUnref(st);
5480 5481 5482 5483 5484 5485 5486
        }
    }
    return rv;
}


static int
5487 5488 5489 5490 5491 5492
remoteDispatchDomainMigratePerform3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
                                          virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                          virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                          virNetMessageErrorPtr rerr,
                                          remote_domain_migrate_perform3_params_args *args,
                                          remote_domain_migrate_perform3_params_ret *ret)
5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508
{
    virTypedParameterPtr params = NULL;
    int nparams = 0;
    virDomainPtr dom = NULL;
    char *cookieout = NULL;
    int cookieoutlen = 0;
    char *dconnuri;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

5509 5510 5511 5512 5513 5514 5515
    if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many migration parameters '%d' for limit '%d'"),
                       args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
        goto cleanup;
    }

5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if (!(params = remoteDeserializeTypedParameters(args->params.params_val,
                                                    args->params.params_len,
                                                    0, &nparams)))
        goto cleanup;

    dconnuri = args->dconnuri == NULL ? NULL : *args->dconnuri;

    if (virDomainMigratePerform3Params(dom, dconnuri, params, nparams,
                                       args->cookie_in.cookie_in_val,
                                       args->cookie_in.cookie_in_len,
                                       &cookieout, &cookieoutlen,
                                       args->flags) < 0)
        goto cleanup;

    ret->cookie_out.cookie_out_len = cookieoutlen;
    ret->cookie_out.cookie_out_val = cookieout;

    rv = 0;

5538
 cleanup:
5539 5540 5541
    virTypedParamsFree(params, nparams);
    if (rv < 0)
        virNetMessageSaveError(rerr);
5542
    virObjectUnref(dom);
5543 5544 5545 5546 5547
    return rv;
}


static int
5548 5549 5550 5551 5552 5553
remoteDispatchDomainMigrateFinish3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
                                         virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                         virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                         virNetMessageErrorPtr rerr,
                                         remote_domain_migrate_finish3_params_args *args,
                                         remote_domain_migrate_finish3_params_ret *ret)
5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568
{
    virTypedParameterPtr params = NULL;
    int nparams = 0;
    virDomainPtr dom = NULL;
    char *cookieout = NULL;
    int cookieoutlen = 0;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

5569 5570 5571 5572 5573 5574 5575
    if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many migration parameters '%d' for limit '%d'"),
                       args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
        goto cleanup;
    }

5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595
    if (!(params = remoteDeserializeTypedParameters(args->params.params_val,
                                                    args->params.params_len,
                                                    0, &nparams)))
        goto cleanup;

    dom = virDomainMigrateFinish3Params(priv->conn, params, nparams,
                                        args->cookie_in.cookie_in_val,
                                        args->cookie_in.cookie_in_len,
                                        &cookieout, &cookieoutlen,
                                        args->flags, args->cancelled);
    if (!dom)
        goto cleanup;

    make_nonnull_domain(&ret->dom, dom);

    ret->cookie_out.cookie_out_len = cookieoutlen;
    ret->cookie_out.cookie_out_val = cookieout;

    rv = 0;

5596
 cleanup:
5597 5598 5599 5600 5601
    virTypedParamsFree(params, nparams);
    if (rv < 0) {
        virNetMessageSaveError(rerr);
        VIR_FREE(cookieout);
    }
5602
    virObjectUnref(dom);
5603 5604 5605 5606 5607
    return rv;
}


static int
5608 5609 5610 5611 5612
remoteDispatchDomainMigrateConfirm3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
                                          virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                          virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                          virNetMessageErrorPtr rerr,
                                          remote_domain_migrate_confirm3_params_args *args)
5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625
{
    virTypedParameterPtr params = NULL;
    int nparams = 0;
    virDomainPtr dom = NULL;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

5626 5627 5628 5629 5630 5631 5632
    if (args->params.params_len > REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many migration parameters '%d' for limit '%d'"),
                       args->params.params_len, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX);
        goto cleanup;
    }

5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if (!(params = remoteDeserializeTypedParameters(args->params.params_val,
                                                    args->params.params_len,
                                                    0, &nparams)))
        goto cleanup;

    if (virDomainMigrateConfirm3Params(dom, params, nparams,
                                       args->cookie_in.cookie_in_val,
                                       args->cookie_in.cookie_in_len,
                                       args->flags, args->cancelled) < 0)
        goto cleanup;

    rv = 0;

5649
 cleanup:
5650 5651 5652
    virTypedParamsFree(params, nparams);
    if (rv < 0)
        virNetMessageSaveError(rerr);
5653
    virObjectUnref(dom);
5654 5655 5656 5657
    return rv;
}


5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701
static int
remoteDispatchConnectGetCPUModelNames(virNetServerPtr server ATTRIBUTE_UNUSED,
                                      virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                      virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                      virNetMessageErrorPtr rerr,
                                      remote_connect_get_cpu_model_names_args *args,
                                      remote_connect_get_cpu_model_names_ret *ret)
{
    int len, rv = -1;
    char **models = NULL;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    len = virConnectGetCPUModelNames(priv->conn, args->arch,
                                     args->need_results ? &models : NULL,
                                     args->flags);
    if (len < 0)
        goto cleanup;

    if (len > REMOTE_CONNECT_CPU_MODELS_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many CPU models '%d' for limit '%d'"),
                       len, REMOTE_CONNECT_CPU_MODELS_MAX);
        goto cleanup;
    }

    if (len && models) {
        ret->models.models_val = models;
        ret->models.models_len = len;
        models = NULL;
    } else {
        ret->models.models_val = NULL;
        ret->models.models_len = 0;
    }

    ret->ret = len;

    rv = 0;

5702
 cleanup:
5703 5704 5705 5706 5707 5708 5709
    if (rv < 0)
        virNetMessageSaveError(rerr);
    virStringFreeList(models);
    return rv;
}


5710 5711 5712 5713 5714 5715 5716
static int
remoteDispatchDomainCreateXMLWithFiles(virNetServerPtr server ATTRIBUTE_UNUSED,
                                       virNetServerClientPtr client,
                                       virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                       virNetMessageErrorPtr rerr,
                                       remote_domain_create_xml_with_files_args *args,
                                       remote_domain_create_xml_with_files_ret *ret)
5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746
{
    int rv = -1;
    virDomainPtr dom = NULL;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
    int *files = NULL;
    unsigned int nfiles = 0;
    size_t i;

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if (VIR_ALLOC_N(files, msg->nfds) < 0)
        goto cleanup;
    for (i = 0; i < msg->nfds; i++) {
        if ((files[i] = virNetMessageDupFD(msg, i)) < 0)
            goto cleanup;
        nfiles++;
    }

    if ((dom = virDomainCreateXMLWithFiles(priv->conn, args->xml_desc,
                                           nfiles, files,
                                           args->flags)) == NULL)
        goto cleanup;

    make_nonnull_domain(&ret->dom, dom);
    rv = 0;

5747
 cleanup:
5748
    for (i = 0; i < nfiles; i++)
5749 5750 5751 5752
        VIR_FORCE_CLOSE(files[i]);
    VIR_FREE(files);
    if (rv < 0)
        virNetMessageSaveError(rerr);
5753
    virObjectUnref(dom);
5754 5755 5756 5757
    return rv;
}


5758 5759 5760 5761 5762 5763
static int remoteDispatchDomainCreateWithFiles(virNetServerPtr server ATTRIBUTE_UNUSED,
                                               virNetServerClientPtr client,
                                               virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                               virNetMessageErrorPtr rerr,
                                               remote_domain_create_with_files_args *args,
                                               remote_domain_create_with_files_ret *ret)
5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796
{
    int rv = -1;
    virDomainPtr dom = NULL;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
    int *files = NULL;
    unsigned int nfiles = 0;
    size_t i;

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if (VIR_ALLOC_N(files, msg->nfds) < 0)
        goto cleanup;
    for (i = 0; i < msg->nfds; i++) {
        if ((files[i] = virNetMessageDupFD(msg, i)) < 0)
            goto cleanup;
        nfiles++;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if (virDomainCreateWithFiles(dom,
                                 nfiles, files,
                                 args->flags) < 0)
        goto cleanup;

    make_nonnull_domain(&ret->dom, dom);
    rv = 0;

5797
 cleanup:
5798
    for (i = 0; i < nfiles; i++)
5799 5800 5801 5802
        VIR_FORCE_CLOSE(files[i]);
    VIR_FREE(files);
    if (rv < 0)
        virNetMessageSaveError(rerr);
5803
    virObjectUnref(dom);
5804 5805 5806 5807
    return rv;
}


5808 5809
static int
remoteDispatchConnectNetworkEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
5810
                                             virNetServerClientPtr client,
5811 5812 5813
                                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                             virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                             remote_connect_network_event_register_any_args *args,
5814
                                             remote_connect_network_event_register_any_ret *ret)
5815 5816 5817
{
    int callbackID;
    int rv = -1;
5818 5819
    daemonClientEventCallbackPtr callback = NULL;
    daemonClientEventCallbackPtr ref;
5820 5821
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
5822
    virNetworkPtr net = NULL;
5823 5824 5825 5826 5827 5828 5829 5830

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    virMutexLock(&priv->lock);

5831 5832 5833 5834
    if (args->net &&
        !(net = get_nonnull_network(priv->conn, *args->net)))
        goto cleanup;

5835 5836 5837
    if (args->eventID >= VIR_NETWORK_EVENT_ID_LAST || args->eventID < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unsupported network event ID %d"), args->eventID);
5838 5839 5840
        goto cleanup;
    }

5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855
    /* If we call register first, we could append a complete callback
     * to our array, but on OOM append failure, we'd have to then hope
     * deregister works to undo our register.  So instead we append an
     * incomplete callback to our array, then register, then fix up
     * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
     * success, we use 'ref' to save a copy of the pointer.  */
    if (VIR_ALLOC(callback) < 0)
        goto cleanup;
    callback->client = client;
    callback->eventID = args->eventID;
    callback->callbackID = -1;
    ref = callback;
    if (VIR_APPEND_ELEMENT(priv->networkEventCallbacks,
                           priv->nnetworkEventCallbacks,
                           callback) < 0)
5856 5857 5858
        goto cleanup;

    if ((callbackID = virConnectNetworkEventRegisterAny(priv->conn,
5859
                                                        net,
5860 5861
                                                        args->eventID,
                                                        networkEventCallbacks[args->eventID],
5862 5863 5864 5865 5866
                                                        ref,
                                                        remoteEventCallbackFree)) < 0) {
        VIR_SHRINK_N(priv->networkEventCallbacks,
                     priv->nnetworkEventCallbacks, 1);
        callback = ref;
5867
        goto cleanup;
5868
    }
5869

5870
    ref->callbackID = callbackID;
5871
    ret->callbackID = callbackID;
5872 5873 5874

    rv = 0;

5875
 cleanup:
5876
    VIR_FREE(callback);
5877 5878
    if (rv < 0)
        virNetMessageSaveError(rerr);
5879
    virObjectUnref(net);
5880 5881 5882 5883 5884 5885 5886
    virMutexUnlock(&priv->lock);
    return rv;
}


static int
remoteDispatchConnectNetworkEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
5887
                                               virNetServerClientPtr client,
5888 5889
                                               virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                               virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
5890
                                               remote_connect_network_event_deregister_any_args *args)
5891 5892
{
    int rv = -1;
5893
    size_t i;
5894 5895 5896 5897 5898 5899 5900 5901 5902 5903
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    virMutexLock(&priv->lock);

5904
    for (i = 0; i < priv->nnetworkEventCallbacks; i++) {
5905
        if (priv->networkEventCallbacks[i]->callbackID == args->callbackID)
5906 5907
            break;
    }
5908
    if (i == priv->nnetworkEventCallbacks) {
5909
        virReportError(VIR_ERR_INTERNAL_ERROR,
5910 5911
                       _("network event callback %d not registered"),
                       args->callbackID);
5912 5913 5914
        goto cleanup;
    }

5915
    if (virConnectNetworkEventDeregisterAny(priv->conn, args->callbackID) < 0)
5916 5917
        goto cleanup;

5918 5919
    VIR_DELETE_ELEMENT(priv->networkEventCallbacks, i,
                       priv->nnetworkEventCallbacks);
5920 5921 5922

    rv = 0;

5923
 cleanup:
5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992
    if (rv < 0)
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
    return rv;
}


static int
qemuDispatchConnectDomainMonitorEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
                                              virNetServerClientPtr client,
                                              virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                              virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                              qemu_connect_domain_monitor_event_register_args *args,
                                              qemu_connect_domain_monitor_event_register_ret *ret)
{
    int callbackID;
    int rv = -1;
    daemonClientEventCallbackPtr callback = NULL;
    daemonClientEventCallbackPtr ref;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
    virDomainPtr dom = NULL;
    const char *event = args->event ? *args->event : NULL;

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    virMutexLock(&priv->lock);

    if (args->dom &&
        !(dom = get_nonnull_domain(priv->conn, *args->dom)))
        goto cleanup;

    /* If we call register first, we could append a complete callback
     * to our array, but on OOM append failure, we'd have to then hope
     * deregister works to undo our register.  So instead we append an
     * incomplete callback to our array, then register, then fix up
     * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
     * success, we use 'ref' to save a copy of the pointer.  */
    if (VIR_ALLOC(callback) < 0)
        goto cleanup;
    callback->client = client;
    callback->callbackID = -1;
    ref = callback;
    if (VIR_APPEND_ELEMENT(priv->qemuEventCallbacks,
                           priv->nqemuEventCallbacks,
                           callback) < 0)
        goto cleanup;

    if ((callbackID = virConnectDomainQemuMonitorEventRegister(priv->conn,
                                                               dom,
                                                               event,
                                                               remoteRelayDomainQemuMonitorEvent,
                                                               ref,
                                                               remoteEventCallbackFree,
                                                               args->flags)) < 0) {
        VIR_SHRINK_N(priv->qemuEventCallbacks,
                     priv->nqemuEventCallbacks, 1);
        callback = ref;
        goto cleanup;
    }

    ref->callbackID = callbackID;
    ret->callbackID = callbackID;

    rv = 0;

5993
 cleanup:
5994 5995 5996
    VIR_FREE(callback);
    if (rv < 0)
        virNetMessageSaveError(rerr);
5997
    virObjectUnref(dom);
5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041
    virMutexUnlock(&priv->lock);
    return rv;
}


static int
qemuDispatchConnectDomainMonitorEventDeregister(virNetServerPtr server ATTRIBUTE_UNUSED,
                                                virNetServerClientPtr client,
                                                virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                                virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                                qemu_connect_domain_monitor_event_deregister_args *args)
{
    int rv = -1;
    size_t i;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    virMutexLock(&priv->lock);

    for (i = 0; i < priv->nqemuEventCallbacks; i++) {
        if (priv->qemuEventCallbacks[i]->callbackID == args->callbackID)
            break;
    }
    if (i == priv->nqemuEventCallbacks) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("qemu monitor event callback %d not registered"),
                       args->callbackID);
        goto cleanup;
    }

    if (virConnectDomainQemuMonitorEventDeregister(priv->conn,
                                                   args->callbackID) < 0)
        goto cleanup;

    VIR_DELETE_ELEMENT(priv->qemuEventCallbacks, i,
                       priv->nqemuEventCallbacks);

    rv = 0;

6042
 cleanup:
6043 6044 6045 6046 6047 6048
    if (rv < 0)
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
    return rv;
}

6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081
static int
remoteDispatchDomainGetTime(virNetServerPtr server ATTRIBUTE_UNUSED,
                            virNetServerClientPtr client,
                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
                            virNetMessageErrorPtr rerr,
                            remote_domain_get_time_args *args,
                            remote_domain_get_time_ret *ret)
{
    int rv = -1;
    virDomainPtr dom = NULL;
    long long seconds;
    unsigned int nseconds;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if (virDomainGetTime(dom, &seconds, &nseconds, args->flags) < 0)
        goto cleanup;

    ret->seconds = seconds;
    ret->nseconds = nseconds;
    rv = 0;

 cleanup:
    if (rv < 0)
        virNetMessageSaveError(rerr);
6082
    virObjectUnref(dom);
6083 6084
    return rv;
}
6085

M
Michal Privoznik 已提交
6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133

static int
remoteDispatchNodeGetFreePages(virNetServerPtr server ATTRIBUTE_UNUSED,
                               virNetServerClientPtr client,
                               virNetMessagePtr msg ATTRIBUTE_UNUSED,
                               virNetMessageErrorPtr rerr,
                               remote_node_get_free_pages_args *args,
                               remote_node_get_free_pages_ret *ret)
{
    int rv = -1;
    int len;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if (args->pages.pages_len * args->cellCount > REMOTE_NODE_MAX_CELLS) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("the result won't fit into REMOTE_NODE_MAX_CELLS"));
        goto cleanup;
    }

    /* Allocate return buffer. */
    if (VIR_ALLOC_N(ret->counts.counts_val,
                    args->pages.pages_len * args->cellCount) < 0)
        goto cleanup;

    if ((len = virNodeGetFreePages(priv->conn,
                                   args->pages.pages_len,
                                   args->pages.pages_val,
                                   args->startCell,
                                   args->cellCount,
                                   (unsigned long long *) ret->counts.counts_val,
                                   args->flags)) <= 0)
        goto cleanup;

    ret->counts.counts_len = len;
    rv = 0;

 cleanup:
    if (rv < 0) {
        virNetMessageSaveError(rerr);
        VIR_FREE(ret->counts.counts_val);
    }
    return rv;
6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148
}

/* Copy contents of virNetworkDHCPLeasePtr to remote_network_dhcp_lease */
static int
remoteSerializeDHCPLease(remote_network_dhcp_lease *lease_dst, virNetworkDHCPLeasePtr lease_src)
{
    char **mac_tmp = NULL;
    char **iaid_tmp = NULL;
    char **hostname_tmp = NULL;
    char **clientid_tmp = NULL;

    lease_dst->expirytime = lease_src->expirytime;
    lease_dst->type = lease_src->type;
    lease_dst->prefix = lease_src->prefix;

6149
    if (VIR_STRDUP(lease_dst->iface, lease_src->iface) < 0 ||
J
Ján Tomko 已提交
6150
        VIR_STRDUP(lease_dst->ipaddr, lease_src->ipaddr) < 0)
6151 6152
        goto error;

J
Ján Tomko 已提交
6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177
    if (lease_src->mac) {
        if (VIR_ALLOC(mac_tmp) < 0 ||
            VIR_STRDUP(*mac_tmp, lease_src->mac) < 0)
            goto error;
    }
    if (lease_src->iaid) {
        if (VIR_ALLOC(iaid_tmp) < 0 ||
            VIR_STRDUP(*iaid_tmp, lease_src->iaid) < 0)
            goto error;
    }
    if (lease_src->hostname) {
        if (VIR_ALLOC(hostname_tmp) < 0 ||
            VIR_STRDUP(*hostname_tmp, lease_src->hostname) < 0)
            goto error;
    }
    if (lease_src->clientid) {
        if (VIR_ALLOC(clientid_tmp) < 0 ||
            VIR_STRDUP(*clientid_tmp, lease_src->clientid) < 0)
            goto error;
    }

    lease_dst->mac = mac_tmp;
    lease_dst->iaid = iaid_tmp;
    lease_dst->hostname = hostname_tmp;
    lease_dst->clientid = clientid_tmp;
6178 6179 6180 6181

    return 0;

 error:
J
Ján Tomko 已提交
6182 6183 6184 6185 6186 6187 6188 6189
    if (mac_tmp)
        VIR_FREE(*mac_tmp);
    if (iaid_tmp)
        VIR_FREE(*iaid_tmp);
    if (hostname_tmp)
        VIR_FREE(*hostname_tmp);
    if (clientid_tmp)
        VIR_FREE(*clientid_tmp);
6190 6191 6192 6193 6194
    VIR_FREE(mac_tmp);
    VIR_FREE(iaid_tmp);
    VIR_FREE(hostname_tmp);
    VIR_FREE(clientid_tmp);
    VIR_FREE(lease_dst->ipaddr);
6195
    VIR_FREE(lease_dst->iface);
6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223
    return -1;
}


static int
remoteDispatchNetworkGetDHCPLeases(virNetServerPtr server ATTRIBUTE_UNUSED,
                                   virNetServerClientPtr client,
                                   virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                   virNetMessageErrorPtr rerr,
                                   remote_network_get_dhcp_leases_args *args,
                                   remote_network_get_dhcp_leases_ret *ret)
{
    int rv = -1;
    size_t i;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
    virNetworkDHCPLeasePtr *leases = NULL;
    virNetworkPtr net = NULL;
    int nleases = 0;

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if (!(net = get_nonnull_network(priv->conn, args->net)))
        goto cleanup;

    if ((nleases = virNetworkGetDHCPLeases(net,
6224
                                           args->mac ? *args->mac : NULL,
6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258
                                           args->need_results ? &leases : NULL,
                                           args->flags)) < 0)
        goto cleanup;

    if (nleases > REMOTE_NETWORK_DHCP_LEASES_MAX) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Number of leases is %d, which exceeds max limit: %d"),
                       nleases, REMOTE_NETWORK_DHCP_LEASES_MAX);
        goto cleanup;
    }

    if (leases && nleases) {
        if (VIR_ALLOC_N(ret->leases.leases_val, nleases) < 0)
            goto cleanup;

        ret->leases.leases_len = nleases;

        for (i = 0; i < nleases; i++) {
            if (remoteSerializeDHCPLease(ret->leases.leases_val + i, leases[i]) < 0)
                goto cleanup;
        }

    } else {
        ret->leases.leases_len = 0;
        ret->leases.leases_val = NULL;
    }

    ret->ret = nleases;

    rv = 0;

 cleanup:
    if (rv < 0)
        virNetMessageSaveError(rerr);
6259
    if (leases && nleases > 0)
6260 6261
        for (i = 0; i < nleases; i++)
            virNetworkDHCPLeaseFree(leases[i]);
6262
    VIR_FREE(leases);
6263
    virObjectUnref(net);
6264
    return rv;
M
Michal Privoznik 已提交
6265 6266 6267
}


6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 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 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353
static int
remoteDispatchConnectGetAllDomainStats(virNetServerPtr server ATTRIBUTE_UNUSED,
                                       virNetServerClientPtr client,
                                       virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                       virNetMessageErrorPtr rerr,
                                       remote_connect_get_all_domain_stats_args *args,
                                       remote_connect_get_all_domain_stats_ret *ret)
{
    int rv = -1;
    size_t i;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
    virDomainStatsRecordPtr *retStats = NULL;
    int nrecords = 0;
    virDomainPtr *doms = NULL;

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if (args->doms.doms_len) {
        if (VIR_ALLOC_N(doms, args->doms.doms_len + 1) < 0)
            goto cleanup;

        for (i = 0; i < args->doms.doms_len; i++) {
            if (!(doms[i] = get_nonnull_domain(priv->conn, args->doms.doms_val[i])))
                goto cleanup;
        }

        if ((nrecords = virDomainListGetStats(doms,
                                              args->stats,
                                              &retStats,
                                              args->flags)) < 0)
            goto cleanup;
    } else {
        if ((nrecords = virConnectGetAllDomainStats(priv->conn,
                                                    args->stats,
                                                    &retStats,
                                                    args->flags)) < 0)
            goto cleanup;
    }

    if (nrecords > REMOTE_CONNECT_GET_ALL_DOMAIN_STATS_MAX) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Number of domain stats records is %d, "
                         "which exceeds max limit: %d"),
                       nrecords, REMOTE_DOMAIN_LIST_MAX);
        goto cleanup;
    }

    if (nrecords) {
        if (VIR_ALLOC_N(ret->retStats.retStats_val, nrecords) < 0)
            goto cleanup;

        ret->retStats.retStats_len = nrecords;

        for (i = 0; i < nrecords; i++) {
            remote_domain_stats_record *dst = ret->retStats.retStats_val + i;

            make_nonnull_domain(&dst->dom, retStats[i]->dom);

            if (remoteSerializeTypedParameters(retStats[i]->params,
                                               retStats[i]->nparams,
                                               &dst->params.params_val,
                                               &dst->params.params_len,
                                               VIR_TYPED_PARAM_STRING_OKAY) < 0)
                goto cleanup;
        }
    } else {
        ret->retStats.retStats_len = 0;
        ret->retStats.retStats_val = NULL;
    }

    rv = 0;

 cleanup:
    if (rv < 0)
        virNetMessageSaveError(rerr);

    virDomainStatsRecordListFree(retStats);
    virDomainListFree(doms);

    return rv;
}


M
Michal Privoznik 已提交
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
static int
remoteDispatchNodeAllocPages(virNetServerPtr server ATTRIBUTE_UNUSED,
                             virNetServerClientPtr client,
                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
                             virNetMessageErrorPtr rerr,
                             remote_node_alloc_pages_args *args,
                             remote_node_alloc_pages_ret *ret)
{
    int rv = -1;
    int len;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if ((len = virNodeAllocPages(priv->conn,
                                 args->pageSizes.pageSizes_len,
                                 args->pageSizes.pageSizes_val,
                                 (unsigned long long *) args->pageCounts.pageCounts_val,
                                 args->startCell,
                                 args->cellCount,
                                 args->flags)) < 0)
        goto cleanup;

    ret->ret = len;
    rv = 0;

 cleanup:
    if (rv < 0)
        virNetMessageSaveError(rerr);
    return rv;
}


6391 6392 6393 6394 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
static int
remoteDispatchDomainGetFSInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
                              virNetServerClientPtr client,
                              virNetMessagePtr msg ATTRIBUTE_UNUSED,
                              virNetMessageErrorPtr rerr,
                              remote_domain_get_fsinfo_args *args,
                              remote_domain_get_fsinfo_ret *ret)
{
    int rv = -1;
    size_t i, j;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
    virDomainFSInfoPtr *info = NULL;
    virDomainPtr dom = NULL;
    remote_domain_fsinfo *dst;
    int ninfo = 0;
    size_t ndisk;

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if ((ninfo = virDomainGetFSInfo(dom, &info, args->flags)) < 0)
        goto cleanup;

    if (ninfo > REMOTE_DOMAIN_FSINFO_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many mountpoints in fsinfo: %d for limit %d"),
                       ninfo, REMOTE_DOMAIN_FSINFO_MAX);
        goto cleanup;
    }

    if (ninfo) {
        if (VIR_ALLOC_N(ret->info.info_val, ninfo) < 0)
            goto cleanup;

        ret->info.info_len = ninfo;

        for (i = 0; i < ninfo; i++) {
            dst = &ret->info.info_val[i];
            if (VIR_STRDUP(dst->mountpoint, info[i]->mountpoint) < 0)
                goto cleanup;

            if (VIR_STRDUP(dst->name, info[i]->name) < 0)
                goto cleanup;

            if (VIR_STRDUP(dst->fstype, info[i]->fstype) < 0)
                goto cleanup;

            ndisk = info[i]->ndevAlias;
            if (ndisk > REMOTE_DOMAIN_FSINFO_DISKS_MAX) {
                virReportError(VIR_ERR_RPC,
                               _("Too many disks in fsinfo: %zd for limit %d"),
                               ndisk, REMOTE_DOMAIN_FSINFO_DISKS_MAX);
                goto cleanup;
            }

            if (ndisk > 0) {
                if (VIR_ALLOC_N(dst->dev_aliases.dev_aliases_val, ndisk) < 0)
                    goto cleanup;

                for (j = 0; j < ndisk; j++) {
                    if (VIR_STRDUP(dst->dev_aliases.dev_aliases_val[j],
                                   info[i]->devAlias[j]) < 0)
                        goto cleanup;
                }

                dst->dev_aliases.dev_aliases_len = ndisk;
            } else {
                dst->dev_aliases.dev_aliases_val = NULL;
                dst->dev_aliases.dev_aliases_len = 0;
            }
        }

    } else {
        ret->info.info_len = 0;
        ret->info.info_val = NULL;
    }

    ret->ret = ninfo;

    rv = 0;

 cleanup:
    if (rv < 0) {
        virNetMessageSaveError(rerr);

        if (ret->info.info_val && ninfo > 0) {
            for (i = 0; i < ninfo; i++) {
                dst = &ret->info.info_val[i];
                VIR_FREE(dst->mountpoint);
                if (dst->dev_aliases.dev_aliases_val) {
                    for (j = 0; j < dst->dev_aliases.dev_aliases_len; j++)
                        VIR_FREE(dst->dev_aliases.dev_aliases_val[j]);
                    VIR_FREE(dst->dev_aliases.dev_aliases_val);
                }
            }
            VIR_FREE(ret->info.info_val);
        }
    }
6494
    virObjectUnref(dom);
6495 6496 6497 6498 6499 6500 6501 6502 6503
    if (ninfo >= 0)
        for (i = 0; i < ninfo; i++)
            virDomainFSInfoFree(info[i]);
    VIR_FREE(info);

    return rv;
}


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
static int
remoteSerializeDomainInterface(virDomainInterfacePtr *ifaces,
                               unsigned int ifaces_count,
                               remote_domain_interface_addresses_ret *ret)
{
    size_t i, j;

    if (ifaces_count > REMOTE_DOMAIN_INTERFACE_MAX) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Number of interfaces, %d exceeds the max limit: %d"),
                       ifaces_count, REMOTE_DOMAIN_INTERFACE_MAX);
        return -1;
    }

    if (VIR_ALLOC_N(ret->ifaces.ifaces_val, ifaces_count) < 0)
        return -1;

    ret->ifaces.ifaces_len = ifaces_count;

    for (i = 0; i < ifaces_count; i++) {
        virDomainInterfacePtr iface = ifaces[i];
        remote_domain_interface *iface_ret = &(ret->ifaces.ifaces_val[i]);

        if ((VIR_STRDUP(iface_ret->name, iface->name)) < 0)
            goto cleanup;

6530 6531 6532
        if (iface->hwaddr &&
            (VIR_ALLOC(iface_ret->hwaddr) < 0 ||
             VIR_STRDUP(*iface_ret->hwaddr, iface->hwaddr) < 0))
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 6565 6566 6567
            goto cleanup;

        if (iface->naddrs > REMOTE_DOMAIN_IP_ADDR_MAX) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Number of interfaces, %d exceeds the max limit: %d"),
                           iface->naddrs, REMOTE_DOMAIN_IP_ADDR_MAX);
            goto cleanup;
        }

        if (VIR_ALLOC_N(iface_ret->addrs.addrs_val,
                        iface->naddrs) < 0)
            goto cleanup;

        iface_ret->addrs.addrs_len = iface->naddrs;

        for (j = 0; j < iface->naddrs; j++) {
            virDomainIPAddressPtr ip_addr = &(iface->addrs[j]);
            remote_domain_ip_addr *ip_addr_ret =
                &(iface_ret->addrs.addrs_val[j]);

            if (VIR_STRDUP(ip_addr_ret->addr, ip_addr->addr) < 0)
                goto cleanup;

            ip_addr_ret->prefix = ip_addr->prefix;
            ip_addr_ret->type = ip_addr->type;
        }
    }

    return 0;

 cleanup:
    if (ret->ifaces.ifaces_val) {
        for (i = 0; i < ifaces_count; i++) {
            remote_domain_interface *iface_ret = &(ret->ifaces.ifaces_val[i]);
            VIR_FREE(iface_ret->name);
6568 6569 6570 6571
            if (iface_ret->hwaddr) {
                VIR_FREE(*iface_ret->hwaddr);
                VIR_FREE(iface_ret->hwaddr);
            }
6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632
            for (j = 0; j < iface_ret->addrs.addrs_len; j++) {
                remote_domain_ip_addr *ip_addr =
                    &(iface_ret->addrs.addrs_val[j]);
                VIR_FREE(ip_addr->addr);
            }
        }
        VIR_FREE(ret->ifaces.ifaces_val);
    }

    return -1;
}


static int
remoteDispatchDomainInterfaceAddresses(virNetServerPtr server ATTRIBUTE_UNUSED,
                                       virNetServerClientPtr client,
                                       virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                       virNetMessageErrorPtr rerr,
                                       remote_domain_interface_addresses_args *args,
                                       remote_domain_interface_addresses_ret *ret)
{
    size_t i;
    int rv = -1;
    virDomainPtr dom = NULL;
    virDomainInterfacePtr *ifaces = NULL;
    int ifaces_count = 0;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
        goto cleanup;
    }

    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
        goto cleanup;

    if ((ifaces_count = virDomainInterfaceAddresses(dom, &ifaces, args->source, args->flags)) < 0)
        goto cleanup;

    if (remoteSerializeDomainInterface(ifaces, ifaces_count, ret) < 0)
        goto cleanup;

    rv = 0;

 cleanup:
    if (rv < 0)
        virNetMessageSaveError(rerr);

    virObjectUnref(dom);

    if (ifaces && ifaces_count > 0) {
        for (i = 0; i < ifaces_count; i++)
            virDomainInterfaceFree(ifaces[i]);
    }
    VIR_FREE(ifaces);

    return rv;
}


6633 6634 6635 6636 6637 6638 6639 6640 6641
/*----- Helpers. -----*/

/* get_nonnull_domain and get_nonnull_network turn an on-wire
 * (name, uuid) pair into virDomainPtr or virNetworkPtr object.
 * virDomainPtr or virNetworkPtr cannot be NULL.
 *
 * NB. If these return NULL then the caller must return an error.
 */
static virDomainPtr
6642
get_nonnull_domain(virConnectPtr conn, remote_nonnull_domain domain)
6643 6644
{
    virDomainPtr dom;
6645
    dom = virGetDomain(conn, domain.name, BAD_CAST domain.uuid);
6646 6647 6648 6649 6650 6651 6652 6653
    /* Should we believe the domain.id sent by the client?  Maybe
     * this should be a check rather than an assignment? XXX
     */
    if (dom) dom->id = domain.id;
    return dom;
}

static virNetworkPtr
6654
get_nonnull_network(virConnectPtr conn, remote_nonnull_network network)
6655
{
6656
    return virGetNetwork(conn, network.name, BAD_CAST network.uuid);
6657 6658
}

D
Daniel Veillard 已提交
6659
static virInterfacePtr
6660
get_nonnull_interface(virConnectPtr conn, remote_nonnull_interface iface)
D
Daniel Veillard 已提交
6661
{
6662
    return virGetInterface(conn, iface.name, iface.mac);
D
Daniel Veillard 已提交
6663 6664
}

6665
static virStoragePoolPtr
6666
get_nonnull_storage_pool(virConnectPtr conn, remote_nonnull_storage_pool pool)
6667
{
6668 6669
    return virGetStoragePool(conn, pool.name, BAD_CAST pool.uuid,
                             NULL, NULL);
6670 6671 6672
}

static virStorageVolPtr
6673
get_nonnull_storage_vol(virConnectPtr conn, remote_nonnull_storage_vol vol)
6674 6675
{
    virStorageVolPtr ret;
6676 6677
    ret = virGetStorageVol(conn, vol.pool, vol.name, vol.key,
                           NULL, NULL);
6678 6679 6680
    return ret;
}

6681
static virSecretPtr
6682
get_nonnull_secret(virConnectPtr conn, remote_nonnull_secret secret)
6683
{
6684
    return virGetSecret(conn, BAD_CAST secret.uuid, secret.usageType, secret.usageID);
6685 6686
}

6687
static virNWFilterPtr
6688
get_nonnull_nwfilter(virConnectPtr conn, remote_nonnull_nwfilter nwfilter)
6689
{
6690
    return virGetNWFilter(conn, nwfilter.name, BAD_CAST nwfilter.uuid);
6691 6692
}

C
Chris Lalancette 已提交
6693
static virDomainSnapshotPtr
6694
get_nonnull_domain_snapshot(virDomainPtr dom, remote_nonnull_domain_snapshot snapshot)
C
Chris Lalancette 已提交
6695
{
6696
    return virGetDomainSnapshot(dom, snapshot.name);
C
Chris Lalancette 已提交
6697 6698
}

6699 6700
/* Make remote_nonnull_domain and remote_nonnull_network. */
static void
6701
make_nonnull_domain(remote_nonnull_domain *dom_dst, virDomainPtr dom_src)
6702 6703
{
    dom_dst->id = dom_src->id;
6704
    ignore_value(VIR_STRDUP_QUIET(dom_dst->name, dom_src->name));
6705
    memcpy(dom_dst->uuid, dom_src->uuid, VIR_UUID_BUFLEN);
6706 6707 6708
}

static void
6709
make_nonnull_network(remote_nonnull_network *net_dst, virNetworkPtr net_src)
6710
{
6711
    ignore_value(VIR_STRDUP_QUIET(net_dst->name, net_src->name));
6712
    memcpy(net_dst->uuid, net_src->uuid, VIR_UUID_BUFLEN);
6713 6714
}

D
Daniel Veillard 已提交
6715
static void
6716 6717
make_nonnull_interface(remote_nonnull_interface *interface_dst,
                       virInterfacePtr interface_src)
D
Daniel Veillard 已提交
6718
{
6719 6720
    ignore_value(VIR_STRDUP_QUIET(interface_dst->name, interface_src->name));
    ignore_value(VIR_STRDUP_QUIET(interface_dst->mac, interface_src->mac));
D
Daniel Veillard 已提交
6721 6722
}

6723
static void
6724
make_nonnull_storage_pool(remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr pool_src)
6725
{
6726
    ignore_value(VIR_STRDUP_QUIET(pool_dst->name, pool_src->name));
6727
    memcpy(pool_dst->uuid, pool_src->uuid, VIR_UUID_BUFLEN);
6728 6729 6730
}

static void
6731
make_nonnull_storage_vol(remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src)
6732
{
6733 6734 6735
    ignore_value(VIR_STRDUP_QUIET(vol_dst->pool, vol_src->pool));
    ignore_value(VIR_STRDUP_QUIET(vol_dst->name, vol_src->name));
    ignore_value(VIR_STRDUP_QUIET(vol_dst->key, vol_src->key));
6736
}
6737 6738

static void
6739
make_nonnull_node_device(remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src)
6740
{
6741
    ignore_value(VIR_STRDUP_QUIET(dev_dst->name, dev_src->name));
6742
}
6743 6744

static void
6745
make_nonnull_secret(remote_nonnull_secret *secret_dst, virSecretPtr secret_src)
6746
{
6747
    memcpy(secret_dst->uuid, secret_src->uuid, VIR_UUID_BUFLEN);
6748
    secret_dst->usageType = secret_src->usageType;
6749
    ignore_value(VIR_STRDUP_QUIET(secret_dst->usageID, secret_src->usageID));
6750
}
6751 6752

static void
6753
make_nonnull_nwfilter(remote_nonnull_nwfilter *nwfilter_dst, virNWFilterPtr nwfilter_src)
6754
{
6755
    ignore_value(VIR_STRDUP_QUIET(nwfilter_dst->name, nwfilter_src->name));
6756
    memcpy(nwfilter_dst->uuid, nwfilter_src->uuid, VIR_UUID_BUFLEN);
6757
}
C
Chris Lalancette 已提交
6758 6759

static void
6760
make_nonnull_domain_snapshot(remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src)
C
Chris Lalancette 已提交
6761
{
6762
    ignore_value(VIR_STRDUP_QUIET(snapshot_dst->name, snapshot_src->name));
6763
    make_nonnull_domain(&snapshot_dst->dom, snapshot_src->domain);
C
Chris Lalancette 已提交
6764
}
6765 6766 6767 6768 6769 6770 6771 6772

static int
remoteSerializeDomainDiskErrors(virDomainDiskErrorPtr errors,
                                int nerrors,
                                remote_domain_disk_error **ret_errors_val,
                                u_int *ret_errors_len)
{
    remote_domain_disk_error *val = NULL;
6773
    size_t i = 0;
6774

6775
    if (VIR_ALLOC_N(val, nerrors) < 0)
6776
        goto error;
6777 6778

    for (i = 0; i < nerrors; i++) {
6779 6780
        if (VIR_STRDUP(val[i].disk, errors[i].disk) < 0)
            goto error;
6781 6782 6783 6784 6785 6786 6787 6788
        val[i].error = errors[i].error;
    }

    *ret_errors_len = nerrors;
    *ret_errors_val = val;

    return 0;

6789
 error:
6790
    if (val) {
6791
        size_t j;
6792 6793 6794 6795 6796 6797
        for (j = 0; j < i; j++)
            VIR_FREE(val[j].disk);
        VIR_FREE(val);
    }
    return -1;
}