mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-01 17:35:17 +00:00
Split generic RPC message dispatch code out from remote protocol API handlers
* po/POTFILES.in: Add qemud/dispatch.c * qemud/dispatch.c, qemud/dispatch.h: Generic code handling dispatch of RPC messages. * qemud/Makefile.am: Add dispatch.c to build * qemud/qemud.c: Include dispatch.h * qemud/qemud.h: Remove remoteDispatchClientRequest, remoteRelayDomainEvent now in dispatch.h * qemud/remote.c: Remove remoteDispatchClientRequest, remoteRelayDomainEvent now in dispatch.c, and dispatch_args, dispatch_ret, dispatch_fn & dispatch_data now in remote.h * qemud/remote.h: Add typedefs for dispatch_args, dispatch_ret, dispatch_fn, dispath_data. Add remoteGetDispatchData() API
This commit is contained in:
parent
e1abc44814
commit
a147ef3837
@ -4,5 +4,5 @@ docs/html/libvirt-virterror.html
|
|||||||
docs/libvirt-api.xml
|
docs/libvirt-api.xml
|
||||||
docs/libvirt-refs.xml
|
docs/libvirt-refs.xml
|
||||||
include/libvirt/virterror.h
|
include/libvirt/virterror.h
|
||||||
qemud/remote.c
|
qemud/dispatch.c
|
||||||
src/virterror.c
|
src/virterror.c
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
qemud/dispatch.c
|
||||||
qemud/qemud.c
|
qemud/qemud.c
|
||||||
qemud/remote.c
|
qemud/remote.c
|
||||||
src/bridge.c
|
src/bridge.c
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
DAEMON_SOURCES = \
|
DAEMON_SOURCES = \
|
||||||
event.c event.h \
|
event.c event.h \
|
||||||
qemud.c qemud.h \
|
qemud.c qemud.h \
|
||||||
remote.c \
|
remote.c remote.h \
|
||||||
|
dispatch.c dispatch.h \
|
||||||
remote_dispatch_prototypes.h \
|
remote_dispatch_prototypes.h \
|
||||||
remote_dispatch_table.h \
|
remote_dispatch_table.h \
|
||||||
remote_dispatch_args.h \
|
remote_dispatch_args.h \
|
||||||
|
302
qemud/dispatch.c
Normal file
302
qemud/dispatch.c
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
/*
|
||||||
|
* dispatch.h: RPC message dispatching infrastructure
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Author: Richard W.M. Jones <rjones@redhat.com>
|
||||||
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "dispatch.h"
|
||||||
|
#include "remote.h"
|
||||||
|
|
||||||
|
/* Convert a libvirt virError object into wire format */
|
||||||
|
static void
|
||||||
|
remoteDispatchCopyError (remote_error *rerr,
|
||||||
|
virErrorPtr verr)
|
||||||
|
{
|
||||||
|
rerr->code = verr->code;
|
||||||
|
rerr->domain = verr->domain;
|
||||||
|
rerr->message = verr->message ? malloc(sizeof(char*)) : NULL;
|
||||||
|
if (rerr->message) *rerr->message = strdup(verr->message);
|
||||||
|
rerr->level = verr->level;
|
||||||
|
rerr->str1 = verr->str1 ? malloc(sizeof(char*)) : NULL;
|
||||||
|
if (rerr->str1) *rerr->str1 = strdup(verr->str1);
|
||||||
|
rerr->str2 = verr->str2 ? malloc(sizeof(char*)) : NULL;
|
||||||
|
if (rerr->str2) *rerr->str2 = strdup(verr->str2);
|
||||||
|
rerr->str3 = verr->str3 ? malloc(sizeof(char*)) : NULL;
|
||||||
|
if (rerr->str3) *rerr->str3 = strdup(verr->str3);
|
||||||
|
rerr->int1 = verr->int1;
|
||||||
|
rerr->int2 = verr->int2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* A set of helpers for sending back errors to client
|
||||||
|
in various ways .... */
|
||||||
|
|
||||||
|
static void
|
||||||
|
remoteDispatchStringError (remote_error *rerr,
|
||||||
|
int code, const char *msg)
|
||||||
|
{
|
||||||
|
virError verr;
|
||||||
|
|
||||||
|
memset(&verr, 0, sizeof verr);
|
||||||
|
|
||||||
|
/* Construct the dummy libvirt virError. */
|
||||||
|
verr.code = code;
|
||||||
|
verr.domain = VIR_FROM_REMOTE;
|
||||||
|
verr.message = (char *)msg;
|
||||||
|
verr.level = VIR_ERR_ERROR;
|
||||||
|
verr.str1 = (char *)msg;
|
||||||
|
|
||||||
|
remoteDispatchCopyError(rerr, &verr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void remoteDispatchAuthError (remote_error *rerr)
|
||||||
|
{
|
||||||
|
remoteDispatchStringError (rerr, VIR_ERR_AUTH_FAILED, "authentication failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void remoteDispatchFormatError (remote_error *rerr,
|
||||||
|
const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
char msgbuf[1024];
|
||||||
|
char *msg = msgbuf;
|
||||||
|
|
||||||
|
va_start (args, fmt);
|
||||||
|
vsnprintf (msgbuf, sizeof msgbuf, fmt, args);
|
||||||
|
va_end (args);
|
||||||
|
|
||||||
|
remoteDispatchStringError (rerr, VIR_ERR_RPC, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void remoteDispatchGenericError (remote_error *rerr)
|
||||||
|
{
|
||||||
|
remoteDispatchStringError(rerr,
|
||||||
|
VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"library function returned error but did not set virterror");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void remoteDispatchOOMError (remote_error *rerr)
|
||||||
|
{
|
||||||
|
remoteDispatchStringError(rerr,
|
||||||
|
VIR_ERR_NO_MEMORY,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void remoteDispatchConnError (remote_error *rerr,
|
||||||
|
virConnectPtr conn)
|
||||||
|
{
|
||||||
|
virErrorPtr verr;
|
||||||
|
|
||||||
|
if (conn)
|
||||||
|
verr = virConnGetLastError(conn);
|
||||||
|
else
|
||||||
|
verr = virGetLastError();
|
||||||
|
if (verr)
|
||||||
|
remoteDispatchCopyError(rerr, verr);
|
||||||
|
else
|
||||||
|
remoteDispatchGenericError(rerr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @server: the unlocked server object
|
||||||
|
* @client: the locked client object
|
||||||
|
* @msg: the complete incoming message packet
|
||||||
|
*
|
||||||
|
* This function gets called from qemud when it pulls a incoming
|
||||||
|
* remote protocol messsage off the dispatch queue for processing.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Returns 0 if the message was dispatched, -1 upon fatal error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
remoteDispatchClientRequest (struct qemud_server *server,
|
||||||
|
struct qemud_client *client,
|
||||||
|
struct qemud_client_message *msg)
|
||||||
|
{
|
||||||
|
XDR xdr;
|
||||||
|
remote_message_header req, rep;
|
||||||
|
remote_error rerr;
|
||||||
|
dispatch_args args;
|
||||||
|
dispatch_ret ret;
|
||||||
|
const dispatch_data *data = NULL;
|
||||||
|
int rv = -1;
|
||||||
|
unsigned int len;
|
||||||
|
virConnectPtr conn = NULL;
|
||||||
|
|
||||||
|
memset(&args, 0, sizeof args);
|
||||||
|
memset(&ret, 0, sizeof ret);
|
||||||
|
memset(&rerr, 0, sizeof rerr);
|
||||||
|
|
||||||
|
/* Parse the header. */
|
||||||
|
xdrmem_create (&xdr,
|
||||||
|
msg->buffer + REMOTE_MESSAGE_HEADER_XDR_LEN,
|
||||||
|
msg->bufferLength - REMOTE_MESSAGE_HEADER_XDR_LEN,
|
||||||
|
XDR_DECODE);
|
||||||
|
|
||||||
|
if (!xdr_remote_message_header (&xdr, &req))
|
||||||
|
goto fatal_error;
|
||||||
|
|
||||||
|
/* Check version, etc. */
|
||||||
|
if (req.prog != REMOTE_PROGRAM) {
|
||||||
|
remoteDispatchFormatError (&rerr,
|
||||||
|
_("program mismatch (actual %x, expected %x)"),
|
||||||
|
req.prog, REMOTE_PROGRAM);
|
||||||
|
goto rpc_error;
|
||||||
|
}
|
||||||
|
if (req.vers != REMOTE_PROTOCOL_VERSION) {
|
||||||
|
remoteDispatchFormatError (&rerr,
|
||||||
|
_("version mismatch (actual %x, expected %x)"),
|
||||||
|
req.vers, REMOTE_PROTOCOL_VERSION);
|
||||||
|
goto rpc_error;
|
||||||
|
}
|
||||||
|
if (req.direction != REMOTE_CALL) {
|
||||||
|
remoteDispatchFormatError (&rerr, _("direction (%d) != REMOTE_CALL"),
|
||||||
|
(int) req.direction);
|
||||||
|
goto rpc_error;
|
||||||
|
}
|
||||||
|
if (req.status != REMOTE_OK) {
|
||||||
|
remoteDispatchFormatError (&rerr, _("status (%d) != REMOTE_OK"),
|
||||||
|
(int) req.status);
|
||||||
|
goto rpc_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If client is marked as needing auth, don't allow any RPC ops,
|
||||||
|
* except for authentication ones
|
||||||
|
*/
|
||||||
|
if (client->auth) {
|
||||||
|
if (req.proc != REMOTE_PROC_AUTH_LIST &&
|
||||||
|
req.proc != REMOTE_PROC_AUTH_SASL_INIT &&
|
||||||
|
req.proc != REMOTE_PROC_AUTH_SASL_START &&
|
||||||
|
req.proc != REMOTE_PROC_AUTH_SASL_STEP &&
|
||||||
|
req.proc != REMOTE_PROC_AUTH_POLKIT
|
||||||
|
) {
|
||||||
|
/* Explicitly *NOT* calling remoteDispatchAuthError() because
|
||||||
|
we want back-compatability with libvirt clients which don't
|
||||||
|
support the VIR_ERR_AUTH_FAILED error code */
|
||||||
|
remoteDispatchFormatError (&rerr, "%s", _("authentication required"));
|
||||||
|
goto rpc_error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data = remoteGetDispatchData(req.proc);
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
remoteDispatchFormatError (&rerr, _("unknown procedure: %d"),
|
||||||
|
req.proc);
|
||||||
|
goto rpc_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* De-serialize args off the wire */
|
||||||
|
if (!((data->args_filter)(&xdr, &args))) {
|
||||||
|
remoteDispatchFormatError (&rerr, "%s", _("parse args failed"));
|
||||||
|
goto rpc_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call function. */
|
||||||
|
conn = client->conn;
|
||||||
|
virMutexUnlock(&client->lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When the RPC handler is called:
|
||||||
|
*
|
||||||
|
* - Server object is unlocked
|
||||||
|
* - Client object is unlocked
|
||||||
|
*
|
||||||
|
* Without locking, it is safe to use:
|
||||||
|
*
|
||||||
|
* 'conn', 'rerr', 'args and 'ret'
|
||||||
|
*/
|
||||||
|
rv = (data->fn)(server, client, conn, &rerr, &args, &ret);
|
||||||
|
|
||||||
|
virMutexLock(&server->lock);
|
||||||
|
virMutexLock(&client->lock);
|
||||||
|
virMutexUnlock(&server->lock);
|
||||||
|
|
||||||
|
xdr_free (data->args_filter, (char*)&args);
|
||||||
|
|
||||||
|
rpc_error:
|
||||||
|
xdr_destroy (&xdr);
|
||||||
|
|
||||||
|
/* Return header. */
|
||||||
|
rep.prog = req.prog;
|
||||||
|
rep.vers = req.vers;
|
||||||
|
rep.proc = req.proc;
|
||||||
|
rep.direction = REMOTE_REPLY;
|
||||||
|
rep.serial = req.serial;
|
||||||
|
rep.status = rv < 0 ? REMOTE_ERROR : REMOTE_OK;
|
||||||
|
|
||||||
|
/* Serialise the return header. */
|
||||||
|
xdrmem_create (&xdr, msg->buffer, sizeof msg->buffer, XDR_ENCODE);
|
||||||
|
|
||||||
|
len = 0; /* We'll come back and write this later. */
|
||||||
|
if (!xdr_u_int (&xdr, &len)) {
|
||||||
|
if (rv == 0) xdr_free (data->ret_filter, (char*)&ret);
|
||||||
|
goto fatal_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!xdr_remote_message_header (&xdr, &rep)) {
|
||||||
|
if (rv == 0) xdr_free (data->ret_filter, (char*)&ret);
|
||||||
|
goto fatal_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If OK, serialise return structure, if error serialise error. */
|
||||||
|
if (rv >= 0) {
|
||||||
|
if (!((data->ret_filter) (&xdr, &ret)))
|
||||||
|
goto fatal_error;
|
||||||
|
xdr_free (data->ret_filter, (char*)&ret);
|
||||||
|
} else /* error */ {
|
||||||
|
/* Error was NULL so synthesize an error. */
|
||||||
|
if (rerr.code == 0)
|
||||||
|
remoteDispatchGenericError(&rerr);
|
||||||
|
if (!xdr_remote_error (&xdr, &rerr))
|
||||||
|
goto fatal_error;
|
||||||
|
xdr_free((xdrproc_t)xdr_remote_error, (char *)&rerr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the length word. */
|
||||||
|
len = xdr_getpos (&xdr);
|
||||||
|
if (xdr_setpos (&xdr, 0) == 0)
|
||||||
|
goto fatal_error;
|
||||||
|
|
||||||
|
if (!xdr_u_int (&xdr, &len))
|
||||||
|
goto fatal_error;
|
||||||
|
|
||||||
|
xdr_destroy (&xdr);
|
||||||
|
|
||||||
|
msg->bufferLength = len;
|
||||||
|
msg->bufferOffset = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fatal_error:
|
||||||
|
/* Seriously bad stuff happened, so we'll kill off this client
|
||||||
|
and not send back any RPC error */
|
||||||
|
xdr_destroy (&xdr);
|
||||||
|
return -1;
|
||||||
|
}
|
58
qemud/dispatch.h
Normal file
58
qemud/dispatch.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* dispatch.h: RPC message dispatching infrastructure
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Author: Richard W.M. Jones <rjones@redhat.com>
|
||||||
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBVIRTD_DISPATCH_H__
|
||||||
|
#define __LIBVIRTD_DISPATCH_H__
|
||||||
|
|
||||||
|
|
||||||
|
#include "qemud.h"
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
remoteDispatchClientRequest (struct qemud_server *server,
|
||||||
|
struct qemud_client *client,
|
||||||
|
struct qemud_client_message *req);
|
||||||
|
|
||||||
|
|
||||||
|
void remoteDispatchFormatError (remote_error *rerr,
|
||||||
|
const char *fmt, ...)
|
||||||
|
ATTRIBUTE_FORMAT(printf, 2, 3);
|
||||||
|
|
||||||
|
void remoteDispatchAuthError (remote_error *rerr);
|
||||||
|
void remoteDispatchGenericError (remote_error *rerr);
|
||||||
|
void remoteDispatchOOMError (remote_error *rerr);
|
||||||
|
void remoteDispatchConnError (remote_error *rerr,
|
||||||
|
virConnectPtr conn);
|
||||||
|
|
||||||
|
/* Having this here is dubious. It should be in remote.h
|
||||||
|
* but qemud.c shouldn't depend on that header directly.
|
||||||
|
* Refactor this later to deal with this properly.
|
||||||
|
*/
|
||||||
|
int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||||
|
virDomainPtr dom,
|
||||||
|
int event,
|
||||||
|
int detail,
|
||||||
|
void *opaque);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __LIBVIRTD_DISPATCH_H__ */
|
@ -54,6 +54,8 @@
|
|||||||
#define VIR_FROM_THIS VIR_FROM_QEMU
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
||||||
|
|
||||||
#include "qemud.h"
|
#include "qemud.h"
|
||||||
|
#include "dispatch.h"
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "remote_internal.h"
|
#include "remote_internal.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
@ -219,7 +221,7 @@ qemudClientMessageQueuePush(struct qemud_client_message **queue,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct qemud_client_message *
|
struct qemud_client_message *
|
||||||
qemudClientMessageQueueServe(struct qemud_client_message **queue)
|
qemudClientMessageQueueServe(struct qemud_client_message **queue)
|
||||||
{
|
{
|
||||||
struct qemud_client_message *tmp = *queue;
|
struct qemud_client_message *tmp = *queue;
|
||||||
|
@ -200,10 +200,6 @@ void qemudLog(int priority, const char *fmt, ...)
|
|||||||
ATTRIBUTE_FORMAT(printf,2,3);
|
ATTRIBUTE_FORMAT(printf,2,3);
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
remoteDispatchClientRequest (struct qemud_server *server,
|
|
||||||
struct qemud_client *client,
|
|
||||||
struct qemud_client_message *req);
|
|
||||||
|
|
||||||
int qemudRegisterClientEvent(struct qemud_server *server,
|
int qemudRegisterClientEvent(struct qemud_server *server,
|
||||||
struct qemud_client *client,
|
struct qemud_client *client,
|
||||||
@ -214,12 +210,9 @@ void qemudDispatchClientFailure(struct qemud_client *client);
|
|||||||
void
|
void
|
||||||
qemudClientMessageQueuePush(struct qemud_client_message **queue,
|
qemudClientMessageQueuePush(struct qemud_client_message **queue,
|
||||||
struct qemud_client_message *msg);
|
struct qemud_client_message *msg);
|
||||||
|
struct qemud_client_message *
|
||||||
|
qemudClientMessageQueueServe(struct qemud_client_message **queue);
|
||||||
|
|
||||||
int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
||||||
virDomainPtr dom,
|
|
||||||
int event,
|
|
||||||
int detail,
|
|
||||||
void *opaque);
|
|
||||||
|
|
||||||
|
|
||||||
#if HAVE_POLKIT
|
#if HAVE_POLKIT
|
||||||
|
325
qemud/remote.c
325
qemud/remote.c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* remote.c: code handling remote requests (from remote_internal.c)
|
* remote.c: handlers for RPC method calls
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
|
* Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
@ -48,18 +48,17 @@
|
|||||||
#include <polkit-dbus/polkit-dbus.h>
|
#include <polkit-dbus/polkit-dbus.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "remote.h"
|
||||||
|
#include "dispatch.h"
|
||||||
|
|
||||||
#include "libvirt_internal.h"
|
#include "libvirt_internal.h"
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
#include "qemud.h"
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_REMOTE
|
#define VIR_FROM_THIS VIR_FROM_REMOTE
|
||||||
#define REMOTE_DEBUG(fmt, ...) DEBUG(fmt, __VA_ARGS__)
|
#define REMOTE_DEBUG(fmt, ...) DEBUG(fmt, __VA_ARGS__)
|
||||||
|
|
||||||
static void remoteDispatchFormatError (remote_error *rerr,
|
|
||||||
const char *fmt, ...)
|
|
||||||
ATTRIBUTE_FORMAT(printf, 2, 3);
|
|
||||||
static virDomainPtr get_nonnull_domain (virConnectPtr conn, remote_nonnull_domain domain);
|
static virDomainPtr get_nonnull_domain (virConnectPtr conn, remote_nonnull_domain domain);
|
||||||
static virNetworkPtr get_nonnull_network (virConnectPtr conn, remote_nonnull_network network);
|
static virNetworkPtr get_nonnull_network (virConnectPtr conn, remote_nonnull_network network);
|
||||||
static virInterfacePtr get_nonnull_interface (virConnectPtr conn, remote_nonnull_interface interface);
|
static virInterfacePtr get_nonnull_interface (virConnectPtr conn, remote_nonnull_interface interface);
|
||||||
@ -72,47 +71,23 @@ static void make_nonnull_storage_pool (remote_nonnull_storage_pool *pool_dst, vi
|
|||||||
static void make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_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_node_device (remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src);
|
||||||
|
|
||||||
|
|
||||||
#include "remote_dispatch_prototypes.h"
|
#include "remote_dispatch_prototypes.h"
|
||||||
|
|
||||||
typedef union {
|
|
||||||
#include "remote_dispatch_args.h"
|
|
||||||
} dispatch_args;
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
#include "remote_dispatch_ret.h"
|
|
||||||
} dispatch_ret;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When the RPC handler is called:
|
|
||||||
*
|
|
||||||
* - Server object is unlocked
|
|
||||||
* - Client object is unlocked
|
|
||||||
*
|
|
||||||
* Both must be locked before use. Server lock must
|
|
||||||
* be held before attempting to lock client.
|
|
||||||
*
|
|
||||||
* Without any locking, it is safe to use:
|
|
||||||
*
|
|
||||||
* 'conn', 'rerr', 'args and 'ret'
|
|
||||||
*/
|
|
||||||
typedef int (*dispatch_fn) (struct qemud_server *server,
|
|
||||||
struct qemud_client *client,
|
|
||||||
virConnectPtr conn,
|
|
||||||
remote_error *err,
|
|
||||||
dispatch_args *args,
|
|
||||||
dispatch_ret *ret);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
dispatch_fn fn;
|
|
||||||
xdrproc_t args_filter;
|
|
||||||
xdrproc_t ret_filter;
|
|
||||||
} dispatch_data;
|
|
||||||
|
|
||||||
static const dispatch_data const dispatch_table[] = {
|
static const dispatch_data const dispatch_table[] = {
|
||||||
#include "remote_dispatch_table.h"
|
#include "remote_dispatch_table.h"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const dispatch_data const *remoteGetDispatchData(int proc)
|
||||||
|
{
|
||||||
|
if (proc >= ARRAY_CARDINALITY(dispatch_table) ||
|
||||||
|
dispatch_table[proc].fn == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &(dispatch_table[proc]);
|
||||||
|
}
|
||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
static void
|
static void
|
||||||
remoteDispatchDomainEventSend (struct qemud_client *client,
|
remoteDispatchDomainEventSend (struct qemud_client *client,
|
||||||
@ -122,276 +97,6 @@ remoteDispatchDomainEventSend (struct qemud_client *client,
|
|||||||
int detail);
|
int detail);
|
||||||
|
|
||||||
|
|
||||||
/* Convert a libvirt virError object into wire format */
|
|
||||||
static void
|
|
||||||
remoteDispatchCopyError (remote_error *rerr,
|
|
||||||
virErrorPtr verr)
|
|
||||||
{
|
|
||||||
rerr->code = verr->code;
|
|
||||||
rerr->domain = verr->domain;
|
|
||||||
rerr->message = verr->message ? malloc(sizeof(char*)) : NULL;
|
|
||||||
if (rerr->message) *rerr->message = strdup(verr->message);
|
|
||||||
rerr->level = verr->level;
|
|
||||||
rerr->str1 = verr->str1 ? malloc(sizeof(char*)) : NULL;
|
|
||||||
if (rerr->str1) *rerr->str1 = strdup(verr->str1);
|
|
||||||
rerr->str2 = verr->str2 ? malloc(sizeof(char*)) : NULL;
|
|
||||||
if (rerr->str2) *rerr->str2 = strdup(verr->str2);
|
|
||||||
rerr->str3 = verr->str3 ? malloc(sizeof(char*)) : NULL;
|
|
||||||
if (rerr->str3) *rerr->str3 = strdup(verr->str3);
|
|
||||||
rerr->int1 = verr->int1;
|
|
||||||
rerr->int2 = verr->int2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* A set of helpers for sending back errors to client
|
|
||||||
in various ways .... */
|
|
||||||
|
|
||||||
static void
|
|
||||||
remoteDispatchStringError (remote_error *rerr,
|
|
||||||
int code, const char *msg)
|
|
||||||
{
|
|
||||||
virError verr;
|
|
||||||
|
|
||||||
memset(&verr, 0, sizeof verr);
|
|
||||||
|
|
||||||
/* Construct the dummy libvirt virError. */
|
|
||||||
verr.code = code;
|
|
||||||
verr.domain = VIR_FROM_REMOTE;
|
|
||||||
verr.message = (char *)msg;
|
|
||||||
verr.level = VIR_ERR_ERROR;
|
|
||||||
verr.str1 = (char *)msg;
|
|
||||||
|
|
||||||
remoteDispatchCopyError(rerr, &verr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
remoteDispatchAuthError (remote_error *rerr)
|
|
||||||
{
|
|
||||||
remoteDispatchStringError (rerr, VIR_ERR_AUTH_FAILED, "authentication failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
remoteDispatchFormatError (remote_error *rerr,
|
|
||||||
const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
char msgbuf[1024];
|
|
||||||
char *msg = msgbuf;
|
|
||||||
|
|
||||||
va_start (args, fmt);
|
|
||||||
vsnprintf (msgbuf, sizeof msgbuf, fmt, args);
|
|
||||||
va_end (args);
|
|
||||||
|
|
||||||
remoteDispatchStringError (rerr, VIR_ERR_RPC, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
remoteDispatchGenericError (remote_error *rerr)
|
|
||||||
{
|
|
||||||
remoteDispatchStringError(rerr,
|
|
||||||
VIR_ERR_INTERNAL_ERROR,
|
|
||||||
"library function returned error but did not set virterror");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
remoteDispatchOOMError (remote_error *rerr)
|
|
||||||
{
|
|
||||||
remoteDispatchStringError(rerr,
|
|
||||||
VIR_ERR_NO_MEMORY,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
remoteDispatchConnError (remote_error *rerr,
|
|
||||||
virConnectPtr conn)
|
|
||||||
{
|
|
||||||
virErrorPtr verr;
|
|
||||||
|
|
||||||
if (conn)
|
|
||||||
verr = virConnGetLastError(conn);
|
|
||||||
else
|
|
||||||
verr = virGetLastError();
|
|
||||||
if (verr)
|
|
||||||
remoteDispatchCopyError(rerr, verr);
|
|
||||||
else
|
|
||||||
remoteDispatchGenericError(rerr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* This function gets called from qemud when it detects an incoming
|
|
||||||
* remote protocol message. At this point, client->buffer contains
|
|
||||||
* the full call message (including length word which we skip).
|
|
||||||
*
|
|
||||||
* Server object is unlocked
|
|
||||||
* Client object is locked
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
remoteDispatchClientRequest (struct qemud_server *server,
|
|
||||||
struct qemud_client *client,
|
|
||||||
struct qemud_client_message *msg)
|
|
||||||
{
|
|
||||||
XDR xdr;
|
|
||||||
remote_message_header req, rep;
|
|
||||||
remote_error rerr;
|
|
||||||
dispatch_args args;
|
|
||||||
dispatch_ret ret;
|
|
||||||
const dispatch_data *data = NULL;
|
|
||||||
int rv = -1;
|
|
||||||
unsigned int len;
|
|
||||||
virConnectPtr conn = NULL;
|
|
||||||
|
|
||||||
memset(&args, 0, sizeof args);
|
|
||||||
memset(&ret, 0, sizeof ret);
|
|
||||||
memset(&rerr, 0, sizeof rerr);
|
|
||||||
|
|
||||||
/* Parse the header. */
|
|
||||||
xdrmem_create (&xdr,
|
|
||||||
msg->buffer + REMOTE_MESSAGE_HEADER_XDR_LEN,
|
|
||||||
msg->bufferLength - REMOTE_MESSAGE_HEADER_XDR_LEN,
|
|
||||||
XDR_DECODE);
|
|
||||||
|
|
||||||
if (!xdr_remote_message_header (&xdr, &req))
|
|
||||||
goto fatal_error;
|
|
||||||
|
|
||||||
/* Check version, etc. */
|
|
||||||
if (req.prog != REMOTE_PROGRAM) {
|
|
||||||
remoteDispatchFormatError (&rerr,
|
|
||||||
_("program mismatch (actual %x, expected %x)"),
|
|
||||||
req.prog, REMOTE_PROGRAM);
|
|
||||||
goto rpc_error;
|
|
||||||
}
|
|
||||||
if (req.vers != REMOTE_PROTOCOL_VERSION) {
|
|
||||||
remoteDispatchFormatError (&rerr,
|
|
||||||
_("version mismatch (actual %x, expected %x)"),
|
|
||||||
req.vers, REMOTE_PROTOCOL_VERSION);
|
|
||||||
goto rpc_error;
|
|
||||||
}
|
|
||||||
if (req.direction != REMOTE_CALL) {
|
|
||||||
remoteDispatchFormatError (&rerr, _("direction (%d) != REMOTE_CALL"),
|
|
||||||
(int) req.direction);
|
|
||||||
goto rpc_error;
|
|
||||||
}
|
|
||||||
if (req.status != REMOTE_OK) {
|
|
||||||
remoteDispatchFormatError (&rerr, _("status (%d) != REMOTE_OK"),
|
|
||||||
(int) req.status);
|
|
||||||
goto rpc_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If client is marked as needing auth, don't allow any RPC ops,
|
|
||||||
* except for authentication ones
|
|
||||||
*/
|
|
||||||
if (client->auth) {
|
|
||||||
if (req.proc != REMOTE_PROC_AUTH_LIST &&
|
|
||||||
req.proc != REMOTE_PROC_AUTH_SASL_INIT &&
|
|
||||||
req.proc != REMOTE_PROC_AUTH_SASL_START &&
|
|
||||||
req.proc != REMOTE_PROC_AUTH_SASL_STEP &&
|
|
||||||
req.proc != REMOTE_PROC_AUTH_POLKIT
|
|
||||||
) {
|
|
||||||
/* Explicitly *NOT* calling remoteDispatchAuthError() because
|
|
||||||
we want back-compatability with libvirt clients which don't
|
|
||||||
support the VIR_ERR_AUTH_FAILED error code */
|
|
||||||
remoteDispatchFormatError (&rerr, "%s", _("authentication required"));
|
|
||||||
goto rpc_error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.proc >= ARRAY_CARDINALITY(dispatch_table) ||
|
|
||||||
dispatch_table[req.proc].fn == NULL) {
|
|
||||||
remoteDispatchFormatError (&rerr, _("unknown procedure: %d"),
|
|
||||||
req.proc);
|
|
||||||
goto rpc_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = &(dispatch_table[req.proc]);
|
|
||||||
|
|
||||||
/* De-serialize args off the wire */
|
|
||||||
if (!((data->args_filter)(&xdr, &args))) {
|
|
||||||
remoteDispatchFormatError (&rerr, "%s", _("parse args failed"));
|
|
||||||
goto rpc_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Call function. */
|
|
||||||
conn = client->conn;
|
|
||||||
virMutexUnlock(&client->lock);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When the RPC handler is called:
|
|
||||||
*
|
|
||||||
* - Server object is unlocked
|
|
||||||
* - Client object is unlocked
|
|
||||||
*
|
|
||||||
* Without locking, it is safe to use:
|
|
||||||
*
|
|
||||||
* 'conn', 'rerr', 'args and 'ret'
|
|
||||||
*/
|
|
||||||
rv = (data->fn)(server, client, conn, &rerr, &args, &ret);
|
|
||||||
|
|
||||||
virMutexLock(&server->lock);
|
|
||||||
virMutexLock(&client->lock);
|
|
||||||
virMutexUnlock(&server->lock);
|
|
||||||
|
|
||||||
xdr_free (data->args_filter, (char*)&args);
|
|
||||||
|
|
||||||
rpc_error:
|
|
||||||
xdr_destroy (&xdr);
|
|
||||||
|
|
||||||
/* Return header. */
|
|
||||||
rep.prog = req.prog;
|
|
||||||
rep.vers = req.vers;
|
|
||||||
rep.proc = req.proc;
|
|
||||||
rep.direction = REMOTE_REPLY;
|
|
||||||
rep.serial = req.serial;
|
|
||||||
rep.status = rv < 0 ? REMOTE_ERROR : REMOTE_OK;
|
|
||||||
|
|
||||||
/* Serialise the return header. */
|
|
||||||
xdrmem_create (&xdr, msg->buffer, sizeof msg->buffer, XDR_ENCODE);
|
|
||||||
|
|
||||||
len = 0; /* We'll come back and write this later. */
|
|
||||||
if (!xdr_u_int (&xdr, &len)) {
|
|
||||||
if (rv == 0) xdr_free (data->ret_filter, (char*)&ret);
|
|
||||||
goto fatal_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!xdr_remote_message_header (&xdr, &rep)) {
|
|
||||||
if (rv == 0) xdr_free (data->ret_filter, (char*)&ret);
|
|
||||||
goto fatal_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If OK, serialise return structure, if error serialise error. */
|
|
||||||
if (rv >= 0) {
|
|
||||||
if (!((data->ret_filter) (&xdr, &ret)))
|
|
||||||
goto fatal_error;
|
|
||||||
xdr_free (data->ret_filter, (char*)&ret);
|
|
||||||
} else /* error */ {
|
|
||||||
/* Error was NULL so synthesize an error. */
|
|
||||||
if (rerr.code == 0)
|
|
||||||
remoteDispatchGenericError(&rerr);
|
|
||||||
if (!xdr_remote_error (&xdr, &rerr))
|
|
||||||
goto fatal_error;
|
|
||||||
xdr_free((xdrproc_t)xdr_remote_error, (char *)&rerr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write the length word. */
|
|
||||||
len = xdr_getpos (&xdr);
|
|
||||||
if (xdr_setpos (&xdr, 0) == 0)
|
|
||||||
goto fatal_error;
|
|
||||||
|
|
||||||
if (!xdr_u_int (&xdr, &len))
|
|
||||||
goto fatal_error;
|
|
||||||
|
|
||||||
xdr_destroy (&xdr);
|
|
||||||
|
|
||||||
msg->bufferLength = len;
|
|
||||||
msg->bufferOffset = 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fatal_error:
|
|
||||||
/* Seriously bad stuff happened, so we'll kill off this client
|
|
||||||
and not send back any RPC error */
|
|
||||||
xdr_destroy (&xdr);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED,
|
int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||||
virDomainPtr dom,
|
virDomainPtr dom,
|
||||||
|
72
qemud/remote.h
Normal file
72
qemud/remote.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* remote.h: handlers for RPC method calls
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Author: Richard W.M. Jones <rjones@redhat.com>
|
||||||
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBVIRTD_REMOTE_H__
|
||||||
|
#define __LIBVIRTD_REMOTE_H__
|
||||||
|
|
||||||
|
|
||||||
|
#include "qemud.h"
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
#include "remote_dispatch_args.h"
|
||||||
|
} dispatch_args;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
#include "remote_dispatch_ret.h"
|
||||||
|
} dispatch_ret;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the RPC handler is called:
|
||||||
|
*
|
||||||
|
* - Server object is unlocked
|
||||||
|
* - Client object is unlocked
|
||||||
|
*
|
||||||
|
* Both must be locked before use. Server lock must
|
||||||
|
* be held before attempting to lock client.
|
||||||
|
*
|
||||||
|
* Without any locking, it is safe to use:
|
||||||
|
*
|
||||||
|
* 'conn', 'rerr', 'args and 'ret'
|
||||||
|
*/
|
||||||
|
typedef int (*dispatch_fn) (struct qemud_server *server,
|
||||||
|
struct qemud_client *client,
|
||||||
|
virConnectPtr conn,
|
||||||
|
remote_error *err,
|
||||||
|
dispatch_args *args,
|
||||||
|
dispatch_ret *ret);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
dispatch_fn fn;
|
||||||
|
xdrproc_t args_filter;
|
||||||
|
xdrproc_t ret_filter;
|
||||||
|
} dispatch_data;
|
||||||
|
|
||||||
|
|
||||||
|
const dispatch_data const *remoteGetDispatchData(int proc);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __LIBVIRTD_REMOTE_H__ */
|
Loading…
x
Reference in New Issue
Block a user