~serge-hallyn/ubuntu/raring/libvirt/libvirt-hugepages

« back to all changes in this revision

Viewing changes to daemon/dispatch.c

  • Committer: James Westby
  • Author(s): Jamie Strandboge
  • Date: 2009-12-02 14:22:21 UTC
  • mfrom: (1.2.3 upstream) (3.4.9 squeeze)
  • Revision ID: james.westby@canonical.com-20091202142221-ltkr0to6h52mla1y
Tags: 0.7.2-4ubuntu1
* Merge from debian testing. Remaining changes:
  - debian/control:
    + Don't build-depend on QEmu
    + Bump bridge-utils, dnsmasq-base, netcat-openbsd, and iptables
      to Depends of libvirt-bin
    + Recommends qemu-kvm (>= 0.11.0-0ubuntu6)
    + Add versioned Conflicts/Replaces to libvirt0 for libvirt0-dbg,
      since we used to ship them as such
    + We call libxen-dev libxen3-dev, so change all references
    + Build-Depends on libxml2-utils
    + Build-Depends on open-iscsi-utils instead of open-iscsi due to
      LP: #414986
  - debian/postinst:
    + rename the libvirt group to libvirtd
    + add each admin user to the libvirtd group
  - debian/libvirt-bin.postrm: rename the libvirt group to libvirtd
  - debian/rules: add DEB_MAKE_CHECK_TARGET := check
  - debian/patches/900[0-7]: updated/refreshed for new paths in 0.7.2
  - debian/patches/series: don't apply 0002-qemu-disable-network.diff.patch
  - AppArmor integration:
    + debian/control: Build-Depends on libapparmor-dev and Suggests
      apparmor (>= 2.3+1289-0ubuntu14)
    + debian/libvirt-bin.dirs: add /etc/apparmor.d/abstractions,
      /etc/apparmor.d/force-complain, /etc/apparmor.d/libvirt,
      /etc/cron.daily and /usr/share/apport/package-hooks
    + add debian/libvirt-bin.cron.daily (LP: #438165)
    + add debian/libvirt-bin.apport
    + debian/libvirt-bin.install: install apparmor profiles, abstractions
      and apport hook
    + debian/postinst: reload apparmor profiles
    + debian/libvirt-bin.postrm: remove apparmor symlinks on purge
    + debian/libvirt-bin.preinst: added to force complain on certain
      upgrades
    + debian/README.Debian: add AppArmor section based on the upstream
      documentation
    + debian/rules: use --with-apparmor and copy apparmor and apport hook to
      debian/tmp
  - Dropped the following patches now included upstream:
    + 0005-Close-logfile-fd-after-spawning-qemu.patch
    + 9090-reenable-nonfile-labels.patch
    + 9091-apparmor.patch
    + 9092-apparmor-autoreconf.patch
* AppArmor integration updates:
  - debian/apparmor/usr.sbin.libvirtd: allow libvirtd access to
    /usr/lib/libvirt/* (LP: #480478)
  - debian/apparmor/libvirt-qemu: allow guests access to
    /etc/pki/libvirt-vnc/** (LP: #484562)
  - debian/libvirt-bin.postinst: 0.7.2 moved /usr/bin/virt-aa-helper to
    /usr/lib/libvirt, so the profile changed from usr.bin.virt-aa-helper
    to usr.lib.libvirt.virt-aa-helper and needs to be migrated. If the user
    made no changes to the old profile, remove it, otherwise, update the
    paths, preserving the shipped usr.lib.libvirt.virt-aa-helper
  - update to 0.7.4 version of the sVirt AppArmor driver (can be dropped in
    0.7.4):
    + debian/patches/9008-apparmor-caps-mockup.patch
    + debian/patches/9009-apparmor-lp453335.patch
    + debian/patches/9010-apparmor-lp460271.patch
    + debian/patches/9011-apparmor-code-cleanups.patch
  - add virt-aa-helper-test and examples/apparmor that were omitted from the
    upstream tarball (can be dropped in 0.7.5):
    + debian/patches/9012-apparmor-add-virt-aa-helper-test.patch
    + debian/patches/9013-apparmor-examples.patch
    + debian/rules: add post-patches target to make virt-aa-helper-test
      executable
* debian/patches/0005-Fix-SELinux-linking-issues.patch: updated to work
  when both apparmor and selinux are available. This patch should be
  dropped in 0.7.4.
* debian/patches/9007-default-config-test-case.patch: updated to not fail
  if building in a deep directory
* debian/patches/9014-event-fuzz.patch: add a little fuzz to not be quite
  so precise with expected expiry time. Fixes FTBFS with HZ=100 kernels.
  Can be dropped in 0.7.5.
* debian/patches/9015-hal-startup-failure-is-nonfatal.patch: disable hal
  driver if hald is not running instead of dying. Can be dropped in
  0.7.4.
* debian/control: temporarily remove Build-Depends on libcap-ng-dev, which
  isn't available in Ubuntu main yet
* revert change to new source format 3.0 (quilt) since Launchpad can't
  handle it yet (see LP: #293106)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * dispatch.h: RPC message dispatching infrastructure
 
3
 *
 
4
 * Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Lesser General Public
 
8
 * License as published by the Free Software Foundation; either
 
9
 * version 2.1 of the License, or (at your option) any later version.
 
10
 *
 
11
 * This library is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 * Lesser General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Lesser General Public
 
17
 * License along with this library; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 
19
 *
 
20
 * Author: Richard W.M. Jones <rjones@redhat.com>
 
21
 * Author: Daniel P. Berrange <berrange@redhat.com>
 
22
 */
 
23
 
 
24
#include <config.h>
 
25
 
 
26
#include "dispatch.h"
 
27
#include "remote.h"
 
28
 
 
29
#include "memory.h"
 
30
 
 
31
/* Convert a libvirt  virError object into wire format */
 
32
static void
 
33
remoteDispatchCopyError (remote_error *rerr,
 
34
                         virErrorPtr verr)
 
35
{
 
36
    rerr->code = verr->code;
 
37
    rerr->domain = verr->domain;
 
38
    rerr->message = verr->message ? malloc(sizeof(char*)) : NULL;
 
39
    if (rerr->message) *rerr->message = strdup(verr->message);
 
40
    rerr->level = verr->level;
 
41
    rerr->str1 = verr->str1 ? malloc(sizeof(char*)) : NULL;
 
42
    if (rerr->str1) *rerr->str1 = strdup(verr->str1);
 
43
    rerr->str2 = verr->str2 ? malloc(sizeof(char*)) : NULL;
 
44
    if (rerr->str2) *rerr->str2 = strdup(verr->str2);
 
45
    rerr->str3 = verr->str3 ? malloc(sizeof(char*)) : NULL;
 
46
    if (rerr->str3) *rerr->str3 = strdup(verr->str3);
 
47
    rerr->int1 = verr->int1;
 
48
    rerr->int2 = verr->int2;
 
49
}
 
50
 
 
51
 
 
52
/* A set of helpers for sending back errors to client
 
53
   in various ways .... */
 
54
 
 
55
static void
 
56
remoteDispatchStringError (remote_error *rerr,
 
57
                           int code, const char *msg)
 
58
{
 
59
    virError verr;
 
60
 
 
61
    memset(&verr, 0, sizeof verr);
 
62
 
 
63
    /* Construct the dummy libvirt virError. */
 
64
    verr.code = code;
 
65
    verr.domain = VIR_FROM_REMOTE;
 
66
    verr.message = (char *)msg;
 
67
    verr.level = VIR_ERR_ERROR;
 
68
    verr.str1 = (char *)msg;
 
69
 
 
70
    remoteDispatchCopyError(rerr, &verr);
 
71
}
 
72
 
 
73
 
 
74
void remoteDispatchAuthError (remote_error *rerr)
 
75
{
 
76
    remoteDispatchStringError (rerr, VIR_ERR_AUTH_FAILED, "authentication failed");
 
77
}
 
78
 
 
79
 
 
80
void remoteDispatchFormatError (remote_error *rerr,
 
81
                                const char *fmt, ...)
 
82
{
 
83
    va_list args;
 
84
    char msgbuf[1024];
 
85
    char *msg = msgbuf;
 
86
 
 
87
    va_start (args, fmt);
 
88
    vsnprintf (msgbuf, sizeof msgbuf, fmt, args);
 
89
    va_end (args);
 
90
 
 
91
    remoteDispatchStringError (rerr, VIR_ERR_RPC, msg);
 
92
}
 
93
 
 
94
 
 
95
void remoteDispatchGenericError (remote_error *rerr)
 
96
{
 
97
    remoteDispatchStringError(rerr,
 
98
                              VIR_ERR_INTERNAL_ERROR,
 
99
                              "library function returned error but did not set virterror");
 
100
}
 
101
 
 
102
 
 
103
void remoteDispatchOOMError (remote_error *rerr)
 
104
{
 
105
    remoteDispatchStringError(rerr,
 
106
                              VIR_ERR_NO_MEMORY,
 
107
                              "out of memory");
 
108
}
 
109
 
 
110
 
 
111
void remoteDispatchConnError (remote_error *rerr,
 
112
                              virConnectPtr conn)
 
113
{
 
114
    virErrorPtr verr;
 
115
 
 
116
    if (conn)
 
117
        verr = virConnGetLastError(conn);
 
118
    else
 
119
        verr = virGetLastError();
 
120
    if (verr)
 
121
        remoteDispatchCopyError(rerr, verr);
 
122
    else
 
123
        remoteDispatchGenericError(rerr);
 
124
}
 
125
 
 
126
static int
 
127
remoteSerializeError(struct qemud_client *client,
 
128
                     remote_error *rerr,
 
129
                     int program,
 
130
                     int version,
 
131
                     int procedure,
 
132
                     int type,
 
133
                     int serial)
 
134
{
 
135
    XDR xdr;
 
136
    unsigned int len;
 
137
    struct qemud_client_message *msg = NULL;
 
138
 
 
139
    DEBUG("prog=%d ver=%d proc=%d type=%d serial=%d, msg=%s",
 
140
          program, version, procedure, type, serial,
 
141
          rerr->message ? *rerr->message : "(none)");
 
142
 
 
143
    if (VIR_ALLOC(msg) < 0)
 
144
        goto fatal_error;
 
145
 
 
146
    /* Return header. */
 
147
    msg->hdr.prog = program;
 
148
    msg->hdr.vers = version;
 
149
    msg->hdr.proc = procedure;
 
150
    msg->hdr.type = type;
 
151
    msg->hdr.serial = serial;
 
152
    msg->hdr.status = REMOTE_ERROR;
 
153
 
 
154
    msg->bufferLength = sizeof(msg->buffer);
 
155
 
 
156
    /* Serialise the return header. */
 
157
    xdrmem_create (&xdr,
 
158
                   msg->buffer,
 
159
                   msg->bufferLength,
 
160
                   XDR_ENCODE);
 
161
 
 
162
    len = 0; /* We'll come back and write this later. */
 
163
    if (!xdr_u_int (&xdr, &len))
 
164
        goto xdr_error;
 
165
 
 
166
    if (!xdr_remote_message_header (&xdr, &msg->hdr))
 
167
        goto xdr_error;
 
168
 
 
169
    /* Error was not set, so synthesize a generic error message. */
 
170
    if (rerr->code == 0)
 
171
        remoteDispatchGenericError(rerr);
 
172
 
 
173
    if (!xdr_remote_error (&xdr, rerr))
 
174
        goto xdr_error;
 
175
 
 
176
    /* Write the length word. */
 
177
    len = xdr_getpos (&xdr);
 
178
    if (xdr_setpos (&xdr, 0) == 0)
 
179
        goto xdr_error;
 
180
 
 
181
    if (!xdr_u_int (&xdr, &len))
 
182
        goto xdr_error;
 
183
 
 
184
    xdr_destroy (&xdr);
 
185
 
 
186
    msg->bufferLength = len;
 
187
    msg->bufferOffset = 0;
 
188
 
 
189
    /* Put reply on end of tx queue to send out  */
 
190
    qemudClientMessageQueuePush(&client->tx, msg);
 
191
    qemudUpdateClientEvent(client);
 
192
    xdr_free((xdrproc_t)xdr_remote_error,  (char *)rerr);
 
193
 
 
194
    return 0;
 
195
 
 
196
xdr_error:
 
197
    xdr_destroy(&xdr);
 
198
    VIR_FREE(msg);
 
199
fatal_error:
 
200
    xdr_free((xdrproc_t)xdr_remote_error,  (char *)rerr);
 
201
    return -1;
 
202
}
 
203
 
 
204
 
 
205
/*
 
206
 * @client: the client to send the error to
 
207
 * @rerr: the error object to send
 
208
 * @req: the message this error is in reply to
 
209
 *
 
210
 * Send an error message to the client
 
211
 *
 
212
 * Returns 0 if the error was sent, -1 upon fatal error
 
213
 */
 
214
int
 
215
remoteSerializeReplyError(struct qemud_client *client,
 
216
                          remote_error *rerr,
 
217
                          remote_message_header *req) {
 
218
    /*
 
219
     * For data streams, errors are sent back as data streams
 
220
     * For method calls, errors are sent back as method replies
 
221
     */
 
222
    return remoteSerializeError(client,
 
223
                                rerr,
 
224
                                req->prog,
 
225
                                req->vers,
 
226
                                req->proc,
 
227
                                req->type == REMOTE_STREAM ? REMOTE_STREAM : REMOTE_REPLY,
 
228
                                req->serial);
 
229
}
 
230
 
 
231
int
 
232
remoteSerializeStreamError(struct qemud_client *client,
 
233
                           remote_error *rerr,
 
234
                           int proc,
 
235
                           int serial)
 
236
{
 
237
    return remoteSerializeError(client,
 
238
                                rerr,
 
239
                                REMOTE_PROGRAM,
 
240
                                REMOTE_PROTOCOL_VERSION,
 
241
                                proc,
 
242
                                REMOTE_STREAM,
 
243
                                serial);
 
244
}
 
245
 
 
246
/*
 
247
 * @msg: the complete incoming message, whose header to decode
 
248
 *
 
249
 * Decodes the header part of the client message, but does not
 
250
 * validate the decoded fields in the header. It expects
 
251
 * bufferLength to refer to length of the data packet. Upon
 
252
 * return bufferOffset will refer to the amount of the packet
 
253
 * consumed by decoding of the header.
 
254
 *
 
255
 * returns 0 if successfully decoded, -1 upon fatal error
 
256
 */
 
257
int
 
258
remoteDecodeClientMessageHeader (struct qemud_client_message *msg)
 
259
{
 
260
    XDR xdr;
 
261
    int ret = -1;
 
262
 
 
263
    msg->bufferOffset = REMOTE_MESSAGE_HEADER_XDR_LEN;
 
264
 
 
265
    /* Parse the header. */
 
266
    xdrmem_create (&xdr,
 
267
                   msg->buffer + msg->bufferOffset,
 
268
                   msg->bufferLength - msg->bufferOffset,
 
269
                   XDR_DECODE);
 
270
 
 
271
    if (!xdr_remote_message_header (&xdr, &msg->hdr))
 
272
        goto cleanup;
 
273
 
 
274
    msg->bufferOffset += xdr_getpos(&xdr);
 
275
 
 
276
    ret = 0;
 
277
 
 
278
cleanup:
 
279
    xdr_destroy(&xdr);
 
280
    return ret;
 
281
}
 
282
 
 
283
 
 
284
/*
 
285
 * @msg: the outgoing message, whose header to encode
 
286
 *
 
287
 * Encodes the header part of the client message, setting the
 
288
 * message offset ready to encode the payload. Leaves space
 
289
 * for the length field later. Upon return bufferLength will
 
290
 * refer to the total available space for message, while
 
291
 * bufferOffset will refer to current space used by header
 
292
 *
 
293
 * returns 0 if successfully encoded, -1 upon fatal error
 
294
 */
 
295
int
 
296
remoteEncodeClientMessageHeader (struct qemud_client_message *msg)
 
297
{
 
298
    XDR xdr;
 
299
    int ret = -1;
 
300
    unsigned int len = 0;
 
301
 
 
302
    msg->bufferLength = sizeof(msg->buffer);
 
303
    msg->bufferOffset = 0;
 
304
 
 
305
    /* Format the header. */
 
306
    xdrmem_create (&xdr,
 
307
                   msg->buffer,
 
308
                   msg->bufferLength,
 
309
                   XDR_ENCODE);
 
310
 
 
311
    /* The real value is filled in shortly */
 
312
    if (!xdr_u_int (&xdr, &len)) {
 
313
        goto cleanup;
 
314
    }
 
315
 
 
316
    if (!xdr_remote_message_header (&xdr, &msg->hdr))
 
317
        goto cleanup;
 
318
 
 
319
    len = xdr_getpos(&xdr);
 
320
    xdr_setpos(&xdr, 0);
 
321
 
 
322
    /* Fill in current length - may be re-written later
 
323
     * if a payload is added
 
324
     */
 
325
    if (!xdr_u_int (&xdr, &len)) {
 
326
        goto cleanup;
 
327
    }
 
328
 
 
329
    msg->bufferOffset += len;
 
330
 
 
331
    ret = 0;
 
332
 
 
333
cleanup:
 
334
    xdr_destroy(&xdr);
 
335
    return ret;
 
336
}
 
337
 
 
338
 
 
339
int
 
340
remoteDispatchClientCall (struct qemud_server *server,
 
341
                          struct qemud_client *client,
 
342
                          struct qemud_client_message *msg);
 
343
 
 
344
 
 
345
/*
 
346
 * @server: the unlocked server object
 
347
 * @client: the locked client object
 
348
 * @msg: the complete incoming message packet, with header already decoded
 
349
 *
 
350
 * This function gets called from qemud when it pulls a incoming
 
351
 * remote protocol messsage off the dispatch queue for processing.
 
352
 *
 
353
 * The @msg parameter must have had its header decoded already by
 
354
 * calling remoteDecodeClientMessageHeader
 
355
 *
 
356
 * Returns 0 if the message was dispatched, -1 upon fatal error
 
357
 */
 
358
int
 
359
remoteDispatchClientRequest (struct qemud_server *server,
 
360
                             struct qemud_client *client,
 
361
                             struct qemud_client_message *msg)
 
362
{
 
363
    int ret;
 
364
    remote_error rerr;
 
365
 
 
366
    DEBUG("prog=%d ver=%d type=%d satus=%d serial=%d proc=%d",
 
367
          msg->hdr.prog, msg->hdr.vers, msg->hdr.type,
 
368
          msg->hdr.status, msg->hdr.serial, msg->hdr.proc);
 
369
 
 
370
    memset(&rerr, 0, sizeof rerr);
 
371
 
 
372
    /* Check version, etc. */
 
373
    if (msg->hdr.prog != REMOTE_PROGRAM) {
 
374
        remoteDispatchFormatError (&rerr,
 
375
                                   _("program mismatch (actual %x, expected %x)"),
 
376
                                   msg->hdr.prog, REMOTE_PROGRAM);
 
377
        goto error;
 
378
    }
 
379
    if (msg->hdr.vers != REMOTE_PROTOCOL_VERSION) {
 
380
        remoteDispatchFormatError (&rerr,
 
381
                                   _("version mismatch (actual %x, expected %x)"),
 
382
                                   msg->hdr.vers, REMOTE_PROTOCOL_VERSION);
 
383
        goto error;
 
384
    }
 
385
 
 
386
    switch (msg->hdr.type) {
 
387
    case REMOTE_CALL:
 
388
        return remoteDispatchClientCall(server, client, msg);
 
389
 
 
390
    case REMOTE_STREAM:
 
391
        /* Since stream data is non-acked, async, we may continue to received
 
392
         * stream packets after we closed down a stream. Just drop & ignore
 
393
         * these.
 
394
         */
 
395
        VIR_INFO("Ignoring unexpected stream data serial=%d proc=%d status=%d",
 
396
                 msg->hdr.serial, msg->hdr.proc, msg->hdr.status);
 
397
        qemudClientMessageRelease(client, msg);
 
398
        break;
 
399
 
 
400
    default:
 
401
        remoteDispatchFormatError (&rerr, _("type (%d) != REMOTE_CALL"),
 
402
                                   (int) msg->hdr.type);
 
403
        goto error;
 
404
    }
 
405
 
 
406
    return 0;
 
407
 
 
408
error:
 
409
    ret = remoteSerializeReplyError(client, &rerr, &msg->hdr);
 
410
 
 
411
    if (ret >= 0)
 
412
        VIR_FREE(msg);
 
413
 
 
414
    return ret;
 
415
}
 
416
 
 
417
 
 
418
/*
 
419
 * @server: the unlocked server object
 
420
 * @client: the locked client object
 
421
 * @msg: the complete incoming method call, with header already decoded
 
422
 *
 
423
 * This method is used to dispatch an message representing an
 
424
 * incoming method call from a client. It decodes the payload
 
425
 * to obtain method call arguments, invokves the method and
 
426
 * then sends a reply packet with the return values
 
427
 *
 
428
 * Returns 0 if the reply was sent, or -1 upon fatal error
 
429
 */
 
430
int
 
431
remoteDispatchClientCall (struct qemud_server *server,
 
432
                          struct qemud_client *client,
 
433
                          struct qemud_client_message *msg)
 
434
{
 
435
    XDR xdr;
 
436
    remote_error rerr;
 
437
    dispatch_args args;
 
438
    dispatch_ret ret;
 
439
    const dispatch_data *data = NULL;
 
440
    int rv = -1;
 
441
    unsigned int len;
 
442
    virConnectPtr conn = NULL;
 
443
 
 
444
    memset(&args, 0, sizeof args);
 
445
    memset(&ret, 0, sizeof ret);
 
446
    memset(&rerr, 0, sizeof rerr);
 
447
 
 
448
    if (msg->hdr.status != REMOTE_OK) {
 
449
        remoteDispatchFormatError (&rerr, _("status (%d) != REMOTE_OK"),
 
450
                                   (int) msg->hdr.status);
 
451
        goto rpc_error;
 
452
    }
 
453
 
 
454
    /* If client is marked as needing auth, don't allow any RPC ops,
 
455
     * except for authentication ones
 
456
     */
 
457
    if (client->auth) {
 
458
        if (msg->hdr.proc != REMOTE_PROC_AUTH_LIST &&
 
459
            msg->hdr.proc != REMOTE_PROC_AUTH_SASL_INIT &&
 
460
            msg->hdr.proc != REMOTE_PROC_AUTH_SASL_START &&
 
461
            msg->hdr.proc != REMOTE_PROC_AUTH_SASL_STEP &&
 
462
            msg->hdr.proc != REMOTE_PROC_AUTH_POLKIT
 
463
            ) {
 
464
            /* Explicitly *NOT* calling  remoteDispatchAuthError() because
 
465
               we want back-compatability with libvirt clients which don't
 
466
               support the VIR_ERR_AUTH_FAILED error code */
 
467
            remoteDispatchFormatError (&rerr, "%s", _("authentication required"));
 
468
            goto rpc_error;
 
469
        }
 
470
    }
 
471
 
 
472
    data = remoteGetDispatchData(msg->hdr.proc);
 
473
 
 
474
    if (!data) {
 
475
        remoteDispatchFormatError (&rerr, _("unknown procedure: %d"),
 
476
                                   msg->hdr.proc);
 
477
        goto rpc_error;
 
478
    }
 
479
 
 
480
    /* De-serialize payload with args from the wire message */
 
481
    xdrmem_create (&xdr,
 
482
                   msg->buffer + msg->bufferOffset,
 
483
                   msg->bufferLength - msg->bufferOffset,
 
484
                   XDR_DECODE);
 
485
    if (!((data->args_filter)(&xdr, &args))) {
 
486
        xdr_destroy (&xdr);
 
487
        remoteDispatchFormatError (&rerr, "%s", _("parse args failed"));
 
488
        goto rpc_error;
 
489
    }
 
490
    xdr_destroy (&xdr);
 
491
 
 
492
    /* Call function. */
 
493
    conn = client->conn;
 
494
    virMutexUnlock(&client->lock);
 
495
 
 
496
    /*
 
497
     * When the RPC handler is called:
 
498
     *
 
499
     *  - Server object is unlocked
 
500
     *  - Client object is unlocked
 
501
     *
 
502
     * Without locking, it is safe to use:
 
503
     *
 
504
     *   'conn', 'rerr', 'args and 'ret'
 
505
     */
 
506
    rv = (data->fn)(server, client, conn, &msg->hdr, &rerr, &args, &ret);
 
507
 
 
508
    virMutexLock(&server->lock);
 
509
    virMutexLock(&client->lock);
 
510
    virMutexUnlock(&server->lock);
 
511
 
 
512
    xdr_free (data->args_filter, (char*)&args);
 
513
 
 
514
    if (rv < 0)
 
515
        goto rpc_error;
 
516
 
 
517
    /* Return header. We're re-using same message object, so
 
518
     * only need to tweak type/status fields */
 
519
    /*msg->hdr.prog = msg->hdr.prog;*/
 
520
    /*msg->hdr.vers = msg->hdr.vers;*/
 
521
    /*msg->hdr.proc = msg->hdr.proc;*/
 
522
    msg->hdr.type = REMOTE_REPLY;
 
523
    /*msg->hdr.serial = msg->hdr.serial;*/
 
524
    msg->hdr.status = REMOTE_OK;
 
525
 
 
526
    if (remoteEncodeClientMessageHeader(msg) < 0) {
 
527
        xdr_free (data->ret_filter, (char*)&ret);
 
528
        goto fatal_error;
 
529
    }
 
530
 
 
531
 
 
532
    /* Now for the payload */
 
533
    xdrmem_create (&xdr,
 
534
                   msg->buffer,
 
535
                   msg->bufferLength,
 
536
                   XDR_ENCODE);
 
537
 
 
538
    if (xdr_setpos(&xdr, msg->bufferOffset) == 0)
 
539
        goto xdr_error;
 
540
 
 
541
    /* If OK, serialise return structure, if error serialise error. */
 
542
    /* Serialise reply data */
 
543
    if (!((data->ret_filter) (&xdr, &ret)))
 
544
        goto xdr_error;
 
545
 
 
546
    /* Update the length word. */
 
547
    msg->bufferOffset += xdr_getpos (&xdr);
 
548
    len = msg->bufferOffset;
 
549
    if (xdr_setpos (&xdr, 0) == 0)
 
550
        goto xdr_error;
 
551
 
 
552
    if (!xdr_u_int (&xdr, &len))
 
553
        goto xdr_error;
 
554
 
 
555
    xdr_destroy (&xdr);
 
556
    xdr_free (data->ret_filter, (char*)&ret);
 
557
 
 
558
    /* Reset ready for I/O */
 
559
    msg->bufferLength = len;
 
560
    msg->bufferOffset = 0;
 
561
 
 
562
    /* Put reply on end of tx queue to send out  */
 
563
    qemudClientMessageQueuePush(&client->tx, msg);
 
564
    qemudUpdateClientEvent(client);
 
565
 
 
566
    return 0;
 
567
 
 
568
rpc_error:
 
569
    /* Semi-bad stuff happened, we can still try to send back
 
570
     * an RPC error message to client */
 
571
    rv = remoteSerializeReplyError(client, &rerr, &msg->hdr);
 
572
 
 
573
    if (rv >= 0)
 
574
        VIR_FREE(msg);
 
575
 
 
576
    return rv;
 
577
 
 
578
xdr_error:
 
579
    /* Seriously bad stuff happened, so we'll kill off this client
 
580
       and not send back any RPC error */
 
581
    xdr_free (data->ret_filter, (char*)&ret);
 
582
    xdr_destroy (&xdr);
 
583
fatal_error:
 
584
    return -1;
 
585
}
 
586
 
 
587
 
 
588
int
 
589
remoteSendStreamData(struct qemud_client *client,
 
590
                     struct qemud_client_stream *stream,
 
591
                     const char *data,
 
592
                     unsigned int len)
 
593
{
 
594
    struct qemud_client_message *msg;
 
595
    XDR xdr;
 
596
 
 
597
    DEBUG("client=%p stream=%p data=%p len=%d", client, stream, data, len);
 
598
 
 
599
    if (VIR_ALLOC(msg) < 0) {
 
600
        return -1;
 
601
    }
 
602
 
 
603
    /* Return header. We're re-using same message object, so
 
604
     * only need to tweak type/status fields */
 
605
    msg->hdr.prog = REMOTE_PROGRAM;
 
606
    msg->hdr.vers = REMOTE_PROTOCOL_VERSION;
 
607
    msg->hdr.proc = stream->procedure;
 
608
    msg->hdr.type = REMOTE_STREAM;
 
609
    msg->hdr.serial = stream->serial;
 
610
    /*
 
611
     * NB
 
612
     *   data != NULL + len > 0    => REMOTE_CONTINUE   (Sending back data)
 
613
     *   data != NULL + len == 0   => REMOTE_CONTINUE   (Sending read EOF)
 
614
     *   data == NULL              => REMOTE_OK         (Sending finish handshake confirmation)
 
615
     */
 
616
    msg->hdr.status = data ? REMOTE_CONTINUE : REMOTE_OK;
 
617
 
 
618
    if (remoteEncodeClientMessageHeader(msg) < 0)
 
619
        goto fatal_error;
 
620
 
 
621
    if (data && len) {
 
622
        if ((msg->bufferLength - msg->bufferOffset) < len)
 
623
            goto fatal_error;
 
624
 
 
625
        /* Now for the payload */
 
626
        xdrmem_create (&xdr,
 
627
                       msg->buffer,
 
628
                       msg->bufferLength,
 
629
                       XDR_ENCODE);
 
630
 
 
631
        /* Skip over existing header already written */
 
632
        if (xdr_setpos(&xdr, msg->bufferOffset) == 0)
 
633
            goto xdr_error;
 
634
 
 
635
        memcpy(msg->buffer + msg->bufferOffset, data, len);
 
636
        msg->bufferOffset += len;
 
637
 
 
638
        /* Update the length word. */
 
639
        len = msg->bufferOffset;
 
640
        if (xdr_setpos (&xdr, 0) == 0)
 
641
            goto xdr_error;
 
642
 
 
643
        if (!xdr_u_int (&xdr, &len))
 
644
            goto xdr_error;
 
645
 
 
646
        xdr_destroy (&xdr);
 
647
 
 
648
        DEBUG("Total %d", msg->bufferOffset);
 
649
    }
 
650
    if (data)
 
651
        msg->streamTX = 1;
 
652
 
 
653
    /* Reset ready for I/O */
 
654
    msg->bufferLength = msg->bufferOffset;
 
655
    msg->bufferOffset = 0;
 
656
 
 
657
    /* Put reply on end of tx queue to send out  */
 
658
    qemudClientMessageQueuePush(&client->tx, msg);
 
659
    qemudUpdateClientEvent(client);
 
660
 
 
661
    return 0;
 
662
 
 
663
xdr_error:
 
664
    xdr_destroy (&xdr);
 
665
fatal_error:
 
666
    VIR_FREE(msg);
 
667
    return -1;
 
668
}