remote.c 220.0 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 109 110
static int
remoteSerializeTypedParameters(virTypedParameterPtr params,
                               int nparams,
                               remote_typed_param **ret_params_val,
                               u_int *ret_params_len,
                               unsigned int flags);

111 112 113 114 115 116
static int
remoteSerializeDomainDiskErrors(virDomainDiskErrorPtr errors,
                                int nerrors,
                                remote_domain_disk_error **ret_errors_val,
                                u_int *ret_errors_len);

117 118
#include "remote_dispatch.h"
#include "qemu_dispatch.h"
119
#include "lxc_dispatch.h"
C
Chris Lalancette 已提交
120 121


122 123
/* Prototypes */
static void
124
remoteDispatchObjectEventSend(virNetServerClientPtr client,
125
                              virNetServerProgramPtr program,
126 127 128
                              int procnr,
                              xdrproc_t proc,
                              void *data);
129

130 131 132 133 134 135
static void
remoteEventCallbackFree(void *opaque)
{
    VIR_FREE(opaque);
}

136 137 138 139 140 141 142 143 144 145 146 147

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.  */
148
    memset(&def, 0, sizeof(def));
149 150 151 152 153 154 155 156 157
    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);

158
 cleanup:
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
    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);

185
 cleanup:
186 187 188 189 190 191
    ignore_value(virIdentitySetCurrent(NULL));
    virObjectUnref(identity);
    return ret;
}


192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
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);

212
 cleanup:
213 214 215 216 217 218
    ignore_value(virIdentitySetCurrent(NULL));
    virObjectUnref(identity);
    return ret;
}


219 220 221 222 223 224
static int
remoteRelayDomainEventLifecycle(virConnectPtr conn,
                                virDomainPtr dom,
                                int event,
                                int detail,
                                void *opaque)
225
{
226
    daemonClientEventCallbackPtr callback = opaque;
227
    remote_domain_event_lifecycle_msg data;
228

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

233 234
    VIR_DEBUG("Relaying domain lifecycle event %d %d, callback %d legacy %d",
              event, detail, callback->callbackID, callback->legacy);
235

236
    /* build return data */
237
    memset(&data, 0, sizeof(data));
238
    make_nonnull_domain(&data.dom, dom);
239 240
    data.event = event;
    data.detail = detail;
241

242 243 244 245 246 247 248 249 250 251 252 253 254 255
    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);
    }
256

257 258
    return 0;
}
259

260 261 262 263
static int
remoteRelayDomainEventReboot(virConnectPtr conn,
                             virDomainPtr dom,
                             void *opaque)
264
{
265
    daemonClientEventCallbackPtr callback = opaque;
266 267
    remote_domain_event_reboot_msg data;

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

272 273
    VIR_DEBUG("Relaying domain reboot event %s %d, callback %d legacy %d",
              dom->name, dom->id, callback->callbackID, callback->legacy);
274 275

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

279 280 281 282 283 284 285 286 287 288 289 290
    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);
    }
291 292 293 294

    return 0;
}

295

296 297 298 299 300
static int
remoteRelayDomainEventRTCChange(virConnectPtr conn,
                                virDomainPtr dom,
                                long long offset,
                                void *opaque)
301
{
302
    daemonClientEventCallbackPtr callback = opaque;
303 304
    remote_domain_event_rtc_change_msg data;

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

309 310 311
    VIR_DEBUG("Relaying domain rtc change event %s %d %lld, callback %d legacy %d",
              dom->name, dom->id, offset,
              callback->callbackID, callback->legacy);
312 313

    /* build return data */
314
    memset(&data, 0, sizeof(data));
315
    make_nonnull_domain(&data.dom, dom);
316 317
    data.offset = offset;

318 319 320 321 322 323 324 325 326 327 328 329
    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);
    }
330 331 332 333 334

    return 0;
}


335 336 337 338 339
static int
remoteRelayDomainEventWatchdog(virConnectPtr conn,
                               virDomainPtr dom,
                               int action,
                               void *opaque)
340
{
341
    daemonClientEventCallbackPtr callback = opaque;
342 343
    remote_domain_event_watchdog_msg data;

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

348 349
    VIR_DEBUG("Relaying domain watchdog event %s %d %d, callback %d",
              dom->name, dom->id, action, callback->callbackID);
350 351

    /* build return data */
352
    memset(&data, 0, sizeof(data));
353
    make_nonnull_domain(&data.dom, dom);
354 355
    data.action = action;

356 357 358 359 360 361 362 363 364 365 366 367
    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);
    }
368 369 370 371 372

    return 0;
}


373 374 375 376 377 378 379
static int
remoteRelayDomainEventIOError(virConnectPtr conn,
                              virDomainPtr dom,
                              const char *srcPath,
                              const char *devAlias,
                              int action,
                              void *opaque)
380
{
381
    daemonClientEventCallbackPtr callback = opaque;
382 383
    remote_domain_event_io_error_msg data;

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

388 389 390
    VIR_DEBUG("Relaying domain io error %s %d %s %s %d, callback %d",
              dom->name, dom->id, srcPath, devAlias, action,
              callback->callbackID);
391 392

    /* build return data */
393
    memset(&data, 0, sizeof(data));
394 395 396
    if (VIR_STRDUP(data.srcPath, srcPath) < 0 ||
        VIR_STRDUP(data.devAlias, devAlias) < 0)
        goto error;
397
    make_nonnull_domain(&data.dom, dom);
398 399
    data.action = action;

400 401 402 403 404 405 406 407 408 409 410 411
    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);
    }
412 413

    return 0;
414
 error:
E
Eric Blake 已提交
415 416
    VIR_FREE(data.srcPath);
    VIR_FREE(data.devAlias);
417
    return -1;
418 419 420
}


421 422 423 424 425 426 427 428
static int
remoteRelayDomainEventIOErrorReason(virConnectPtr conn,
                                    virDomainPtr dom,
                                    const char *srcPath,
                                    const char *devAlias,
                                    int action,
                                    const char *reason,
                                    void *opaque)
429
{
430
    daemonClientEventCallbackPtr callback = opaque;
431 432
    remote_domain_event_io_error_reason_msg data;

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

437 438 439
    VIR_DEBUG("Relaying domain io error %s %d %s %s %d %s, callback %d",
              dom->name, dom->id, srcPath, devAlias, action, reason,
              callback->callbackID);
440 441

    /* build return data */
442
    memset(&data, 0, sizeof(data));
443 444 445 446
    if (VIR_STRDUP(data.srcPath, srcPath) < 0 ||
        VIR_STRDUP(data.devAlias, devAlias) < 0 ||
        VIR_STRDUP(data.reason, reason) < 0)
        goto error;
447
    data.action = action;
448 449

    make_nonnull_domain(&data.dom, dom);
450

451 452 453 454 455 456 457 458 459 460 461 462
    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);
    }
463 464

    return 0;
465

466
 error:
E
Eric Blake 已提交
467 468 469
    VIR_FREE(data.srcPath);
    VIR_FREE(data.devAlias);
    VIR_FREE(data.reason);
470
    return -1;
471 472 473
}


474 475 476 477 478 479 480 481 482
static int
remoteRelayDomainEventGraphics(virConnectPtr conn,
                               virDomainPtr dom,
                               int phase,
                               virDomainEventGraphicsAddressPtr local,
                               virDomainEventGraphicsAddressPtr remote,
                               const char *authScheme,
                               virDomainEventGraphicsSubjectPtr subject,
                               void *opaque)
483
{
484
    daemonClientEventCallbackPtr callback = opaque;
485
    remote_domain_event_graphics_msg data;
486
    size_t i;
487

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

492 493
    VIR_DEBUG("Relaying domain graphics event %s %d %d - %d %s %s  - %d %s %s - %s, callback %d",
              dom->name, dom->id, phase,
494 495
              local->family, local->service, local->node,
              remote->family, remote->service, remote->node,
496
              authScheme, callback->callbackID);
497

498
    VIR_DEBUG("Subject %d", subject->nidentity);
499
    for (i = 0; i < subject->nidentity; i++)
500
        VIR_DEBUG("  %s=%s", subject->identities[i].type, subject->identities[i].name);
501 502

    /* build return data */
503
    memset(&data, 0, sizeof(data));
504 505 506
    data.phase = phase;
    data.local.family = local->family;
    data.remote.family = remote->family;
507 508 509 510 511 512
    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;
513 514

    data.subject.subject_len = subject->nidentity;
515
    if (VIR_ALLOC_N(data.subject.subject_val, data.subject.subject_len) < 0)
516
        goto error;
517

518
    for (i = 0; i < data.subject.subject_len; i++) {
519 520 521
        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;
522
    }
523
    make_nonnull_domain(&data.dom, dom);
524

525 526 527 528 529 530 531 532 533 534 535 536
    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);
    }
537 538

    return 0;
539

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

556 557 558 559 560 561 562
static int
remoteRelayDomainEventBlockJob(virConnectPtr conn,
                               virDomainPtr dom,
                               const char *path,
                               int type,
                               int status,
                               void *opaque)
563
{
564
    daemonClientEventCallbackPtr callback = opaque;
565 566
    remote_domain_event_block_job_msg data;

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

571 572
    VIR_DEBUG("Relaying domain block job event %s %d %s %i, %i, callback %d",
              dom->name, dom->id, path, type, status, callback->callbackID);
573 574

    /* build return data */
575
    memset(&data, 0, sizeof(data));
576 577
    if (VIR_STRDUP(data.path, path) < 0)
        goto error;
578 579
    data.type = type;
    data.status = status;
580
    make_nonnull_domain(&data.dom, dom);
581

582 583 584 585 586 587 588 589 590 591 592 593
    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);
    }
594 595

    return 0;
596
 error:
E
Eric Blake 已提交
597
    VIR_FREE(data.path);
598
    return -1;
599 600
}

601

602 603 604 605
static int
remoteRelayDomainEventControlError(virConnectPtr conn,
                                   virDomainPtr dom,
                                   void *opaque)
606
{
607
    daemonClientEventCallbackPtr callback = opaque;
608 609
    remote_domain_event_control_error_msg data;

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

614 615
    VIR_DEBUG("Relaying domain control error %s %d, callback %d",
              dom->name, dom->id, callback->callbackID);
616 617

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

621 622 623 624 625 626 627 628 629 630 631 632
    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);
    }
633 634 635 636 637

    return 0;
}


638 639 640 641 642 643 644 645
static int
remoteRelayDomainEventDiskChange(virConnectPtr conn,
                                 virDomainPtr dom,
                                 const char *oldSrcPath,
                                 const char *newSrcPath,
                                 const char *devAlias,
                                 int reason,
                                 void *opaque)
646
{
647
    daemonClientEventCallbackPtr callback = opaque;
648 649 650
    remote_domain_event_disk_change_msg data;
    char **oldSrcPath_p = NULL, **newSrcPath_p = NULL;

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

655 656 657
    VIR_DEBUG("Relaying domain %s %d disk change %s %s %s %d, callback %d",
              dom->name, dom->id, oldSrcPath, newSrcPath, devAlias, reason,
              callback->callbackID);
658 659

    /* build return data */
660
    memset(&data, 0, sizeof(data));
661 662
    if (oldSrcPath &&
        ((VIR_ALLOC(oldSrcPath_p) < 0) ||
663
         VIR_STRDUP(*oldSrcPath_p, oldSrcPath) < 0))
664
        goto error;
665 666 667

    if (newSrcPath &&
        ((VIR_ALLOC(newSrcPath_p) < 0) ||
668
         VIR_STRDUP(*newSrcPath_p, newSrcPath) < 0))
669
        goto error;
670 671 672

    data.oldSrcPath = oldSrcPath_p;
    data.newSrcPath = newSrcPath_p;
673 674
    if (VIR_STRDUP(data.devAlias, devAlias) < 0)
        goto error;
675 676 677 678
    data.reason = reason;

    make_nonnull_domain(&data.dom, dom);

679 680 681 682 683 684 685 686 687 688 689 690
    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);
    }
691 692 693

    return 0;

694
 error:
M
Michal Privoznik 已提交
695 696
    VIR_FREE(oldSrcPath_p);
    VIR_FREE(newSrcPath_p);
697 698 699 700
    return -1;
}


701 702 703 704 705 706 707
static int
remoteRelayDomainEventTrayChange(virConnectPtr conn,
                                 virDomainPtr dom,
                                 const char *devAlias,
                                 int reason,
                                 void *opaque)
{
708
    daemonClientEventCallbackPtr callback = opaque;
709 710
    remote_domain_event_tray_change_msg data;

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

715 716
    VIR_DEBUG("Relaying domain %s %d tray change devAlias: %s reason: %d, callback %d",
              dom->name, dom->id, devAlias, reason, callback->callbackID);
717 718

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

721
    if (VIR_STRDUP(data.devAlias, devAlias) < 0)
722 723 724 725 726
        return -1;
    data.reason = reason;

    make_nonnull_domain(&data.dom, dom);

727 728 729 730 731 732 733 734 735 736 737 738
    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);
    }
739 740 741 742

    return 0;
}

743 744 745
static int
remoteRelayDomainEventPMWakeup(virConnectPtr conn,
                               virDomainPtr dom,
E
Eric Blake 已提交
746
                               int reason,
747 748
                               void *opaque)
{
749
    daemonClientEventCallbackPtr callback = opaque;
O
Osier Yang 已提交
750 751
    remote_domain_event_pmwakeup_msg data;

752 753
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
O
Osier Yang 已提交
754 755
        return -1;

756 757
    VIR_DEBUG("Relaying domain %s %d system pmwakeup, callback %d",
              dom->name, dom->id, callback->callbackID);
O
Osier Yang 已提交
758 759

    /* build return data */
760
    memset(&data, 0, sizeof(data));
O
Osier Yang 已提交
761 762
    make_nonnull_domain(&data.dom, dom);

763 764 765 766 767 768
    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 已提交
769
                                                          reason, data };
770 771 772 773 774

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMWAKEUP,
                                      (xdrproc_t)xdr_remote_domain_event_callback_pmwakeup_msg, &msg);
    }
O
Osier Yang 已提交
775 776 777 778

    return 0;
}

779 780 781
static int
remoteRelayDomainEventPMSuspend(virConnectPtr conn,
                                virDomainPtr dom,
E
Eric Blake 已提交
782
                                int reason,
783 784
                                void *opaque)
{
785
    daemonClientEventCallbackPtr callback = opaque;
O
Osier Yang 已提交
786 787
    remote_domain_event_pmsuspend_msg data;

788 789
    if (callback->callbackID < 0 ||
        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
O
Osier Yang 已提交
790 791
        return -1;

792 793
    VIR_DEBUG("Relaying domain %s %d system pmsuspend, callback %d",
              dom->name, dom->id, callback->callbackID);
O
Osier Yang 已提交
794 795

    /* build return data */
796
    memset(&data, 0, sizeof(data));
O
Osier Yang 已提交
797 798
    make_nonnull_domain(&data.dom, dom);

799 800 801 802 803 804
    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 已提交
805
                                                           reason, data };
806 807 808 809 810

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMSUSPEND,
                                      (xdrproc_t)xdr_remote_domain_event_callback_pmsuspend_msg, &msg);
    }
O
Osier Yang 已提交
811 812 813 814

    return 0;
}

815
static int
816
remoteRelayDomainEventBalloonChange(virConnectPtr conn,
817 818 819 820
                                    virDomainPtr dom,
                                    unsigned long long actual,
                                    void *opaque)
{
821
    daemonClientEventCallbackPtr callback = opaque;
822 823
    remote_domain_event_balloon_change_msg data;

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

828 829
    VIR_DEBUG("Relaying domain balloon change event %s %d %lld, callback %d",
              dom->name, dom->id, actual, callback->callbackID);
830 831 832 833 834 835

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

836 837 838 839 840 841 842 843 844 845 846 847
    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);
    }
848 849 850 851 852

    return 0;
}


853 854 855
static int
remoteRelayDomainEventPMSuspendDisk(virConnectPtr conn,
                                    virDomainPtr dom,
E
Eric Blake 已提交
856
                                    int reason,
857 858
                                    void *opaque)
{
859
    daemonClientEventCallbackPtr callback = opaque;
860 861
    remote_domain_event_pmsuspend_disk_msg data;

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

866 867
    VIR_DEBUG("Relaying domain %s %d system pmsuspend-disk, callback %d",
              dom->name, dom->id, callback->callbackID);
868 869 870 871 872

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

873 874 875 876 877 878
    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 已提交
879
                                                                reason, data };
880 881 882 883 884

        remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                      REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMSUSPEND_DISK,
                                      (xdrproc_t)xdr_remote_domain_event_callback_pmsuspend_disk_msg, &msg);
    }
885 886 887 888

    return 0;
}

889
static int
890
remoteRelayDomainEventDeviceRemoved(virConnectPtr conn,
891 892 893 894
                                    virDomainPtr dom,
                                    const char *devAlias,
                                    void *opaque)
{
895
    daemonClientEventCallbackPtr callback = opaque;
896 897
    remote_domain_event_device_removed_msg data;

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

902 903
    VIR_DEBUG("Relaying domain device removed event %s %d %s, callback %d",
              dom->name, dom->id, devAlias, callback->callbackID);
904 905 906 907 908 909 910 911 912

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

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

    make_nonnull_domain(&data.dom, dom);

913 914 915 916 917 918 919 920 921 922 923 924 925 926
    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);
    }
927 928 929 930

    return 0;
}

931

932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
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;
}


970 971 972 973 974 975 976 977 978 979 980 981 982 983
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;

984 985
    VIR_DEBUG("Relaying domain tunable event %s %d, callback %d, params %p %d",
              dom->name, dom->id, callback->callbackID, params, nparams);
986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006

    /* 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;
}


1007 1008 1009 1010 1011 1012 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
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;
}


1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
static int
remoteRelayDomainEventDeviceAdded(virConnectPtr conn,
                                  virDomainPtr dom,
                                  const char *devAlias,
                                  void *opaque)
{
    daemonClientEventCallbackPtr callback = opaque;
    remote_domain_event_callback_device_added_msg data;

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

    VIR_DEBUG("Relaying domain device added event %s %d %s, callback %d",
              dom->name, dom->id, devAlias, callback->callbackID);

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

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

    make_nonnull_domain(&data.dom, dom);
E
Eric Blake 已提交
1065
    data.callbackID = callback->callbackID;
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075

    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                  REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_ADDED,
                                  (xdrproc_t)xdr_remote_domain_event_callback_device_added_msg,
                                  &data);

    return 0;
}


1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
static int
remoteRelayDomainEventMigrationIteration(virConnectPtr conn,
                                         virDomainPtr dom,
                                         int iteration,
                                         void *opaque)
{
    daemonClientEventCallbackPtr callback = opaque;
    remote_domain_event_callback_migration_iteration_msg data;

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

    VIR_DEBUG("Relaying domain migration pass event %s %d, "
              "callback %d, iteration %d",
              dom->name, dom->id, callback->callbackID, iteration);

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

    data.iteration = iteration;

    remoteDispatchObjectEventSend(callback->client, remoteProgram,
                                  REMOTE_PROC_DOMAIN_EVENT_CALLBACK_MIGRATION_ITERATION,
                                  (xdrproc_t)xdr_remote_domain_event_callback_migration_iteration_msg,
                                  &data);

    return 0;
}
1107 1108


1109
static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
1110
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
1111
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot),
1112
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventRTCChange),
1113
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventWatchdog),
1114
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOError),
1115
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventGraphics),
1116
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOErrorReason),
1117
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventControlError),
1118
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob),
1119
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDiskChange),
1120
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventTrayChange),
O
Osier Yang 已提交
1121
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMWakeup),
O
Osier Yang 已提交
1122
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspend),
1123
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBalloonChange),
1124
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspendDisk),
1125
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemoved),
1126
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob2),
1127
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventTunable),
1128
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventAgentLifecycle),
1129
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceAdded),
1130
    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMigrationIteration),
1131 1132 1133 1134
};

verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);

1135
static int
1136
remoteRelayNetworkEventLifecycle(virConnectPtr conn,
1137 1138 1139 1140
                                 virNetworkPtr net,
                                 int event,
                                 int detail,
                                 void *opaque)
1141
{
1142
    daemonClientEventCallbackPtr callback = opaque;
1143 1144
    remote_network_event_lifecycle_msg data;

1145 1146
    if (callback->callbackID < 0 ||
        !remoteRelayNetworkEventCheckACL(callback->client, conn, net))
1147 1148
        return -1;

1149 1150
    VIR_DEBUG("Relaying network lifecycle event %d, detail %d, callback %d",
              event, detail, callback->callbackID);
1151 1152 1153 1154

    /* build return data */
    memset(&data, 0, sizeof(data));
    make_nonnull_network(&data.net, net);
1155
    data.callbackID = callback->callbackID;
1156 1157 1158
    data.event = event;
    data.detail = detail;

1159
    remoteDispatchObjectEventSend(callback->client, remoteProgram,
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171
                                  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);

1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212
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;

1213
 error:
1214 1215 1216 1217
    VIR_FREE(data.event);
    VIR_FREE(details_p);
}

1218 1219 1220 1221 1222 1223 1224
/*
 * 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
 */
1225
void remoteClientFreeFunc(void *data)
1226 1227 1228 1229 1230
{
    struct daemonClientPrivate *priv = data;

    /* Deregister event delivery callback */
    if (priv->conn) {
1231
        virIdentityPtr sysident = virIdentityGetSystem();
1232
        size_t i;
1233

1234 1235
        virIdentitySetCurrent(sysident);

1236 1237 1238 1239 1240
        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;
1241
            }
1242 1243 1244 1245 1246
            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");
1247
        }
1248
        VIR_FREE(priv->domainEventCallbacks);
1249

1250 1251 1252 1253 1254
        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;
1255
            }
1256 1257 1258 1259 1260 1261
            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");
1262
        }
1263
        VIR_FREE(priv->networkEventCallbacks);
1264

1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279
        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);

1280
        virConnectClose(priv->conn);
1281 1282 1283

        virIdentitySetCurrent(NULL);
        virObjectUnref(sysident);
1284 1285 1286 1287 1288 1289
    }

    VIR_FREE(priv);
}


1290 1291 1292 1293 1294 1295 1296
static void remoteClientCloseFunc(virNetServerClientPtr client)
{
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);

    daemonRemoveAllClientStreams(priv->streams);
}

1297

1298 1299
void *remoteClientInitHook(virNetServerClientPtr client,
                           void *opaque ATTRIBUTE_UNUSED)
1300 1301 1302
{
    struct daemonClientPrivate *priv;

1303
    if (VIR_ALLOC(priv) < 0)
1304
        return NULL;
1305 1306 1307

    if (virMutexInit(&priv->lock) < 0) {
        VIR_FREE(priv);
1308
        virReportSystemError(errno, "%s", _("unable to init mutex"));
1309
        return NULL;
1310 1311
    }

1312
    virNetServerClientSetCloseHook(client, remoteClientCloseFunc);
1313
    return priv;
1314 1315
}

1316 1317 1318
/*----- Functions. -----*/

static int
1319
remoteDispatchConnectOpen(virNetServerPtr server ATTRIBUTE_UNUSED,
1320 1321 1322 1323
                          virNetServerClientPtr client,
                          virNetMessagePtr msg ATTRIBUTE_UNUSED,
                          virNetMessageErrorPtr rerr,
                          struct remote_connect_open_args *args)
1324 1325
{
    const char *name;
1326
    unsigned int flags;
1327
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
1328
    int rv = -1;
1329

1330 1331 1332 1333
    VIR_DEBUG("priv=%p conn=%p", priv, priv->conn);
    virMutexLock(&priv->lock);
    /* Already opened? */
    if (priv->conn) {
1334
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection already open"));
1335 1336 1337
        goto cleanup;
    }

1338 1339 1340 1341 1342 1343
    name = args->name ? *args->name : NULL;

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

1347
    priv->conn =
1348
        flags & VIR_CONNECT_RO
1349 1350
        ? virConnectOpenReadOnly(name)
        : virConnectOpen(name);
1351

1352
    if (priv->conn == NULL)
1353 1354 1355
        goto cleanup;

    rv = 0;
1356

1357
 cleanup:
1358
    if (rv < 0)
1359 1360
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
1361
    return rv;
1362 1363 1364 1365
}


static int
1366 1367 1368 1369
remoteDispatchConnectClose(virNetServerPtr server ATTRIBUTE_UNUSED,
                           virNetServerClientPtr client ATTRIBUTE_UNUSED,
                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
                           virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED)
1370
{
1371
    virNetServerClientDelayedClose(client);
1372
    return 0;
1373 1374
}

1375

1376
static int
1377 1378
remoteDispatchDomainGetSchedulerType(virNetServerPtr server ATTRIBUTE_UNUSED,
                                     virNetServerClientPtr client ATTRIBUTE_UNUSED,
1379
                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
1380
                                     virNetMessageErrorPtr rerr,
1381 1382
                                     remote_domain_get_scheduler_type_args *args,
                                     remote_domain_get_scheduler_type_ret *ret)
1383
{
1384
    virDomainPtr dom = NULL;
1385 1386
    char *type;
    int nparams;
1387
    int rv = -1;
1388 1389
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
1390

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

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

1399
    if (!(type = virDomainGetSchedulerType(dom, &nparams)))
1400
        goto cleanup;
1401 1402 1403

    ret->type = type;
    ret->nparams = nparams;
1404 1405
    rv = 0;

1406
 cleanup:
1407
    if (rv < 0)
1408
        virNetMessageSaveError(rerr);
1409
    virObjectUnref(dom);
1410
    return rv;
1411 1412
}

1413 1414
/* Helper to serialize typed parameters. This also filters out any string
 * parameters that must not be returned to older clients.  */
1415 1416 1417
static int
remoteSerializeTypedParameters(virTypedParameterPtr params,
                               int nparams,
1418
                               remote_typed_param **ret_params_val,
1419 1420
                               u_int *ret_params_len,
                               unsigned int flags)
1421
{
1422 1423
    size_t i;
    size_t j;
1424 1425 1426 1427
    int rv = -1;
    remote_typed_param *val;

    *ret_params_len = nparams;
1428
    if (VIR_ALLOC_N(val, nparams) < 0)
1429 1430
        goto cleanup;

1431
    for (i = 0, j = 0; i < nparams; ++i) {
1432 1433 1434 1435 1436
        /* 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)) {
1437 1438 1439 1440
            --*ret_params_len;
            continue;
        }

1441
        /* remoteDispatchClientRequest will free this: */
1442
        if (VIR_STRDUP(val[j].field, params[i].field) < 0)
1443
            goto cleanup;
1444
        val[j].value.type = params[i].type;
1445
        switch (params[i].type) {
1446
        case VIR_TYPED_PARAM_INT:
1447
            val[j].value.remote_typed_param_value_u.i = params[i].value.i;
1448 1449
            break;
        case VIR_TYPED_PARAM_UINT:
1450
            val[j].value.remote_typed_param_value_u.ui = params[i].value.ui;
1451 1452
            break;
        case VIR_TYPED_PARAM_LLONG:
1453
            val[j].value.remote_typed_param_value_u.l = params[i].value.l;
1454 1455
            break;
        case VIR_TYPED_PARAM_ULLONG:
1456
            val[j].value.remote_typed_param_value_u.ul = params[i].value.ul;
1457 1458
            break;
        case VIR_TYPED_PARAM_DOUBLE:
1459
            val[j].value.remote_typed_param_value_u.d = params[i].value.d;
1460 1461
            break;
        case VIR_TYPED_PARAM_BOOLEAN:
1462 1463 1464
            val[j].value.remote_typed_param_value_u.b = params[i].value.b;
            break;
        case VIR_TYPED_PARAM_STRING:
1465
            if (VIR_STRDUP(val[j].value.remote_typed_param_value_u.s, params[i].value.s) < 0)
1466
                goto cleanup;
1467 1468
            break;
        default:
1469 1470
            virReportError(VIR_ERR_RPC, _("unknown parameter type: %d"),
                           params[i].type);
1471 1472
            goto cleanup;
        }
1473
        j++;
1474 1475 1476 1477 1478 1479
    }

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

1480
 cleanup:
1481
    if (val) {
1482
        for (i = 0; i < nparams; i++) {
1483
            VIR_FREE(val[i].field);
1484
            if (val[i].value.type == VIR_TYPED_PARAM_STRING)
1485 1486
                VIR_FREE(val[i].value.remote_typed_param_value_u.s);
        }
1487 1488 1489 1490 1491
        VIR_FREE(val);
    }
    return rv;
}

1492
static int
1493 1494
remoteDispatchDomainGetSchedulerParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
                                           virNetServerClientPtr client ATTRIBUTE_UNUSED,
1495
                                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
1496
                                           virNetMessageErrorPtr rerr,
1497 1498
                                           remote_domain_get_scheduler_parameters_args *args,
                                           remote_domain_get_scheduler_parameters_ret *ret)
1499
{
1500
    virDomainPtr dom = NULL;
1501
    virTypedParameterPtr params = NULL;
1502
    int nparams = 0;
1503
    int rv = -1;
1504 1505
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
1506

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

1512
    if (args->nparams > REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX) {
1513
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
1514
        goto cleanup;
1515
    }
1516
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
1517
        goto cleanup;
1518
    nparams = args->nparams;
1519

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

1523
    if (virDomainGetSchedulerParameters(dom, params, &nparams) < 0)
1524
        goto cleanup;
1525

1526
    if (remoteSerializeTypedParameters(params, nparams,
1527
                                       &ret->params.params_val,
1528 1529
                                       &ret->params.params_len,
                                       0) < 0)
1530 1531 1532 1533
        goto cleanup;

    rv = 0;

1534
 cleanup:
1535
    if (rv < 0)
1536
        virNetMessageSaveError(rerr);
1537
    virTypedParamsFree(params, nparams);
1538
    virObjectUnref(dom);
1539 1540 1541
    return rv;
}

1542 1543 1544 1545 1546 1547 1548 1549 1550 1551
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;
1552
    size_t i;
1553 1554 1555 1556
    int rv = -1;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
1557
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
1558 1559 1560 1561 1562 1563 1564 1565
        goto cleanup;
    }

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

1566 1567 1568 1569 1570 1571 1572
    if (ndomains > REMOTE_DOMAIN_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many domains '%d' for limit '%d'"),
                       ndomains, REMOTE_DOMAIN_LIST_MAX);
        goto cleanup;
    }

1573
    if (doms && ndomains) {
1574
        if (VIR_ALLOC_N(ret->domains.domains_val, ndomains) < 0)
1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589
            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;

1590
 cleanup:
1591 1592
    if (rv < 0)
        virNetMessageSaveError(rerr);
1593
    if (doms && ndomains > 0)
1594
        for (i = 0; i < ndomains; i++)
1595
            virObjectUnref(doms[i]);
1596
    VIR_FREE(doms);
1597 1598 1599
    return rv;
}

1600
static int
1601 1602
remoteDispatchDomainGetSchedulerParametersFlags(virNetServerPtr server ATTRIBUTE_UNUSED,
                                                virNetServerClientPtr client ATTRIBUTE_UNUSED,
1603
                                                virNetMessagePtr msg ATTRIBUTE_UNUSED,
1604
                                                virNetMessageErrorPtr rerr,
1605 1606 1607 1608 1609
                                                remote_domain_get_scheduler_parameters_flags_args *args,
                                                remote_domain_get_scheduler_parameters_flags_ret *ret)
{
    virDomainPtr dom = NULL;
    virTypedParameterPtr params = NULL;
1610
    int nparams = 0;
1611
    int rv = -1;
1612 1613
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
1614

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

1620
    if (args->nparams > REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX) {
1621
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
1622 1623
        goto cleanup;
    }
1624
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
1625
        goto cleanup;
1626
    nparams = args->nparams;
1627

1628
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
1629 1630 1631 1632 1633 1634 1635
        goto cleanup;

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

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

1641
    rv = 0;
1642

1643
 cleanup:
1644
    if (rv < 0)
1645
        virNetMessageSaveError(rerr);
1646
    virTypedParamsFree(params, nparams);
1647
    virObjectUnref(dom);
1648
    return rv;
1649 1650
}

1651
static int
1652 1653
remoteDispatchDomainMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED,
                                virNetServerClientPtr client ATTRIBUTE_UNUSED,
1654
                                virNetMessagePtr msg ATTRIBUTE_UNUSED,
1655
                                virNetMessageErrorPtr rerr,
1656 1657
                                remote_domain_memory_stats_args *args,
                                remote_domain_memory_stats_ret *ret)
1658
{
1659
    virDomainPtr dom = NULL;
1660
    virDomainMemoryStatPtr stats = NULL;
1661 1662
    int nr_stats;
    size_t i;
1663
    int rv = -1;
1664 1665
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
1666

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

1672
    if (args->maxStats > REMOTE_DOMAIN_MEMORY_STATS_MAX) {
1673 1674
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("maxStats > REMOTE_DOMAIN_MEMORY_STATS_MAX"));
1675
        goto cleanup;
1676 1677
    }

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

    /* Allocate stats array for making dispatch call */
1682
    if (VIR_ALLOC_N(stats, args->maxStats) < 0)
1683
        goto cleanup;
1684

1685
    nr_stats = virDomainMemoryStats(dom, stats, args->maxStats, args->flags);
1686
    if (nr_stats < 0)
1687
        goto cleanup;
1688 1689

    /* Allocate return buffer */
1690
    if (VIR_ALLOC_N(ret->stats.stats_val, args->maxStats) < 0)
1691
        goto cleanup;
1692 1693 1694 1695 1696 1697 1698

    /* 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;
1699 1700
    rv = 0;

1701
 cleanup:
1702
    if (rv < 0)
1703
        virNetMessageSaveError(rerr);
1704
    virObjectUnref(dom);
1705
    VIR_FREE(stats);
1706
    return rv;
1707 1708
}

1709
static int
1710 1711
remoteDispatchDomainBlockPeek(virNetServerPtr server ATTRIBUTE_UNUSED,
                              virNetServerClientPtr client ATTRIBUTE_UNUSED,
1712
                              virNetMessagePtr msg ATTRIBUTE_UNUSED,
1713
                              virNetMessageErrorPtr rerr,
1714 1715
                              remote_domain_block_peek_args *args,
                              remote_domain_block_peek_ret *ret)
1716
{
1717
    virDomainPtr dom = NULL;
1718 1719 1720 1721
    char *path;
    unsigned long long offset;
    size_t size;
    unsigned int flags;
1722
    int rv = -1;
1723 1724
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
1725

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

1731
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
1732
        goto cleanup;
1733 1734 1735 1736 1737 1738
    path = args->path;
    offset = args->offset;
    size = args->size;
    flags = args->flags;

    if (size > REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX) {
1739 1740
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("size > maximum buffer size"));
1741
        goto cleanup;
1742 1743 1744
    }

    ret->buffer.buffer_len = size;
1745
    if (VIR_ALLOC_N(ret->buffer.buffer_val, size) < 0)
1746
        goto cleanup;
1747

1748
    if (virDomainBlockPeek(dom, path, offset, size,
1749
                           ret->buffer.buffer_val, flags) < 0)
1750
        goto cleanup;
1751

1752 1753
    rv = 0;

1754
 cleanup:
1755
    if (rv < 0) {
1756
        virNetMessageSaveError(rerr);
1757 1758
        VIR_FREE(ret->buffer.buffer_val);
    }
1759
    virObjectUnref(dom);
1760
    return rv;
1761 1762
}

1763 1764 1765
static int
remoteDispatchDomainBlockStatsFlags(virNetServerPtr server ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
1766
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
1767 1768 1769 1770 1771 1772 1773
                                    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;
1774
    int nparams = 0;
1775 1776 1777 1778 1779 1780
    unsigned int flags;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
1781
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
1782 1783 1784 1785 1786 1787 1788
        goto cleanup;
    }

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

1789
    if (args->nparams > REMOTE_DOMAIN_BLOCK_STATS_PARAMETERS_MAX) {
1790
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
1791 1792
        goto cleanup;
    }
1793
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
1794
        goto cleanup;
1795
    nparams = args->nparams;
1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810

    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,
1811 1812
                                       &ret->params.params_len,
                                       args->flags) < 0)
1813 1814
        goto cleanup;

1815
 success:
1816 1817
    rv = 0;

1818
 cleanup:
1819
    if (rv < 0)
1820
        virNetMessageSaveError(rerr);
1821
    virTypedParamsFree(params, nparams);
1822
    virObjectUnref(dom);
1823 1824 1825
    return rv;
}

R
Richard W.M. Jones 已提交
1826
static int
1827 1828
remoteDispatchDomainMemoryPeek(virNetServerPtr server ATTRIBUTE_UNUSED,
                               virNetServerClientPtr client ATTRIBUTE_UNUSED,
1829
                               virNetMessagePtr msg ATTRIBUTE_UNUSED,
1830
                               virNetMessageErrorPtr rerr,
1831 1832
                               remote_domain_memory_peek_args *args,
                               remote_domain_memory_peek_ret *ret)
R
Richard W.M. Jones 已提交
1833
{
1834
    virDomainPtr dom = NULL;
R
Richard W.M. Jones 已提交
1835 1836 1837
    unsigned long long offset;
    size_t size;
    unsigned int flags;
1838
    int rv = -1;
1839 1840
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
R
Richard W.M. Jones 已提交
1841

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

1847
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
1848
        goto cleanup;
R
Richard W.M. Jones 已提交
1849 1850 1851 1852 1853
    offset = args->offset;
    size = args->size;
    flags = args->flags;

    if (size > REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX) {
1854 1855
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("size > maximum buffer size"));
1856
        goto cleanup;
R
Richard W.M. Jones 已提交
1857 1858 1859
    }

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

1863
    if (virDomainMemoryPeek(dom, offset, size,
1864
                            ret->buffer.buffer_val, flags) < 0)
1865
        goto cleanup;
R
Richard W.M. Jones 已提交
1866

1867 1868
    rv = 0;

1869
 cleanup:
1870
    if (rv < 0) {
1871
        virNetMessageSaveError(rerr);
1872 1873
        VIR_FREE(ret->buffer.buffer_val);
    }
1874
    virObjectUnref(dom);
1875
    return rv;
R
Richard W.M. Jones 已提交
1876 1877
}

1878
static int
1879 1880
remoteDispatchDomainGetSecurityLabel(virNetServerPtr server ATTRIBUTE_UNUSED,
                                     virNetServerClientPtr client ATTRIBUTE_UNUSED,
1881
                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
1882
                                     virNetMessageErrorPtr rerr,
1883 1884
                                     remote_domain_get_security_label_args *args,
                                     remote_domain_get_security_label_ret *ret)
1885
{
1886 1887
    virDomainPtr dom = NULL;
    virSecurityLabelPtr seclabel = NULL;
1888
    int rv = -1;
1889 1890
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
1891

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

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

1900
    if (VIR_ALLOC(seclabel) < 0)
1901 1902 1903 1904 1905 1906
        goto cleanup;

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

    ret->label.label_len = strlen(seclabel->label) + 1;
1907
    if (VIR_ALLOC_N(ret->label.label_val, ret->label.label_len) < 0)
1908
        goto cleanup;
1909 1910
    strcpy(ret->label.label_val, seclabel->label);
    ret->enforcing = seclabel->enforcing;
1911

1912 1913
    rv = 0;

1914
 cleanup:
1915
    if (rv < 0)
1916
        virNetMessageSaveError(rerr);
1917
    virObjectUnref(dom);
1918
    VIR_FREE(seclabel);
1919
    return rv;
1920 1921
}

M
Marcelo Cerri 已提交
1922 1923 1924 1925 1926 1927 1928 1929 1930 1931
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;
1932 1933
    int len, rv = -1;
    size_t i;
M
Marcelo Cerri 已提交
1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951
    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;
    }

1952
    if (VIR_ALLOC_N(ret->labels.labels_val, len) < 0)
M
Marcelo Cerri 已提交
1953 1954 1955 1956 1957
        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];
1958
        if (VIR_ALLOC_N(cur->label.label_val, label_len) < 0)
M
Marcelo Cerri 已提交
1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969
            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;

1970
 done:
M
Marcelo Cerri 已提交
1971 1972
    rv = 0;

1973
 cleanup:
M
Marcelo Cerri 已提交
1974 1975
    if (rv < 0)
        virNetMessageSaveError(rerr);
1976
    virObjectUnref(dom);
M
Marcelo Cerri 已提交
1977 1978 1979 1980
    VIR_FREE(seclabels);
    return rv;
}

1981
static int
1982 1983
remoteDispatchNodeGetSecurityModel(virNetServerPtr server ATTRIBUTE_UNUSED,
                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
1984
                                   virNetMessagePtr msg ATTRIBUTE_UNUSED,
1985
                                   virNetMessageErrorPtr rerr,
1986
                                   remote_node_get_security_model_ret *ret)
1987
{
1988
    virSecurityModel secmodel;
1989
    int rv = -1;
1990 1991
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
1992

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

1998
    memset(&secmodel, 0, sizeof(secmodel));
1999
    if (virNodeGetSecurityModel(priv->conn, &secmodel) < 0)
2000 2001 2002
        goto cleanup;

    ret->model.model_len = strlen(secmodel.model) + 1;
2003
    if (VIR_ALLOC_N(ret->model.model_val, ret->model.model_len) < 0)
2004 2005 2006 2007
        goto cleanup;
    strcpy(ret->model.model_val, secmodel.model);

    ret->doi.doi_len = strlen(secmodel.doi) + 1;
2008
    if (VIR_ALLOC_N(ret->doi.doi_val, ret->doi.doi_len) < 0)
2009
        goto cleanup;
2010
    strcpy(ret->doi.doi_val, secmodel.doi);
2011

2012 2013
    rv = 0;

2014
 cleanup:
2015
    if (rv < 0)
2016
        virNetMessageSaveError(rerr);
2017
    return rv;
2018 2019
}

2020
static int
2021 2022
remoteDispatchDomainGetVcpuPinInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
2023
                                   virNetMessagePtr msg ATTRIBUTE_UNUSED,
2024
                                   virNetMessageErrorPtr rerr,
E
Eric Blake 已提交
2025 2026
                                   remote_domain_get_vcpu_pin_info_args *args,
                                   remote_domain_get_vcpu_pin_info_ret *ret)
2027 2028 2029 2030 2031
{
    virDomainPtr dom = NULL;
    unsigned char *cpumaps = NULL;
    int num;
    int rv = -1;
2032 2033
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2034

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

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

    if (args->ncpumaps > REMOTE_VCPUINFO_MAX) {
2044
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("ncpumaps > REMOTE_VCPUINFO_MAX"));
2045 2046 2047 2048 2049
        goto cleanup;
    }

    if (INT_MULTIPLY_OVERFLOW(args->ncpumaps, args->maplen) ||
        args->ncpumaps * args->maplen > REMOTE_CPUMAPS_MAX) {
2050
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo * maplen > REMOTE_CPUMAPS_MAX"));
2051 2052 2053 2054 2055 2056
        goto cleanup;
    }

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

E
Eric Blake 已提交
2059
    if ((num = virDomainGetVcpuPinInfo(dom,
2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072
                                       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;
2073 2074 2075 2076
    cpumaps = NULL;

    rv = 0;

2077
 cleanup:
2078 2079 2080
    if (rv < 0)
        virNetMessageSaveError(rerr);
    VIR_FREE(cpumaps);
2081
    virObjectUnref(dom);
2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112
    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;

2113
 cleanup:
2114 2115
    if (rv < 0)
        virNetMessageSaveError(rerr);
2116
    virObjectUnref(dom);
2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146
    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)
2147
        goto cleanup;
2148 2149 2150 2151 2152 2153 2154 2155 2156 2157

    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;
2158 2159 2160 2161
    cpumaps = NULL;

    rv = 0;

2162
 cleanup:
2163
    if (rv < 0)
2164
        virNetMessageSaveError(rerr);
2165
    VIR_FREE(cpumaps);
2166
    virObjectUnref(dom);
2167 2168 2169
    return rv;
}

2170
static int
2171 2172
remoteDispatchDomainGetVcpus(virNetServerPtr server ATTRIBUTE_UNUSED,
                             virNetServerClientPtr client ATTRIBUTE_UNUSED,
2173
                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
2174
                             virNetMessageErrorPtr rerr,
2175 2176
                             remote_domain_get_vcpus_args *args,
                             remote_domain_get_vcpus_ret *ret)
2177
{
2178
    virDomainPtr dom = NULL;
2179 2180
    virVcpuInfoPtr info = NULL;
    unsigned char *cpumaps = NULL;
2181 2182
    int info_len;
    size_t i;
2183
    int rv = -1;
2184 2185
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2186

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

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

2195
    if (args->maxinfo > REMOTE_VCPUINFO_MAX) {
2196
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo > REMOTE_VCPUINFO_MAX"));
2197
        goto cleanup;
2198
    }
2199

2200 2201
    if (INT_MULTIPLY_OVERFLOW(args->maxinfo, args->maplen) ||
        args->maxinfo * args->maplen > REMOTE_CPUMAPS_MAX) {
2202
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo * maplen > REMOTE_CPUMAPS_MAX"));
2203 2204 2205 2206 2207
        goto cleanup;
    }

    /* Allocate buffers to take the results. */
    if (VIR_ALLOC_N(info, args->maxinfo) < 0)
2208
        goto cleanup;
2209 2210
    if (args->maplen > 0 &&
        VIR_ALLOC_N(cpumaps, args->maxinfo * args->maplen) < 0)
2211
        goto cleanup;
2212 2213 2214 2215 2216 2217 2218 2219 2220

    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)
2221
        goto cleanup;
2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238

    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;
2239

2240
 cleanup:
2241
    if (rv < 0) {
2242
        virNetMessageSaveError(rerr);
2243 2244 2245 2246
        VIR_FREE(ret->info.info_val);
    }
    VIR_FREE(cpumaps);
    VIR_FREE(info);
2247
    virObjectUnref(dom);
2248
    return rv;
2249 2250
}

2251
static int
2252 2253 2254 2255 2256 2257
remoteDispatchDomainGetIOThreadInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client,
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                    virNetMessageErrorPtr rerr,
                                    remote_domain_get_iothread_info_args *args,
                                    remote_domain_get_iothread_info_ret *ret)
2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274
{
    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;

2275
    if ((ninfo = virDomainGetIOThreadInfo(dom, &info, args->flags)) < 0)
2276 2277
        goto cleanup;

2278
    if (ninfo > REMOTE_IOTHREAD_INFO_MAX) {
2279 2280
        virReportError(VIR_ERR_RPC,
                       _("Too many IOThreads in info: %d for limit %d"),
2281
                       ninfo, REMOTE_IOTHREAD_INFO_MAX);
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
        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++)
2317
            virDomainIOThreadInfoFree(info[i]);
2318 2319 2320 2321 2322
    VIR_FREE(info);

    return rv;
}

2323
static int
2324 2325
remoteDispatchDomainMigratePrepare(virNetServerPtr server ATTRIBUTE_UNUSED,
                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
2326
                                   virNetMessagePtr msg ATTRIBUTE_UNUSED,
2327
                                   virNetMessageErrorPtr rerr,
2328 2329
                                   remote_domain_migrate_prepare_args *args,
                                   remote_domain_migrate_prepare_ret *ret)
2330
{
2331 2332 2333 2334 2335
    char *cookie = NULL;
    int cookielen = 0;
    char *uri_in;
    char **uri_out;
    char *dname;
2336
    int rv = -1;
2337 2338
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2339

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

2345 2346 2347 2348
    uri_in = args->uri_in == NULL ? NULL : *args->uri_in;
    dname = args->dname == NULL ? NULL : *args->dname;

    /* Wacky world of XDR ... */
2349
    if (VIR_ALLOC(uri_out) < 0)
2350
        goto cleanup;
2351

2352
    if (virDomainMigratePrepare(priv->conn, &cookie, &cookielen,
2353 2354
                                uri_in, uri_out,
                                args->flags, dname, args->resource) < 0)
2355
        goto cleanup;
2356

2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367
    /* 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;
    }
2368

2369
    rv = 0;
2370

2371
 cleanup:
2372
    if (rv < 0)
2373
        virNetMessageSaveError(rerr);
2374
    VIR_FREE(uri_out);
2375
    return rv;
2376 2377
}

2378
static int
2379 2380
remoteDispatchDomainMigratePrepare2(virNetServerPtr server ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
2381
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
2382
                                    virNetMessageErrorPtr rerr,
2383 2384
                                    remote_domain_migrate_prepare2_args *args,
                                    remote_domain_migrate_prepare2_ret *ret)
2385
{
2386 2387 2388 2389 2390
    char *cookie = NULL;
    int cookielen = 0;
    char *uri_in;
    char **uri_out;
    char *dname;
2391
    int rv = -1;
2392 2393
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2394

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

2400 2401
    uri_in = args->uri_in == NULL ? NULL : *args->uri_in;
    dname = args->dname == NULL ? NULL : *args->dname;
2402

2403
    /* Wacky world of XDR ... */
2404
    if (VIR_ALLOC(uri_out) < 0)
2405
        goto cleanup;
2406

2407
    if (virDomainMigratePrepare2(priv->conn, &cookie, &cookielen,
2408 2409 2410
                                 uri_in, uri_out,
                                 args->flags, dname, args->resource,
                                 args->dom_xml) < 0)
2411
        goto cleanup;
2412

2413 2414 2415 2416 2417 2418
    /* 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;
2419

2420 2421
    rv = 0;

2422
 cleanup:
2423
    if (rv < 0) {
2424
        virNetMessageSaveError(rerr);
2425 2426
        VIR_FREE(uri_out);
    }
2427
    return rv;
2428 2429
}

C
Chris Lalancette 已提交
2430
static int
2431 2432
remoteDispatchDomainGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
                                        virNetServerClientPtr client ATTRIBUTE_UNUSED,
2433
                                        virNetMessagePtr msg ATTRIBUTE_UNUSED,
2434 2435 2436
                                        virNetMessageErrorPtr rerr,
                                        remote_domain_get_memory_parameters_args *args,
                                        remote_domain_get_memory_parameters_ret *ret)
C
Chris Lalancette 已提交
2437
{
2438
    virDomainPtr dom = NULL;
2439
    virTypedParameterPtr params = NULL;
2440
    int nparams = 0;
2441
    unsigned int flags;
2442
    int rv = -1;
2443 2444
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2445

2446
    if (!priv->conn) {
2447
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2448
        goto cleanup;
2449
    }
C
Chris Lalancette 已提交
2450

2451
    flags = args->flags;
C
Chris Lalancette 已提交
2452

2453
    if (args->nparams > REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX) {
2454
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
2455 2456
        goto cleanup;
    }
2457
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
2458
        goto cleanup;
2459
    nparams = args->nparams;
C
Chris Lalancette 已提交
2460

2461
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
2462
        goto cleanup;
C
Chris Lalancette 已提交
2463

2464
    if (virDomainGetMemoryParameters(dom, params, &nparams, flags) < 0)
2465
        goto cleanup;
C
Chris Lalancette 已提交
2466

2467 2468 2469 2470 2471 2472
    /* In this case, we need to send back the number of parameters
     * supported
     */
    if (args->nparams == 0) {
        ret->nparams = nparams;
        goto success;
2473 2474
    }

2475
    if (remoteSerializeTypedParameters(params, nparams,
2476
                                       &ret->params.params_val,
2477 2478
                                       &ret->params.params_len,
                                       args->flags) < 0)
2479
        goto cleanup;
2480

2481
 success:
2482 2483
    rv = 0;

2484
 cleanup:
2485
    if (rv < 0)
2486
        virNetMessageSaveError(rerr);
2487
    virTypedParamsFree(params, nparams);
2488
    virObjectUnref(dom);
2489
    return rv;
2490 2491
}

2492 2493 2494 2495 2496 2497 2498 2499 2500 2501
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;
2502
    int nparams = 0;
2503 2504 2505 2506 2507 2508
    unsigned int flags;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
2509
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2510 2511 2512 2513 2514
        goto cleanup;
    }

    flags = args->flags;

2515
    if (args->nparams > REMOTE_DOMAIN_NUMA_PARAMETERS_MAX) {
2516
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
2517 2518
        goto cleanup;
    }
2519
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
2520
        goto cleanup;
2521
    nparams = args->nparams;
2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542

    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;

2543
 success:
2544 2545
    rv = 0;

2546
 cleanup:
2547 2548
    if (rv < 0)
        virNetMessageSaveError(rerr);
2549
    virTypedParamsFree(params, nparams);
2550
    virObjectUnref(dom);
2551 2552 2553
    return rv;
}

2554
static int
2555 2556
remoteDispatchDomainGetBlkioParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
                                       virNetServerClientPtr client ATTRIBUTE_UNUSED,
2557
                                       virNetMessagePtr msg ATTRIBUTE_UNUSED,
2558 2559 2560
                                       virNetMessageErrorPtr rerr,
                                       remote_domain_get_blkio_parameters_args *args,
                                       remote_domain_get_blkio_parameters_ret *ret)
2561
{
2562
    virDomainPtr dom = NULL;
2563
    virTypedParameterPtr params = NULL;
2564
    int nparams = 0;
2565
    unsigned int flags;
2566
    int rv = -1;
2567 2568
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2569

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

2575 2576
    flags = args->flags;

2577
    if (args->nparams > REMOTE_DOMAIN_BLKIO_PARAMETERS_MAX) {
2578
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
2579
        goto cleanup;
2580
    }
2581
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
2582
        goto cleanup;
2583
    nparams = args->nparams;
2584

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

2588
    if (virDomainGetBlkioParameters(dom, params, &nparams, flags) < 0)
2589
        goto cleanup;
2590

2591 2592 2593 2594 2595 2596 2597 2598
    /* In this case, we need to send back the number of parameters
     * supported
     */
    if (args->nparams == 0) {
        ret->nparams = nparams;
        goto success;
    }

2599
    if (remoteSerializeTypedParameters(params, nparams,
2600
                                       &ret->params.params_val,
2601 2602
                                       &ret->params.params_len,
                                       args->flags) < 0)
2603
        goto cleanup;
2604

2605
 success:
2606
    rv = 0;
2607

2608
 cleanup:
2609
    if (rv < 0)
2610
        virNetMessageSaveError(rerr);
2611
    virTypedParamsFree(params, nparams);
2612
    virObjectUnref(dom);
2613
    return rv;
2614 2615
}

2616
static int
2617 2618
remoteDispatchNodeGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED,
                              virNetServerClientPtr client ATTRIBUTE_UNUSED,
2619
                              virNetMessagePtr msg ATTRIBUTE_UNUSED,
2620 2621 2622
                              virNetMessageErrorPtr rerr,
                              remote_node_get_cpu_stats_args *args,
                              remote_node_get_cpu_stats_ret *ret)
2623
{
2624
    virNodeCPUStatsPtr params = NULL;
2625
    size_t i;
2626
    int cpuNum = args->cpuNum;
2627
    int nparams = 0;
2628 2629
    unsigned int flags;
    int rv = -1;
2630 2631
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2632

2633
    if (!priv->conn) {
2634
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2635 2636 2637 2638 2639
        goto cleanup;
    }

    flags = args->flags;

2640
    if (args->nparams > REMOTE_NODE_CPU_STATS_MAX) {
2641
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
2642 2643
        goto cleanup;
    }
2644
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
2645
        goto cleanup;
2646
    nparams = args->nparams;
2647

2648
    if (virNodeGetCPUStats(priv->conn, cpuNum, params, &nparams, flags) < 0)
2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661
        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)
2662
        goto cleanup;
2663 2664 2665

    for (i = 0; i < nparams; ++i) {
        /* remoteDispatchClientRequest will free this: */
2666 2667
        if (VIR_STRDUP(ret->params.params_val[i].field, params[i].field) < 0)
            goto cleanup;
2668 2669 2670 2671

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

2672
 success:
2673 2674
    rv = 0;

2675
 cleanup:
2676
    if (rv < 0) {
2677
        virNetMessageSaveError(rerr);
2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688
        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
2689 2690
remoteDispatchNodeGetMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED,
                                 virNetServerClientPtr client ATTRIBUTE_UNUSED,
2691
                                 virNetMessagePtr msg ATTRIBUTE_UNUSED,
2692 2693 2694
                                 virNetMessageErrorPtr rerr,
                                 remote_node_get_memory_stats_args *args,
                                 remote_node_get_memory_stats_ret *ret)
2695
{
2696
    virNodeMemoryStatsPtr params = NULL;
2697
    size_t i;
2698
    int cellNum = args->cellNum;
2699
    int nparams = 0;
2700 2701
    unsigned int flags;
    int rv = -1;
2702 2703
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2704

2705
    if (!priv->conn) {
2706
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2707 2708 2709 2710 2711
        goto cleanup;
    }

    flags = args->flags;

2712
    if (args->nparams > REMOTE_NODE_MEMORY_STATS_MAX) {
2713
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
2714 2715
        goto cleanup;
    }
2716
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
2717
        goto cleanup;
2718
    nparams = args->nparams;
2719

2720
    if (virNodeGetMemoryStats(priv->conn, cellNum, params, &nparams, flags) < 0)
2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733
        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)
2734
        goto cleanup;
2735 2736 2737

    for (i = 0; i < nparams; ++i) {
        /* remoteDispatchClientRequest will free this: */
2738 2739
        if (VIR_STRDUP(ret->params.params_val[i].field, params[i].field) < 0)
            goto cleanup;
2740 2741 2742 2743

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

2744
 success:
2745 2746
    rv = 0;

2747
 cleanup:
2748
    if (rv < 0) {
2749
        virNetMessageSaveError(rerr);
2750 2751 2752 2753 2754 2755 2756 2757 2758 2759
        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;
}

2760 2761 2762
static int
remoteDispatchDomainGetBlockJobInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
2763
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774
                                    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) {
2775
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792
        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;

2793
 cleanup:
2794 2795
    if (rv < 0)
        virNetMessageSaveError(rerr);
2796
    virObjectUnref(dom);
2797 2798 2799
    return rv;
}

2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810
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;
2811
    int nparams = 0;
2812 2813 2814 2815
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

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

2820
    if (args->nparams > REMOTE_DOMAIN_BLOCK_IO_TUNE_PARAMETERS_MAX) {
2821
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
2822 2823 2824
        goto cleanup;
    }

2825
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
2826
        goto cleanup;
2827
    nparams = args->nparams;
2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850

    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;

2851
 success:
2852 2853
    rv = 0;

2854
 cleanup:
2855 2856
    if (rv < 0)
        virNetMessageSaveError(rerr);
2857
    virTypedParamsFree(params, nparams);
2858
    virObjectUnref(dom);
2859 2860
    return rv;
}
2861

D
Daniel Veillard 已提交
2862 2863
/*-------------------------------------------------------------*/

2864
static int
2865
remoteDispatchAuthList(virNetServerPtr server,
2866
                       virNetServerClientPtr client,
2867
                       virNetMessagePtr msg ATTRIBUTE_UNUSED,
2868
                       virNetMessageErrorPtr rerr,
2869
                       remote_auth_list_ret *ret)
2870
{
2871
    int rv = -1;
2872 2873
    int auth = virNetServerClientGetAuth(client);
    uid_t callerUid;
2874
    gid_t callerGid;
2875
    pid_t callerPid;
2876
    unsigned long long timestamp;
2877 2878 2879 2880 2881 2882

    /* 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) {
2883
        if (virNetServerClientGetUNIXIdentity(client, &callerUid, &callerGid,
2884
                                              &callerPid, &timestamp) < 0) {
2885 2886 2887 2888
            /* Don't do anything on error - it'll be validated at next
             * phase of auth anyway */
            virResetLastError();
        } else if (callerUid == 0) {
2889 2890
            char *ident;
            if (virAsprintf(&ident, "pid:%lld,uid:%d",
2891
                            (long long) callerPid, (int) callerUid) < 0)
J
Jim Fehlig 已提交
2892 2893
                goto cleanup;
            VIR_INFO("Bypass polkit auth for privileged client %s", ident);
2894
            virNetServerClientSetAuth(client, 0);
2895
            virNetServerTrackCompletedAuth(server);
2896
            auth = VIR_NET_SERVER_SERVICE_AUTH_NONE;
J
Jim Fehlig 已提交
2897
            VIR_FREE(ident);
2898 2899
        }
    }
2900

2901
    ret->types.types_len = 1;
2902
    if (VIR_ALLOC_N(ret->types.types_val, ret->types.types_len) < 0)
2903
        goto cleanup;
2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917

    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;
    }
2918

2919 2920
    rv = 0;

2921
 cleanup:
2922
    if (rv < 0)
2923
        virNetMessageSaveError(rerr);
2924
    return rv;
2925 2926 2927
}


2928
#ifdef WITH_SASL
2929 2930
/*
 * Initializes the SASL session in prepare for authentication
2931
 * and gives the client a list of allowed mechanisms to choose
2932 2933
 */
static int
2934 2935
remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED,
                           virNetServerClientPtr client,
2936
                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
2937
                           virNetMessageErrorPtr rerr,
2938
                           remote_auth_sasl_init_ret *ret)
2939
{
2940 2941 2942
    virNetSASLSessionPtr sasl = NULL;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
2943

2944
    virMutexLock(&priv->lock);
2945

2946 2947 2948
    VIR_DEBUG("Initialize SASL auth %d", virNetServerClientGetFD(client));
    if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
        priv->sasl != NULL) {
2949
        VIR_ERROR(_("client tried invalid SASL init request"));
2950
        goto authfail;
2951 2952
    }

2953 2954 2955 2956 2957
    sasl = virNetSASLSessionNewServer(saslCtxt,
                                      "libvirt",
                                      virNetServerClientLocalAddrString(client),
                                      virNetServerClientRemoteAddrString(client));
    if (!sasl)
2958
        goto authfail;
2959

2960
# if WITH_GNUTLS
2961
    /* Inform SASL that we've got an external SSF layer from TLS */
2962 2963 2964 2965
    if (virNetServerClientHasTLSSession(client)) {
        int ssf;

        if ((ssf = virNetServerClientGetTLSKeySize(client)) < 0)
2966
            goto authfail;
2967 2968 2969 2970 2971

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

        VIR_DEBUG("Setting external SSF %d", ssf);
        if (virNetSASLSessionExtKeySize(sasl, ssf) < 0)
2972
            goto authfail;
2973
    }
2974
# endif
2975

2976
    if (virNetServerClientIsSecure(client))
2977
        /* If we've got TLS or UNIX domain sock, we don't care about SSF */
2978 2979
        virNetSASLSessionSecProps(sasl, 0, 0, true);
    else
2980
        /* Plain TCP, better get an SSF layer */
2981 2982 2983 2984
        virNetSASLSessionSecProps(sasl,
                                  56,  /* Good enough to require kerberos */
                                  100000,  /* Arbitrary big number */
                                  false); /* No anonymous */
2985

2986
    if (!(ret->mechlist = virNetSASLSessionListMechanisms(sasl)))
2987
        goto authfail;
2988
    VIR_DEBUG("Available mechanisms for client: '%s'", ret->mechlist);
2989

2990 2991
    priv->sasl = sasl;
    virMutexUnlock(&priv->lock);
2992
    return 0;
2993

2994
 authfail:
2995
    virResetLastError();
2996 2997
    virReportError(VIR_ERR_AUTH_FAILED, "%s",
                   _("authentication failed"));
2998
    virNetMessageSaveError(rerr);
2999 3000 3001
    PROBE(RPC_SERVER_CLIENT_AUTH_FAIL,
          "client=%p auth=%d",
          client, REMOTE_AUTH_SASL);
3002
    virObjectUnref(sasl);
3003
    virMutexUnlock(&priv->lock);
3004
    return -1;
3005 3006
}

3007
/*
3008 3009
 * Returns 0 if ok, -1 on error, -2 if rejected
 */
3010
static int
3011 3012
remoteSASLFinish(virNetServerPtr server,
                 virNetServerClientPtr client)
3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027
{
    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;
        }
3028
    }
3029 3030

    if (!(identity = virNetSASLSessionGetIdentity(priv->sasl)))
3031
        return -2;
3032

3033 3034
    if (!virNetSASLContextCheckIdentity(saslCtxt, identity))
        return -2;
3035

3036
    virNetServerClientSetAuth(client, 0);
3037
    virNetServerTrackCompletedAuth(server);
3038
    virNetServerClientSetSASLSession(client, priv->sasl);
3039

3040
    VIR_DEBUG("Authentication successful %d", virNetServerClientGetFD(client));
3041

3042 3043 3044
    PROBE(RPC_SERVER_CLIENT_AUTH_ALLOW,
          "client=%p auth=%d identity=%s",
          client, REMOTE_AUTH_SASL, identity);
3045

3046
    virObjectUnref(priv->sasl);
3047
    priv->sasl = NULL;
3048

3049
    return 0;
3050

3051
 error:
3052 3053
    return -1;
}
3054

3055 3056 3057 3058
/*
 * This starts the SASL authentication negotiation.
 */
static int
3059
remoteDispatchAuthSaslStart(virNetServerPtr server,
3060
                            virNetServerClientPtr client,
3061
                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
3062
                            virNetMessageErrorPtr rerr,
3063 3064
                            remote_auth_sasl_start_args *args,
                            remote_auth_sasl_start_ret *ret)
3065 3066
{
    const char *serverout;
3067
    size_t serveroutlen;
3068
    int err;
3069 3070 3071
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3072
    const char *identity;
3073

3074
    virMutexLock(&priv->lock);
3075

3076 3077 3078
    VIR_DEBUG("Start SASL auth %d", virNetServerClientGetFD(client));
    if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
        priv->sasl == NULL) {
3079
        VIR_ERROR(_("client tried invalid SASL start request"));
3080
        goto authfail;
3081 3082
    }

3083 3084
    VIR_DEBUG("Using SASL mechanism %s. Data %d bytes, nil: %d",
              args->mech, args->data.data_len, args->nil);
3085 3086 3087 3088 3089 3090 3091 3092 3093
    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)
3094
        goto authfail;
3095

3096
    if (serveroutlen > REMOTE_AUTH_SASL_DATA_MAX) {
3097
        VIR_ERROR(_("sasl start reply data too long %d"), (int)serveroutlen);
3098
        goto authfail;
3099 3100 3101 3102
    }

    /* NB, distinction of NULL vs "" is *critical* in SASL */
    if (serverout) {
3103 3104
        if (VIR_ALLOC_N(ret->data.data_val, serveroutlen) < 0)
            goto authfail;
3105 3106 3107 3108 3109 3110 3111
        memcpy(ret->data.data_val, serverout, serveroutlen);
    } else {
        ret->data.data_val = NULL;
    }
    ret->nil = serverout ? 0 : 1;
    ret->data.data_len = serveroutlen;

3112
    VIR_DEBUG("SASL return data %d bytes, nil; %d", ret->data.data_len, ret->nil);
3113
    if (err == VIR_NET_SASL_CONTINUE) {
3114 3115
        ret->complete = 0;
    } else {
3116
        /* Check username whitelist ACL */
3117
        if ((err = remoteSASLFinish(server, client)) < 0) {
3118 3119 3120 3121 3122
            if (err == -2)
                goto authdeny;
            else
                goto authfail;
        }
3123

3124 3125 3126
        ret->complete = 1;
    }

3127
    virMutexUnlock(&priv->lock);
3128
    return 0;
3129

3130
 authfail:
3131 3132 3133
    PROBE(RPC_SERVER_CLIENT_AUTH_FAIL,
          "client=%p auth=%d",
          client, REMOTE_AUTH_SASL);
3134 3135
    goto error;

3136
 authdeny:
3137
    identity = virNetSASLSessionGetIdentity(priv->sasl);
3138 3139 3140
    PROBE(RPC_SERVER_CLIENT_AUTH_DENY,
          "client=%p auth=%d identity=%s",
          client, REMOTE_AUTH_SASL, identity);
3141 3142
    goto error;

3143
 error:
3144
    virObjectUnref(priv->sasl);
3145 3146
    priv->sasl = NULL;
    virResetLastError();
3147 3148
    virReportError(VIR_ERR_AUTH_FAILED, "%s",
                   _("authentication failed"));
3149 3150 3151
    if (rv < 0)
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
3152
    return -1;
3153 3154 3155 3156
}


static int
3157
remoteDispatchAuthSaslStep(virNetServerPtr server,
3158
                           virNetServerClientPtr client,
3159
                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
3160
                           virNetMessageErrorPtr rerr,
3161 3162
                           remote_auth_sasl_step_args *args,
                           remote_auth_sasl_step_ret *ret)
3163 3164
{
    const char *serverout;
3165
    size_t serveroutlen;
3166
    int err;
3167 3168 3169
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3170
    const char *identity;
3171

3172 3173 3174 3175 3176
    virMutexLock(&priv->lock);

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

3181
    VIR_DEBUG("Step using SASL Data %d bytes, nil: %d",
3182
              args->data.data_len, args->nil);
3183 3184 3185 3186 3187 3188 3189 3190
    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)
3191
        goto authfail;
3192 3193

    if (serveroutlen > REMOTE_AUTH_SASL_DATA_MAX) {
3194
        VIR_ERROR(_("sasl step reply data too long %d"),
3195
                  (int)serveroutlen);
3196
        goto authfail;
3197 3198 3199 3200
    }

    /* NB, distinction of NULL vs "" is *critical* in SASL */
    if (serverout) {
3201 3202
        if (VIR_ALLOC_N(ret->data.data_val, serveroutlen) < 0)
            goto authfail;
3203 3204 3205 3206 3207 3208 3209
        memcpy(ret->data.data_val, serverout, serveroutlen);
    } else {
        ret->data.data_val = NULL;
    }
    ret->nil = serverout ? 0 : 1;
    ret->data.data_len = serveroutlen;

3210
    VIR_DEBUG("SASL return data %d bytes, nil; %d", ret->data.data_len, ret->nil);
3211
    if (err == VIR_NET_SASL_CONTINUE) {
3212 3213
        ret->complete = 0;
    } else {
3214
        /* Check username whitelist ACL */
3215
        if ((err = remoteSASLFinish(server, client)) < 0) {
3216 3217 3218 3219 3220
            if (err == -2)
                goto authdeny;
            else
                goto authfail;
        }
3221

3222 3223 3224
        ret->complete = 1;
    }

3225
    virMutexUnlock(&priv->lock);
3226
    return 0;
3227

3228
 authfail:
3229 3230 3231
    PROBE(RPC_SERVER_CLIENT_AUTH_FAIL,
          "client=%p auth=%d",
          client, REMOTE_AUTH_SASL);
3232 3233
    goto error;

3234
 authdeny:
3235
    identity = virNetSASLSessionGetIdentity(priv->sasl);
3236 3237 3238
    PROBE(RPC_SERVER_CLIENT_AUTH_DENY,
          "client=%p auth=%d identity=%s",
          client, REMOTE_AUTH_SASL, identity);
3239 3240
    goto error;

3241
 error:
3242
    virObjectUnref(priv->sasl);
3243 3244
    priv->sasl = NULL;
    virResetLastError();
3245 3246
    virReportError(VIR_ERR_AUTH_FAILED, "%s",
                   _("authentication failed"));
3247 3248 3249
    if (rv < 0)
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
3250 3251
    return -1;
}
3252 3253 3254 3255
#else
static int
remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED,
                           virNetServerClientPtr client ATTRIBUTE_UNUSED,
3256
                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
3257 3258 3259 3260
                           virNetMessageErrorPtr rerr,
                           remote_auth_sasl_init_ret *ret ATTRIBUTE_UNUSED)
{
    VIR_WARN("Client tried unsupported SASL auth");
3261 3262
    virReportError(VIR_ERR_AUTH_FAILED, "%s",
                   _("authentication failed"));
3263 3264 3265 3266 3267 3268
    virNetMessageSaveError(rerr);
    return -1;
}
static int
remoteDispatchAuthSaslStart(virNetServerPtr server ATTRIBUTE_UNUSED,
                            virNetServerClientPtr client ATTRIBUTE_UNUSED,
3269
                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
3270 3271 3272 3273 3274
                            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");
3275 3276
    virReportError(VIR_ERR_AUTH_FAILED, "%s",
                   _("authentication failed"));
3277 3278 3279 3280 3281 3282
    virNetMessageSaveError(rerr);
    return -1;
}
static int
remoteDispatchAuthSaslStep(virNetServerPtr server ATTRIBUTE_UNUSED,
                           virNetServerClientPtr client ATTRIBUTE_UNUSED,
3283
                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
3284 3285 3286 3287 3288
                           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");
3289 3290
    virReportError(VIR_ERR_AUTH_FAILED, "%s",
                   _("authentication failed"));
3291 3292 3293 3294
    virNetMessageSaveError(rerr);
    return -1;
}
#endif
3295 3296 3297



3298
static int
3299
remoteDispatchAuthPolkit(virNetServerPtr server,
3300
                         virNetServerClientPtr client,
3301
                         virNetMessagePtr msg ATTRIBUTE_UNUSED,
3302
                         virNetMessageErrorPtr rerr,
3303
                         remote_auth_polkit_ret *ret)
3304
{
3305
    pid_t callerPid = -1;
3306
    gid_t callerGid = -1;
3307
    uid_t callerUid = -1;
3308
    unsigned long long timestamp;
3309
    const char *action;
3310
    char *ident = NULL;
3311 3312
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3313
    int rv;
3314

3315 3316
    virMutexLock(&priv->lock);
    action = virNetServerClientGetReadonly(client) ?
3317 3318 3319
        "org.libvirt.unix.monitor" :
        "org.libvirt.unix.manage";

3320 3321
    VIR_DEBUG("Start PolicyKit auth %d", virNetServerClientGetFD(client));
    if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_POLKIT) {
3322
        VIR_ERROR(_("client tried invalid PolicyKit init request"));
3323 3324 3325
        goto authfail;
    }

3326
    if (virNetServerClientGetUNIXIdentity(client, &callerUid, &callerGid,
3327
                                          &callerPid, &timestamp) < 0) {
3328 3329 3330
        goto authfail;
    }

3331 3332 3333 3334 3335 3336
    if (timestamp == 0) {
        VIR_WARN("Failing polkit auth due to missing client (pid=%lld) start time",
                 (long long)callerPid);
        goto authfail;
    }

3337 3338
    VIR_INFO("Checking PID %lld running as %d",
             (long long) callerPid, callerUid);
3339

3340 3341 3342 3343 3344 3345 3346
    rv = virPolkitCheckAuth(action,
                            callerPid,
                            timestamp,
                            callerUid,
                            NULL,
                            true);
    if (rv == -1)
3347
        goto authfail;
3348
    else if (rv == -2)
3349
        goto authdeny;
3350

3351 3352 3353
    PROBE(RPC_SERVER_CLIENT_AUTH_ALLOW,
          "client=%p auth=%d identity=%s",
          client, REMOTE_AUTH_POLKIT, ident);
3354 3355
    VIR_INFO("Policy allowed action %s from pid %lld, uid %d",
             action, (long long) callerPid, callerUid);
3356 3357
    ret->complete = 1;

3358
    virNetServerClientSetAuth(client, 0);
3359
    virNetServerTrackCompletedAuth(server);
3360
    virMutexUnlock(&priv->lock);
3361

3362
    return 0;
3363

3364
 error:
3365
    virNetMessageSaveError(rerr);
J
Jim Fehlig 已提交
3366
    virMutexUnlock(&priv->lock);
3367 3368
    return -1;

3369
 authfail:
3370 3371 3372
    PROBE(RPC_SERVER_CLIENT_AUTH_FAIL,
          "client=%p auth=%d",
          client, REMOTE_AUTH_POLKIT);
3373
    goto error;
3374

3375
 authdeny:
3376 3377 3378
    PROBE(RPC_SERVER_CLIENT_AUTH_DENY,
          "client=%p auth=%d identity=%s",
          client, REMOTE_AUTH_POLKIT, ident);
3379
    goto error;
3380 3381
}

3382

3383 3384 3385
/***************************************************************
 *     NODE INFO APIS
 **************************************************************/
3386

3387
static int
3388 3389
remoteDispatchNodeDeviceGetParent(virNetServerPtr server ATTRIBUTE_UNUSED,
                                  virNetServerClientPtr client ATTRIBUTE_UNUSED,
3390
                                  virNetMessagePtr msg ATTRIBUTE_UNUSED,
3391
                                  virNetMessageErrorPtr rerr,
3392 3393
                                  remote_node_device_get_parent_args *args,
                                  remote_node_device_get_parent_ret *ret)
3394
{
3395 3396
    virNodeDevicePtr dev = NULL;
    const char *parent = NULL;
3397
    int rv = -1;
3398 3399
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3400

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

3406
    if (!(dev = virNodeDeviceLookupByName(priv->conn, args->name)))
3407 3408
        goto cleanup;

3409 3410 3411 3412 3413 3414 3415
    parent = virNodeDeviceGetParent(dev);

    if (parent == NULL) {
        ret->parent = NULL;
    } else {
        /* remoteDispatchClientRequest will free this. */
        char **parent_p;
3416
        if (VIR_ALLOC(parent_p) < 0)
3417
            goto cleanup;
3418
        if (VIR_STRDUP(*parent_p, parent) < 0) {
3419 3420 3421 3422 3423 3424
            VIR_FREE(parent_p);
            goto cleanup;
        }
        ret->parent = parent_p;
    }

3425 3426
    rv = 0;

3427
 cleanup:
3428
    if (rv < 0)
3429
        virNetMessageSaveError(rerr);
3430
    virObjectUnref(dev);
3431
    return rv;
3432 3433
}

3434 3435 3436 3437 3438

/***************************
 * Register / deregister events
 ***************************/
static int
3439
remoteDispatchConnectDomainEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
3440
                                         virNetServerClientPtr client,
3441 3442 3443
                                         virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                         virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                         remote_connect_domain_event_register_ret *ret ATTRIBUTE_UNUSED)
O
Osier Yang 已提交
3444
{
3445
    int callbackID;
3446
    int rv = -1;
3447 3448
    daemonClientEventCallbackPtr callback = NULL;
    daemonClientEventCallbackPtr ref;
3449 3450
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
O
Osier Yang 已提交
3451

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

3457 3458
    virMutexLock(&priv->lock);

3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469
    /* 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;
3470
    callback->legacy = true;
3471 3472 3473 3474
    ref = callback;
    if (VIR_APPEND_ELEMENT(priv->domainEventCallbacks,
                           priv->ndomainEventCallbacks,
                           callback) < 0)
3475
        goto cleanup;
O
Osier Yang 已提交
3476

3477
    if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
3478 3479 3480
                                                       NULL,
                                                       VIR_DOMAIN_EVENT_ID_LIFECYCLE,
                                                       VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
3481 3482 3483 3484 3485
                                                       ref,
                                                       remoteEventCallbackFree)) < 0) {
        VIR_SHRINK_N(priv->domainEventCallbacks,
                     priv->ndomainEventCallbacks, 1);
        callback = ref;
3486
        goto cleanup;
3487
    }
O
Osier Yang 已提交
3488

3489
    ref->callbackID = callbackID;
3490

3491 3492
    rv = 0;

3493
 cleanup:
3494
    VIR_FREE(callback);
3495
    if (rv < 0)
3496 3497
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
3498
    return rv;
O
Osier Yang 已提交
3499 3500
}

3501
static int
3502
remoteDispatchConnectDomainEventDeregister(virNetServerPtr server ATTRIBUTE_UNUSED,
3503
                                           virNetServerClientPtr client,
3504 3505 3506
                                           virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                           virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                           remote_connect_domain_event_deregister_ret *ret ATTRIBUTE_UNUSED)
3507
{
3508
    int callbackID = -1;
3509
    int rv = -1;
3510
    size_t i;
3511 3512
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3513

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

3519 3520
    virMutexLock(&priv->lock);

3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531
    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);
3532
        goto cleanup;
3533
    }
3534

3535
    if (virConnectDomainEventDeregisterAny(priv->conn, callbackID) < 0)
3536
        goto cleanup;
3537

3538 3539
    VIR_DELETE_ELEMENT(priv->domainEventCallbacks, i,
                       priv->ndomainEventCallbacks);
3540

3541 3542
    rv = 0;

3543
 cleanup:
3544
    if (rv < 0)
3545 3546
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
3547 3548 3549 3550
    return rv;
}

static void
3551
remoteDispatchObjectEventSend(virNetServerClientPtr client,
3552
                              virNetServerProgramPtr program,
3553 3554 3555 3556
                              int procnr,
                              xdrproc_t proc,
                              void *data)
{
3557
    virNetMessagePtr msg;
3558

3559
    if (!(msg = virNetMessageNew(false)))
3560
        goto cleanup;
3561

3562 3563 3564 3565 3566 3567
    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;
3568

3569
    if (virNetMessageEncodeHeader(msg) < 0)
3570 3571
        goto cleanup;

3572 3573
    if (virNetMessageEncodePayload(msg, proc, data) < 0)
        goto cleanup;
3574

3575 3576
    VIR_DEBUG("Queue event %d %zu", procnr, msg->bufferLength);
    virNetServerClientSendMessage(client, msg);
3577

3578
    xdr_free(proc, data);
3579 3580
    return;

3581
 cleanup:
3582
    virNetMessageFree(msg);
3583
    xdr_free(proc, data);
3584 3585
}

3586
static int
3587 3588
remoteDispatchSecretGetValue(virNetServerPtr server ATTRIBUTE_UNUSED,
                             virNetServerClientPtr client ATTRIBUTE_UNUSED,
3589
                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
3590
                             virNetMessageErrorPtr rerr,
3591 3592
                             remote_secret_get_value_args *args,
                             remote_secret_get_value_ret *ret)
3593
{
3594 3595 3596
    virSecretPtr secret = NULL;
    size_t value_size;
    unsigned char *value;
3597
    int rv = -1;
3598 3599
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3600

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

3606
    if (!(secret = get_nonnull_secret(priv->conn, args->secret)))
3607
        goto cleanup;
3608

3609
    if (!(value = virSecretGetValue(secret, &value_size, args->flags)))
3610
        goto cleanup;
3611

3612 3613 3614
    ret->value.value_len = value_size;
    ret->value.value_val = (char *)value;

3615 3616
    rv = 0;

3617
 cleanup:
3618
    if (rv < 0)
3619
        virNetMessageSaveError(rerr);
3620
    virObjectUnref(secret);
3621
    return rv;
3622 3623
}

3624
static int
3625 3626
remoteDispatchDomainGetState(virNetServerPtr server ATTRIBUTE_UNUSED,
                             virNetServerClientPtr client ATTRIBUTE_UNUSED,
3627
                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
3628
                             virNetMessageErrorPtr rerr,
3629 3630 3631 3632 3633
                             remote_domain_get_state_args *args,
                             remote_domain_get_state_ret *ret)
{
    virDomainPtr dom = NULL;
    int rv = -1;
3634 3635
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3636

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

3642
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
3643 3644 3645 3646 3647 3648 3649
        goto cleanup;

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

    rv = 0;

3650
 cleanup:
3651
    if (rv < 0)
3652
        virNetMessageSaveError(rerr);
3653
    virObjectUnref(dom);
3654 3655 3656
    return rv;
}

3657 3658 3659 3660 3661 3662

/* 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.  */
3663
static int
3664
remoteDispatchConnectDomainEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
3665
                                            virNetServerClientPtr client,
3666 3667 3668
                                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                            virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                            remote_connect_domain_event_register_any_args *args)
3669 3670
{
    int callbackID;
3671
    int rv = -1;
3672 3673
    daemonClientEventCallbackPtr callback = NULL;
    daemonClientEventCallbackPtr ref;
3674 3675
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3676

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

3682 3683
    virMutexLock(&priv->lock);

3684 3685 3686 3687
    /* 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 ||
3688
        args->eventID < 0) {
3689 3690
        virReportError(VIR_ERR_INTERNAL_ERROR, _("unsupported event ID %d"),
                       args->eventID);
3691
        goto cleanup;
3692 3693
    }

3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704
    /* 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;
3705
    callback->legacy = true;
3706 3707 3708 3709
    ref = callback;
    if (VIR_APPEND_ELEMENT(priv->domainEventCallbacks,
                           priv->ndomainEventCallbacks,
                           callback) < 0)
3710
        goto cleanup;
3711

3712
    if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
3713 3714 3715
                                                       NULL,
                                                       args->eventID,
                                                       domainEventCallbacks[args->eventID],
3716 3717 3718 3719 3720
                                                       ref,
                                                       remoteEventCallbackFree)) < 0) {
        VIR_SHRINK_N(priv->domainEventCallbacks,
                     priv->ndomainEventCallbacks, 1);
        callback = ref;
3721
        goto cleanup;
3722
    }
3723

3724
    ref->callbackID = callbackID;
3725

3726 3727
    rv = 0;

3728
 cleanup:
3729
    VIR_FREE(callback);
3730
    if (rv < 0)
3731 3732
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
3733
    return rv;
3734 3735 3736
}


3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763
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;

3764
    if (args->eventID >= VIR_DOMAIN_EVENT_ID_LAST || args->eventID < 0) {
3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803
        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;

3804
 cleanup:
3805 3806 3807
    VIR_FREE(callback);
    if (rv < 0)
        virNetMessageSaveError(rerr);
3808
    virObjectUnref(dom);
3809 3810 3811 3812 3813
    virMutexUnlock(&priv->lock);
    return rv;
}


3814
static int
3815
remoteDispatchConnectDomainEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
3816
                                              virNetServerClientPtr client,
3817 3818 3819
                                              virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                              virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                              remote_connect_domain_event_deregister_any_args *args)
3820 3821
{
    int callbackID = -1;
3822
    int rv = -1;
3823
    size_t i;
3824 3825
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3826

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

3832 3833
    virMutexLock(&priv->lock);

3834 3835 3836 3837
    /* 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 ||
3838
        args->eventID < 0) {
3839 3840
        virReportError(VIR_ERR_INTERNAL_ERROR, _("unsupported event ID %d"),
                       args->eventID);
3841
        goto cleanup;
3842 3843
    }

3844 3845 3846 3847 3848 3849
    for (i = 0; i < priv->ndomainEventCallbacks; i++) {
        if (priv->domainEventCallbacks[i]->eventID == args->eventID) {
            callbackID = priv->domainEventCallbacks[i]->callbackID;
            break;
        }
    }
3850
    if (callbackID < 0) {
3851 3852
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("domain event %d not registered"), args->eventID);
3853
        goto cleanup;
3854 3855
    }

3856
    if (virConnectDomainEventDeregisterAny(priv->conn, callbackID) < 0)
3857
        goto cleanup;
3858

3859 3860
    VIR_DELETE_ELEMENT(priv->domainEventCallbacks, i,
                       priv->ndomainEventCallbacks);
3861

3862 3863
    rv = 0;

3864
 cleanup:
3865
    if (rv < 0)
3866 3867
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
3868
    return rv;
3869 3870
}

3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909

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;

3910
 cleanup:
3911 3912 3913 3914 3915 3916 3917
    if (rv < 0)
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
    return rv;
}


C
Chris Lalancette 已提交
3918
static int
3919 3920 3921 3922 3923 3924
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 已提交
3925
{
3926
    virDomainPtr dom = NULL;
3927
    int rv = -1;
3928 3929
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
C
Chris Lalancette 已提交
3930

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

3936
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
3937
        goto cleanup;
C
Chris Lalancette 已提交
3938

3939
    if (virDomainQemuMonitorCommand(dom, args->cmd, &ret->result,
3940
                                    args->flags) < 0)
3941
        goto cleanup;
C
Chris Lalancette 已提交
3942

3943
    rv = 0;
C
Chris Lalancette 已提交
3944

3945
 cleanup:
3946
    if (rv < 0)
3947
        virNetMessageSaveError(rerr);
3948
    virObjectUnref(dom);
3949
    return rv;
C
Chris Lalancette 已提交
3950 3951
}

3952

3953
static int
3954 3955
remoteDispatchDomainMigrateBegin3(virNetServerPtr server ATTRIBUTE_UNUSED,
                                  virNetServerClientPtr client ATTRIBUTE_UNUSED,
3956
                                  virNetMessagePtr msg ATTRIBUTE_UNUSED,
3957
                                  virNetMessageErrorPtr rerr,
3958 3959 3960 3961 3962 3963
                                  remote_domain_migrate_begin3_args *args,
                                  remote_domain_migrate_begin3_ret *ret)
{
    char *xml = NULL;
    virDomainPtr dom = NULL;
    char *dname;
3964
    char *xmlin;
3965 3966 3967
    char *cookieout = NULL;
    int cookieoutlen = 0;
    int rv = -1;
3968 3969
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
3970

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

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

3979
    xmlin = args->xmlin == NULL ? NULL : *args->xmlin;
3980 3981
    dname = args->dname == NULL ? NULL : *args->dname;

3982
    if (!(xml = virDomainMigrateBegin3(dom, xmlin,
3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995
                                       &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;

3996
 cleanup:
3997
    if (rv < 0)
3998
        virNetMessageSaveError(rerr);
3999
    virObjectUnref(dom);
4000 4001 4002 4003 4004
    return rv;
}


static int
4005 4006
remoteDispatchDomainMigratePrepare3(virNetServerPtr server ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
4007
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
4008
                                    virNetMessageErrorPtr rerr,
4009 4010 4011 4012 4013 4014 4015 4016 4017
                                    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;
4018 4019
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
4020

4021
    if (!priv->conn) {
4022
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4023 4024 4025 4026 4027 4028 4029
        goto cleanup;
    }

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

    /* Wacky world of XDR ... */
4030
    if (VIR_ALLOC(uri_out) < 0)
4031 4032
        goto cleanup;

4033
    if (virDomainMigratePrepare3(priv->conn,
4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050
                                 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;

4051
 cleanup:
4052
    if (rv < 0) {
4053
        virNetMessageSaveError(rerr);
4054 4055 4056 4057 4058
        VIR_FREE(uri_out);
    }
    return rv;
}

4059

4060
static int
4061 4062
remoteDispatchDomainMigratePerform3(virNetServerPtr server ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
4063
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
4064
                                    virNetMessageErrorPtr rerr,
4065 4066 4067 4068
                                    remote_domain_migrate_perform3_args *args,
                                    remote_domain_migrate_perform3_ret *ret)
{
    virDomainPtr dom = NULL;
4069
    char *xmlin;
4070
    char *dname;
4071 4072
    char *uri;
    char *dconnuri;
4073 4074 4075
    char *cookieout = NULL;
    int cookieoutlen = 0;
    int rv = -1;
4076 4077
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
4078

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

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

4087
    xmlin = args->xmlin == NULL ? NULL : *args->xmlin;
4088
    dname = args->dname == NULL ? NULL : *args->dname;
4089 4090
    uri = args->uri == NULL ? NULL : *args->uri;
    dconnuri = args->dconnuri == NULL ? NULL : *args->dconnuri;
4091

4092
    if (virDomainMigratePerform3(dom, xmlin,
4093 4094 4095
                                 args->cookie_in.cookie_in_val,
                                 args->cookie_in.cookie_in_len,
                                 &cookieout, &cookieoutlen,
4096
                                 dconnuri, uri,
4097 4098 4099 4100 4101 4102 4103 4104 4105 4106
                                 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;

4107
 cleanup:
4108
    if (rv < 0)
4109
        virNetMessageSaveError(rerr);
4110
    virObjectUnref(dom);
4111 4112 4113 4114 4115
    return rv;
}


static int
4116 4117
remoteDispatchDomainMigrateFinish3(virNetServerPtr server ATTRIBUTE_UNUSED,
                                   virNetServerClientPtr client ATTRIBUTE_UNUSED,
4118
                                   virNetMessagePtr msg ATTRIBUTE_UNUSED,
4119
                                   virNetMessageErrorPtr rerr,
4120 4121 4122 4123 4124 4125
                                   remote_domain_migrate_finish3_args *args,
                                   remote_domain_migrate_finish3_ret *ret)
{
    virDomainPtr dom = NULL;
    char *cookieout = NULL;
    int cookieoutlen = 0;
4126 4127
    char *uri;
    char *dconnuri;
4128
    int rv = -1;
4129 4130
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
4131

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

4137 4138 4139
    uri = args->uri == NULL ? NULL : *args->uri;
    dconnuri = args->dconnuri == NULL ? NULL : *args->dconnuri;

4140
    if (!(dom = virDomainMigrateFinish3(priv->conn, args->dname,
4141 4142 4143 4144 4145 4146
                                        args->cookie_in.cookie_in_val,
                                        args->cookie_in.cookie_in_len,
                                        &cookieout, &cookieoutlen,
                                        dconnuri, uri,
                                        args->flags,
                                        args->cancelled)))
4147 4148
        goto cleanup;

4149
    make_nonnull_domain(&ret->dom, dom);
4150 4151 4152 4153 4154 4155 4156 4157

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

    rv = 0;

4158
 cleanup:
4159
    if (rv < 0) {
4160
        virNetMessageSaveError(rerr);
4161 4162
        VIR_FREE(cookieout);
    }
4163
    virObjectUnref(dom);
4164 4165 4166 4167 4168
    return rv;
}


static int
4169 4170
remoteDispatchDomainMigrateConfirm3(virNetServerPtr server ATTRIBUTE_UNUSED,
                                    virNetServerClientPtr client ATTRIBUTE_UNUSED,
4171
                                    virNetMessagePtr msg ATTRIBUTE_UNUSED,
4172 4173
                                    virNetMessageErrorPtr rerr,
                                    remote_domain_migrate_confirm3_args *args)
4174 4175 4176
{
    virDomainPtr dom = NULL;
    int rv = -1;
4177 4178
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
4179

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

4185
    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
4186 4187 4188 4189 4190 4191 4192 4193 4194 4195
        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;

4196
 cleanup:
4197
    if (rv < 0)
4198
        virNetMessageSaveError(rerr);
4199
    virObjectUnref(dom);
4200 4201 4202 4203
    return rv;
}


4204 4205 4206 4207 4208 4209
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)
4210 4211 4212 4213 4214 4215
{
    int rv = -1;
    int supported;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

4216 4217 4218 4219 4220 4221 4222 4223 4224 4225
    /* 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;
    }

4226
    if (!priv->conn) {
4227
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4228 4229 4230 4231 4232
        goto cleanup;
    }

    switch (args->feature) {
    case VIR_DRV_FEATURE_FD_PASSING:
4233
    case VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK:
4234 4235 4236 4237
        supported = 1;
        break;

    default:
4238
        if ((supported = virConnectSupportsFeature(priv->conn, args->feature)) < 0)
4239 4240 4241 4242
            goto cleanup;
        break;
    }

4243
 done:
4244 4245 4246
    ret->supported = supported;
    rv = 0;

4247
 cleanup:
4248 4249 4250 4251 4252 4253
    if (rv < 0)
        virNetMessageSaveError(rerr);
    return rv;
}


4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267
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) {
4268
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285
        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;

4286
 cleanup:
4287 4288 4289
    VIR_FORCE_CLOSE(fd);
    if (rv < 0)
        virNetMessageSaveError(rerr);
4290
    virObjectUnref(dom);
4291 4292 4293
    return rv;
}

4294

4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315
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;

4316 4317 4318
    if ((fd = virDomainOpenGraphicsFD(dom,
                                      args->idx,
                                      args->flags)) < 0)
4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329
        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);
4330
    if (rv < 0)
4331 4332
        virNetMessageSaveError(rerr);

4333
    virObjectUnref(dom);
4334 4335
    return rv;
}
4336 4337


4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348
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;
4349
    int nparams = 0;
4350 4351 4352 4353 4354 4355
    unsigned int flags;
    int rv = -1;
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
4356
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4357 4358 4359 4360 4361
        goto cleanup;
    }

    flags = args->flags;

4362
    if (args->nparams > REMOTE_DOMAIN_INTERFACE_PARAMETERS_MAX) {
4363
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
4364 4365
        goto cleanup;
    }
4366
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
4367
        goto cleanup;
4368
    nparams = args->nparams;
4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389

    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;

4390
 success:
4391 4392
    rv = 0;

4393
 cleanup:
4394 4395
    if (rv < 0)
        virNetMessageSaveError(rerr);
4396
    virTypedParamsFree(params, nparams);
4397
    virObjectUnref(dom);
4398 4399
    return rv;
}
4400

4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416
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) {
4417
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4418 4419 4420 4421
        goto cleanup;
    }

    if (args->nparams > REMOTE_NODE_CPU_STATS_MAX) {
4422
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
4423 4424 4425
        goto cleanup;
    }
    if (args->ncpus > REMOTE_DOMAIN_GET_CPU_STATS_NCPUS_MAX) {
4426
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("ncpus too large"));
4427 4428 4429 4430
        goto cleanup;
    }

    if (args->nparams > 0 &&
4431
        VIR_ALLOC_N(params, args->ncpus * args->nparams) < 0)
4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451
        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;

4452
 success:
4453 4454
    rv = 0;
    ret->nparams = percpu_len;
4455
    if (args->nparams && !(args->flags & VIR_TYPED_PARAM_STRING_OKAY)) {
4456
        size_t i;
4457 4458 4459 4460 4461 4462

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

4464
 cleanup:
4465 4466
    if (rv < 0)
         virNetMessageSaveError(rerr);
4467
    virTypedParamsFree(params, args->ncpus * args->nparams);
4468
    virObjectUnref(dom);
4469 4470 4471
    return rv;
}

4472 4473 4474 4475 4476 4477 4478
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)
4479 4480 4481 4482
{
    int rv = -1;
    virDomainPtr dom = NULL;
    virDomainDiskErrorPtr errors = NULL;
4483
    int len = 0;
4484 4485 4486 4487
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

    if (!priv->conn) {
4488
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4489 4490 4491 4492 4493 4494 4495
        goto cleanup;
    }

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

    if (args->maxerrors > REMOTE_DOMAIN_DISK_ERRORS_MAX) {
4496 4497
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("maxerrors too large"));
4498 4499 4500 4501
        goto cleanup;
    }

    if (args->maxerrors &&
4502
        VIR_ALLOC_N(errors, args->maxerrors) < 0)
4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518
        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;

4519
 cleanup:
4520 4521
    if (rv < 0)
        virNetMessageSaveError(rerr);
4522
    virObjectUnref(dom);
4523
    if (errors && len > 0) {
4524
        size_t i;
4525 4526 4527 4528 4529 4530 4531
        for (i = 0; i < len; i++)
            VIR_FREE(errors[i].disk);
    }
    VIR_FREE(errors);
    return rv;
}

4532 4533 4534 4535 4536 4537 4538 4539 4540 4541
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;
4542
    size_t i;
4543 4544 4545 4546 4547
    int rv = -1;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
    virDomainPtr dom = NULL;

    if (!priv->conn) {
4548
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559
        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;

4560 4561 4562 4563 4564 4565 4566
    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;
    }

4567
    if (snaps && nsnaps) {
4568
        if (VIR_ALLOC_N(ret->snapshots.snapshots_val, nsnaps) < 0)
4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583
            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;

4584
 cleanup:
4585 4586
    if (rv < 0)
        virNetMessageSaveError(rerr);
4587
    virObjectUnref(dom);
4588
    if (snaps && nsnaps > 0)
4589
        for (i = 0; i < nsnaps; i++)
4590
            virObjectUnref(snaps[i]);
4591
    VIR_FREE(snaps);
4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604
    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;
4605
    size_t i;
4606 4607 4608 4609 4610 4611
    int rv = -1;
    struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
    virDomainPtr dom = NULL;
    virDomainSnapshotPtr snapshot = NULL;

    if (!priv->conn) {
4612
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626
        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;

4627 4628 4629 4630 4631 4632 4633
    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;
    }

4634
    if (snaps && nsnaps) {
4635
        if (VIR_ALLOC_N(ret->snapshots.snapshots_val, nsnaps) < 0)
4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650
            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;

4651
 cleanup:
4652 4653
    if (rv < 0)
        virNetMessageSaveError(rerr);
4654
    virObjectUnref(snapshot);
4655
    virObjectUnref(dom);
4656
    if (snaps && nsnaps > 0)
4657
        for (i = 0; i < nsnaps; i++)
4658
            virObjectUnref(snaps[i]);
4659
    VIR_FREE(snaps);
4660 4661 4662
    return rv;
}

4663 4664 4665 4666 4667 4668 4669 4670 4671 4672
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;
4673
    size_t i;
4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686
    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;

4687 4688 4689 4690 4691 4692 4693
    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;
    }

4694
    if (pools && npools) {
4695
        if (VIR_ALLOC_N(ret->pools.pools_val, npools) < 0)
4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710
            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;

4711
 cleanup:
4712 4713
    if (rv < 0)
        virNetMessageSaveError(rerr);
4714
    if (pools && npools > 0)
4715
        for (i = 0; i < npools; i++)
4716
            virObjectUnref(pools[i]);
4717
    VIR_FREE(pools);
4718 4719 4720
    return rv;
}

4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731
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;
4732
    size_t i;
4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748
    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;

4749 4750 4751 4752 4753 4754 4755
    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;
    }

4756
    if (vols && nvols) {
4757
        if (VIR_ALLOC_N(ret->vols.vols_val, nvols) < 0)
4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772
            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;

4773
 cleanup:
4774 4775
    if (rv < 0)
        virNetMessageSaveError(rerr);
4776
    if (vols && nvols > 0)
4777
        for (i = 0; i < nvols; i++)
4778
            virObjectUnref(vols[i]);
4779
    VIR_FREE(vols);
4780
    virObjectUnref(pool);
4781 4782 4783
    return rv;
}

4784 4785 4786 4787 4788 4789 4790 4791 4792 4793
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;
4794
    size_t i;
4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807
    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;

4808 4809 4810 4811 4812 4813 4814
    if (nnets > REMOTE_NETWORK_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many networks '%d' for limit '%d'"),
                       nnets, REMOTE_NETWORK_LIST_MAX);
        goto cleanup;
    }

4815
    if (nets && nnets) {
4816
        if (VIR_ALLOC_N(ret->nets.nets_val, nnets) < 0)
4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831
            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;

4832
 cleanup:
4833 4834
    if (rv < 0)
        virNetMessageSaveError(rerr);
4835
    if (nets && nnets > 0)
4836
        for (i = 0; i < nnets; i++)
4837
            virObjectUnref(nets[i]);
4838
    VIR_FREE(nets);
4839 4840 4841
    return rv;
}

4842 4843 4844 4845 4846 4847 4848 4849 4850 4851
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;
4852
    size_t i;
4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865
    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;

4866 4867 4868 4869 4870 4871 4872
    if (nifaces > REMOTE_INTERFACE_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many interfaces '%d' for limit '%d'"),
                       nifaces, REMOTE_INTERFACE_LIST_MAX);
        goto cleanup;
    }

4873
    if (ifaces && nifaces) {
4874
        if (VIR_ALLOC_N(ret->ifaces.ifaces_val, nifaces) < 0)
4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889
            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;

4890
 cleanup:
4891 4892
    if (rv < 0)
        virNetMessageSaveError(rerr);
4893
    if (ifaces && nifaces > 0)
4894
        for (i = 0; i < nifaces; i++)
4895
            virObjectUnref(ifaces[i]);
4896
    VIR_FREE(ifaces);
4897 4898 4899
    return rv;
}

4900 4901 4902 4903 4904 4905 4906 4907 4908 4909
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;
4910
    size_t i;
4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923
    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;

4924 4925 4926 4927 4928 4929 4930
    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;
    }

4931
    if (devices && ndevices) {
4932
        if (VIR_ALLOC_N(ret->devices.devices_val, ndevices) < 0)
4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947
            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;

4948
 cleanup:
4949 4950
    if (rv < 0)
        virNetMessageSaveError(rerr);
4951
    if (devices && ndevices > 0)
4952
        for (i = 0; i < ndevices; i++)
4953
            virObjectUnref(devices[i]);
4954
    VIR_FREE(devices);
4955 4956
    return rv;
}
4957

4958 4959 4960 4961 4962 4963 4964 4965 4966 4967
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;
4968
    size_t i;
4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981
    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;

4982 4983 4984 4985 4986 4987 4988
    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;
    }

4989
    if (filters && nfilters) {
4990
        if (VIR_ALLOC_N(ret->filters.filters_val, nfilters) < 0)
4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005
            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;

5006
 cleanup:
5007 5008
    if (rv < 0)
        virNetMessageSaveError(rerr);
5009
    if (filters && nfilters > 0)
5010
        for (i = 0; i < nfilters; i++)
5011
            virObjectUnref(filters[i]);
5012
    VIR_FREE(filters);
5013 5014 5015
    return rv;
}

5016 5017 5018 5019 5020 5021 5022 5023 5024 5025
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;
5026
    size_t i;
5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039
    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;

5040 5041 5042 5043 5044 5045 5046
    if (nsecrets > REMOTE_SECRET_LIST_MAX) {
        virReportError(VIR_ERR_RPC,
                       _("Too many secrets '%d' for limit '%d'"),
                       nsecrets, REMOTE_SECRET_LIST_MAX);
        goto cleanup;
    }

5047
    if (secrets && nsecrets) {
5048
        if (VIR_ALLOC_N(ret->secrets.secrets_val, nsecrets) < 0)
5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063
            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;

5064
 cleanup:
5065 5066
    if (rv < 0)
        virNetMessageSaveError(rerr);
5067
    if (secrets && nsecrets > 0)
5068
        for (i = 0; i < nsecrets; i++)
5069
            virObjectUnref(secrets[i]);
5070
    VIR_FREE(secrets);
5071 5072 5073
    return rv;
}

5074 5075 5076 5077 5078 5079 5080 5081 5082
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;
5083
    int nparams = 0;
5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095
    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;

5096
    if (args->nparams > REMOTE_NODE_MEMORY_PARAMETERS_MAX) {
5097 5098 5099
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
        goto cleanup;
    }
5100
    if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0)
5101
        goto cleanup;
5102
    nparams = args->nparams;
5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120

    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;

5121
 success:
5122 5123
    rv = 0;

5124
 cleanup:
5125 5126
    if (rv < 0)
        virNetMessageSaveError(rerr);
5127
    virTypedParamsFree(params, nparams);
5128 5129 5130
    return rv;
}

5131 5132 5133 5134 5135 5136 5137 5138 5139
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;
5140
    unsigned int online = 0;
5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153
    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;

5154 5155
    cpunum = virNodeGetCPUMap(priv->conn, args->need_map ? &cpumap : NULL,
                              args->need_online ? &online : NULL, flags);
5156 5157 5158 5159
    if (cpunum < 0)
        goto cleanup;

    /* 'serialize' return cpumap */
5160
    if (args->need_map) {
5161 5162 5163 5164 5165 5166 5167 5168 5169 5170
        ret->cpumap.cpumap_len = VIR_CPU_MAPLEN(cpunum);
        ret->cpumap.cpumap_val = (char *) cpumap;
        cpumap = NULL;
    }

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

    rv = 0;

5171
 cleanup:
5172 5173 5174 5175 5176 5177
    if (rv < 0)
        virNetMessageSaveError(rerr);
    VIR_FREE(cpumap);
    return rv;
}

5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210
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
     */
5211
    for (i = 0; i < msg->nfds; i++)
5212 5213 5214 5215 5216 5217 5218 5219 5220
        VIR_FORCE_CLOSE(msg->fds[i]);
    VIR_FREE(msg->fds);
    msg->nfds = 0;

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

    rv = 1;

5221
 cleanup:
5222 5223
    if (rv < 0)
        virNetMessageSaveError(rerr);
5224
    virObjectUnref(dom);
5225 5226 5227
    return rv;
}

5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254
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;

5255 5256 5257 5258 5259 5260 5261
    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;
    }

5262 5263 5264 5265 5266 5267 5268 5269
    if (remoteSerializeTypedParameters(params, nparams,
                                       &ret->params.params_val,
                                       &ret->params.params_len,
                                       0) < 0)
        goto cleanup;

    rv = 0;

5270
 cleanup:
5271 5272 5273
    if (rv < 0)
        virNetMessageSaveError(rerr);
    virTypedParamsFree(params, nparams);
5274
    virObjectUnref(dom);
5275 5276 5277
    return rv;
}

5278
static int
5279 5280 5281 5282 5283 5284
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)
5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300
{
    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;
    }

5301 5302 5303 5304 5305 5306 5307
    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;
    }

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

5311 5312 5313
    if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
                                  args->params.params_len,
                                  0, &params, &nparams) < 0)
5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326
        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;

5327
 cleanup:
5328 5329 5330
    virTypedParamsFree(params, nparams);
    if (rv < 0)
        virNetMessageSaveError(rerr);
5331
    virObjectUnref(dom);
5332 5333 5334 5335
    return rv;
}

static int
5336 5337 5338 5339 5340 5341
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)
5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356
{
    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;
    }

5357 5358 5359 5360 5361 5362 5363
    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;
    }

5364 5365 5366
    if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
                                  args->params.params_len,
                                  0, &params, &nparams) < 0)
5367 5368 5369
        goto cleanup;

    /* Wacky world of XDR ... */
5370
    if (VIR_ALLOC(uri_out) < 0)
5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385
        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;

5386
 cleanup:
5387 5388 5389 5390 5391 5392 5393 5394 5395
    virTypedParamsFree(params, nparams);
    if (rv < 0) {
        virNetMessageSaveError(rerr);
        VIR_FREE(uri_out);
    }
    return rv;
}

static int
5396 5397 5398 5399 5400 5401
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)
5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417
{
    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;
    }

5418 5419 5420 5421 5422 5423 5424
    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;
    }

5425 5426 5427
    if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
                                  args->params.params_len,
                                  0, &params, &nparams) < 0)
5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448
        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;

5449
 cleanup:
5450 5451 5452 5453 5454 5455 5456 5457
    virTypedParamsFree(params, nparams);
    if (rv < 0) {
        virNetMessageSaveError(rerr);
        VIR_FREE(cookieout);
        if (stream) {
            virStreamAbort(st);
            daemonFreeClientStream(client, stream);
        } else {
5458
            virObjectUnref(st);
5459 5460 5461 5462 5463 5464 5465
        }
    }
    return rv;
}


static int
5466 5467 5468 5469 5470 5471
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)
5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487
{
    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;
    }

5488 5489 5490 5491 5492 5493 5494
    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;
    }

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

5498 5499 5500
    if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
                                  args->params.params_len,
                                  0, &params, &nparams) < 0)
5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516
        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;

5517
 cleanup:
5518 5519 5520
    virTypedParamsFree(params, nparams);
    if (rv < 0)
        virNetMessageSaveError(rerr);
5521
    virObjectUnref(dom);
5522 5523 5524 5525 5526
    return rv;
}


static int
5527 5528 5529 5530 5531 5532
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)
5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547
{
    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;
    }

5548 5549 5550 5551 5552 5553 5554
    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;
    }

5555 5556 5557
    if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
                                  args->params.params_len,
                                  0, &params, &nparams) < 0)
5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574
        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;

5575
 cleanup:
5576 5577 5578 5579 5580
    virTypedParamsFree(params, nparams);
    if (rv < 0) {
        virNetMessageSaveError(rerr);
        VIR_FREE(cookieout);
    }
5581
    virObjectUnref(dom);
5582 5583 5584 5585 5586
    return rv;
}


static int
5587 5588 5589 5590 5591
remoteDispatchDomainMigrateConfirm3Params(virNetServerPtr server ATTRIBUTE_UNUSED,
                                          virNetServerClientPtr client ATTRIBUTE_UNUSED,
                                          virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                          virNetMessageErrorPtr rerr,
                                          remote_domain_migrate_confirm3_params_args *args)
5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604
{
    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;
    }

5605 5606 5607 5608 5609 5610 5611
    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;
    }

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

5615 5616 5617
    if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
                                  args->params.params_len,
                                  0, &params, &nparams) < 0)
5618 5619 5620 5621 5622 5623 5624 5625 5626 5627
        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;

5628
 cleanup:
5629 5630 5631
    virTypedParamsFree(params, nparams);
    if (rv < 0)
        virNetMessageSaveError(rerr);
5632
    virObjectUnref(dom);
5633 5634 5635 5636
    return rv;
}


5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680
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;

5681
 cleanup:
5682 5683 5684 5685 5686 5687 5688
    if (rv < 0)
        virNetMessageSaveError(rerr);
    virStringFreeList(models);
    return rv;
}


5689 5690 5691 5692 5693 5694 5695
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)
5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725
{
    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;

5726
 cleanup:
5727
    for (i = 0; i < nfiles; i++)
5728 5729 5730 5731
        VIR_FORCE_CLOSE(files[i]);
    VIR_FREE(files);
    if (rv < 0)
        virNetMessageSaveError(rerr);
5732
    virObjectUnref(dom);
5733 5734 5735 5736
    return rv;
}


5737 5738 5739 5740 5741 5742
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)
5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775
{
    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;

5776
 cleanup:
5777
    for (i = 0; i < nfiles; i++)
5778 5779 5780 5781
        VIR_FORCE_CLOSE(files[i]);
    VIR_FREE(files);
    if (rv < 0)
        virNetMessageSaveError(rerr);
5782
    virObjectUnref(dom);
5783 5784 5785 5786
    return rv;
}


5787 5788
static int
remoteDispatchConnectNetworkEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
5789
                                             virNetServerClientPtr client,
5790 5791 5792
                                             virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                             virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
                                             remote_connect_network_event_register_any_args *args,
5793
                                             remote_connect_network_event_register_any_ret *ret)
5794 5795 5796
{
    int callbackID;
    int rv = -1;
5797 5798
    daemonClientEventCallbackPtr callback = NULL;
    daemonClientEventCallbackPtr ref;
5799 5800
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);
5801
    virNetworkPtr net = NULL;
5802 5803 5804 5805 5806 5807 5808 5809

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

    virMutexLock(&priv->lock);

5810 5811 5812 5813
    if (args->net &&
        !(net = get_nonnull_network(priv->conn, *args->net)))
        goto cleanup;

5814 5815 5816
    if (args->eventID >= VIR_NETWORK_EVENT_ID_LAST || args->eventID < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unsupported network event ID %d"), args->eventID);
5817 5818 5819
        goto cleanup;
    }

5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834
    /* 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)
5835 5836 5837
        goto cleanup;

    if ((callbackID = virConnectNetworkEventRegisterAny(priv->conn,
5838
                                                        net,
5839 5840
                                                        args->eventID,
                                                        networkEventCallbacks[args->eventID],
5841 5842 5843 5844 5845
                                                        ref,
                                                        remoteEventCallbackFree)) < 0) {
        VIR_SHRINK_N(priv->networkEventCallbacks,
                     priv->nnetworkEventCallbacks, 1);
        callback = ref;
5846
        goto cleanup;
5847
    }
5848

5849
    ref->callbackID = callbackID;
5850
    ret->callbackID = callbackID;
5851 5852 5853

    rv = 0;

5854
 cleanup:
5855
    VIR_FREE(callback);
5856 5857
    if (rv < 0)
        virNetMessageSaveError(rerr);
5858
    virObjectUnref(net);
5859 5860 5861 5862 5863 5864 5865
    virMutexUnlock(&priv->lock);
    return rv;
}


static int
remoteDispatchConnectNetworkEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
5866
                                               virNetServerClientPtr client,
5867 5868
                                               virNetMessagePtr msg ATTRIBUTE_UNUSED,
                                               virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
5869
                                               remote_connect_network_event_deregister_any_args *args)
5870 5871
{
    int rv = -1;
5872
    size_t i;
5873 5874 5875 5876 5877 5878 5879 5880 5881 5882
    struct daemonClientPrivate *priv =
        virNetServerClientGetPrivateData(client);

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

    virMutexLock(&priv->lock);

5883
    for (i = 0; i < priv->nnetworkEventCallbacks; i++) {
5884
        if (priv->networkEventCallbacks[i]->callbackID == args->callbackID)
5885 5886
            break;
    }
5887
    if (i == priv->nnetworkEventCallbacks) {
5888
        virReportError(VIR_ERR_INTERNAL_ERROR,
5889 5890
                       _("network event callback %d not registered"),
                       args->callbackID);
5891 5892 5893
        goto cleanup;
    }

5894
    if (virConnectNetworkEventDeregisterAny(priv->conn, args->callbackID) < 0)
5895 5896
        goto cleanup;

5897 5898
    VIR_DELETE_ELEMENT(priv->networkEventCallbacks, i,
                       priv->nnetworkEventCallbacks);
5899 5900 5901

    rv = 0;

5902
 cleanup:
5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 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
    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;

5972
 cleanup:
5973 5974 5975
    VIR_FREE(callback);
    if (rv < 0)
        virNetMessageSaveError(rerr);
5976
    virObjectUnref(dom);
5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020
    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;

6021
 cleanup:
6022 6023 6024 6025 6026 6027
    if (rv < 0)
        virNetMessageSaveError(rerr);
    virMutexUnlock(&priv->lock);
    return rv;
}

6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060
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);
6061
    virObjectUnref(dom);
6062 6063
    return rv;
}
6064

M
Michal Privoznik 已提交
6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 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

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;
6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127
}

/* 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;

6128
    if (VIR_STRDUP(lease_dst->iface, lease_src->iface) < 0 ||
J
Ján Tomko 已提交
6129
        VIR_STRDUP(lease_dst->ipaddr, lease_src->ipaddr) < 0)
6130 6131
        goto error;

J
Ján Tomko 已提交
6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156
    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;
6157 6158 6159 6160

    return 0;

 error:
J
Ján Tomko 已提交
6161 6162 6163 6164 6165 6166 6167 6168
    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);
6169 6170 6171 6172 6173
    VIR_FREE(mac_tmp);
    VIR_FREE(iaid_tmp);
    VIR_FREE(hostname_tmp);
    VIR_FREE(clientid_tmp);
    VIR_FREE(lease_dst->ipaddr);
6174
    VIR_FREE(lease_dst->iface);
6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202
    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,
6203
                                           args->mac ? *args->mac : NULL,
6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237
                                           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);
6238
    if (leases && nleases > 0)
6239 6240
        for (i = 0; i < nleases; i++)
            virNetworkDHCPLeaseFree(leases[i]);
6241
    VIR_FREE(leases);
6242
    virObjectUnref(net);
6243
    return rv;
M
Michal Privoznik 已提交
6244 6245 6246
}


6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 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
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);
6327
    virObjectListFree(doms);
6328 6329 6330 6331 6332

    return rv;
}


M
Michal Privoznik 已提交
6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369
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;
}


6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 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
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);
        }
    }
6473
    virObjectUnref(dom);
6474 6475 6476 6477 6478 6479 6480 6481 6482
    if (ninfo >= 0)
        for (i = 0; i < ninfo; i++)
            virDomainFSInfoFree(info[i]);
    VIR_FREE(info);

    return rv;
}


6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508
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;

6509 6510 6511
        if (iface->hwaddr &&
            (VIR_ALLOC(iface_ret->hwaddr) < 0 ||
             VIR_STRDUP(*iface_ret->hwaddr, iface->hwaddr) < 0))
6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546
            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);
6547 6548 6549 6550
            if (iface_ret->hwaddr) {
                VIR_FREE(*iface_ret->hwaddr);
                VIR_FREE(iface_ret->hwaddr);
            }
6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611
            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;
}


6612 6613 6614 6615 6616 6617 6618 6619 6620
/*----- 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
6621
get_nonnull_domain(virConnectPtr conn, remote_nonnull_domain domain)
6622 6623
{
    virDomainPtr dom;
6624
    dom = virGetDomain(conn, domain.name, BAD_CAST domain.uuid);
6625 6626 6627 6628 6629 6630 6631 6632
    /* 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
6633
get_nonnull_network(virConnectPtr conn, remote_nonnull_network network)
6634
{
6635
    return virGetNetwork(conn, network.name, BAD_CAST network.uuid);
6636 6637
}

D
Daniel Veillard 已提交
6638
static virInterfacePtr
6639
get_nonnull_interface(virConnectPtr conn, remote_nonnull_interface iface)
D
Daniel Veillard 已提交
6640
{
6641
    return virGetInterface(conn, iface.name, iface.mac);
D
Daniel Veillard 已提交
6642 6643
}

6644
static virStoragePoolPtr
6645
get_nonnull_storage_pool(virConnectPtr conn, remote_nonnull_storage_pool pool)
6646
{
6647 6648
    return virGetStoragePool(conn, pool.name, BAD_CAST pool.uuid,
                             NULL, NULL);
6649 6650 6651
}

static virStorageVolPtr
6652
get_nonnull_storage_vol(virConnectPtr conn, remote_nonnull_storage_vol vol)
6653 6654
{
    virStorageVolPtr ret;
6655 6656
    ret = virGetStorageVol(conn, vol.pool, vol.name, vol.key,
                           NULL, NULL);
6657 6658 6659
    return ret;
}

6660
static virSecretPtr
6661
get_nonnull_secret(virConnectPtr conn, remote_nonnull_secret secret)
6662
{
6663
    return virGetSecret(conn, BAD_CAST secret.uuid, secret.usageType, secret.usageID);
6664 6665
}

6666
static virNWFilterPtr
6667
get_nonnull_nwfilter(virConnectPtr conn, remote_nonnull_nwfilter nwfilter)
6668
{
6669
    return virGetNWFilter(conn, nwfilter.name, BAD_CAST nwfilter.uuid);
6670 6671
}

C
Chris Lalancette 已提交
6672
static virDomainSnapshotPtr
6673
get_nonnull_domain_snapshot(virDomainPtr dom, remote_nonnull_domain_snapshot snapshot)
C
Chris Lalancette 已提交
6674
{
6675
    return virGetDomainSnapshot(dom, snapshot.name);
C
Chris Lalancette 已提交
6676 6677
}

6678 6679
/* Make remote_nonnull_domain and remote_nonnull_network. */
static void
6680
make_nonnull_domain(remote_nonnull_domain *dom_dst, virDomainPtr dom_src)
6681 6682
{
    dom_dst->id = dom_src->id;
6683
    ignore_value(VIR_STRDUP_QUIET(dom_dst->name, dom_src->name));
6684
    memcpy(dom_dst->uuid, dom_src->uuid, VIR_UUID_BUFLEN);
6685 6686 6687
}

static void
6688
make_nonnull_network(remote_nonnull_network *net_dst, virNetworkPtr net_src)
6689
{
6690
    ignore_value(VIR_STRDUP_QUIET(net_dst->name, net_src->name));
6691
    memcpy(net_dst->uuid, net_src->uuid, VIR_UUID_BUFLEN);
6692 6693
}

D
Daniel Veillard 已提交
6694
static void
6695 6696
make_nonnull_interface(remote_nonnull_interface *interface_dst,
                       virInterfacePtr interface_src)
D
Daniel Veillard 已提交
6697
{
6698 6699
    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 已提交
6700 6701
}

6702
static void
6703
make_nonnull_storage_pool(remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr pool_src)
6704
{
6705
    ignore_value(VIR_STRDUP_QUIET(pool_dst->name, pool_src->name));
6706
    memcpy(pool_dst->uuid, pool_src->uuid, VIR_UUID_BUFLEN);
6707 6708 6709
}

static void
6710
make_nonnull_storage_vol(remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src)
6711
{
6712 6713 6714
    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));
6715
}
6716 6717

static void
6718
make_nonnull_node_device(remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src)
6719
{
6720
    ignore_value(VIR_STRDUP_QUIET(dev_dst->name, dev_src->name));
6721
}
6722 6723

static void
6724
make_nonnull_secret(remote_nonnull_secret *secret_dst, virSecretPtr secret_src)
6725
{
6726
    memcpy(secret_dst->uuid, secret_src->uuid, VIR_UUID_BUFLEN);
6727
    secret_dst->usageType = secret_src->usageType;
6728
    ignore_value(VIR_STRDUP_QUIET(secret_dst->usageID, secret_src->usageID));
6729
}
6730 6731

static void
6732
make_nonnull_nwfilter(remote_nonnull_nwfilter *nwfilter_dst, virNWFilterPtr nwfilter_src)
6733
{
6734
    ignore_value(VIR_STRDUP_QUIET(nwfilter_dst->name, nwfilter_src->name));
6735
    memcpy(nwfilter_dst->uuid, nwfilter_src->uuid, VIR_UUID_BUFLEN);
6736
}
C
Chris Lalancette 已提交
6737 6738

static void
6739
make_nonnull_domain_snapshot(remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src)
C
Chris Lalancette 已提交
6740
{
6741
    ignore_value(VIR_STRDUP_QUIET(snapshot_dst->name, snapshot_src->name));
6742
    make_nonnull_domain(&snapshot_dst->dom, snapshot_src->domain);
C
Chris Lalancette 已提交
6743
}
6744 6745 6746 6747 6748 6749 6750 6751

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;
6752
    size_t i = 0;
6753

6754
    if (VIR_ALLOC_N(val, nerrors) < 0)
6755
        goto error;
6756 6757

    for (i = 0; i < nerrors; i++) {
6758 6759
        if (VIR_STRDUP(val[i].disk, errors[i].disk) < 0)
            goto error;
6760 6761 6762 6763 6764 6765 6766 6767
        val[i].error = errors[i].error;
    }

    *ret_errors_len = nerrors;
    *ret_errors_val = val;

    return 0;

6768
 error:
6769
    if (val) {
6770
        size_t j;
6771 6772 6773 6774 6775 6776
        for (j = 0; j < i; j++)
            VIR_FREE(val[j].disk);
        VIR_FREE(val);
    }
    return -1;
}