[libvirt] [PATCH 1/9] Split generic RPC message dispatch code out from remote protocol API handlers

Daniel P. Berrange berrange at redhat.com
Tue Jul 14 10:17:16 UTC 2009


* 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

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 qemud/Makefile.am |    3 +-
 qemud/dispatch.c  |  302 +++++++++++++++++++++++++++++++++++++++++++++++++
 qemud/dispatch.h  |   58 ++++++++++
 qemud/qemud.c     |    4 +-
 qemud/qemud.h     |   11 +--
 qemud/remote.c    |  325 +++--------------------------------------------------
 qemud/remote.h    |   72 ++++++++++++
 7 files changed, 454 insertions(+), 321 deletions(-)
 create mode 100644 qemud/dispatch.c
 create mode 100644 qemud/dispatch.h
 create mode 100644 qemud/remote.h

diff --git a/qemud/Makefile.am b/qemud/Makefile.am
index 403846a..74dfd22 100644
--- a/qemud/Makefile.am
+++ b/qemud/Makefile.am
@@ -3,7 +3,8 @@
 DAEMON_SOURCES =					\
 		event.c event.h				\
 		qemud.c qemud.h				\
-		remote.c				\
+		remote.c remote.h			\
+		dispatch.c dispatch.h			\
 		remote_dispatch_prototypes.h		\
 		remote_dispatch_table.h			\
 		remote_dispatch_args.h			\
diff --git a/qemud/dispatch.c b/qemud/dispatch.c
new file mode 100644
index 0000000..d2338fb
--- /dev/null
+++ b/qemud/dispatch.c
@@ -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 at redhat.com>
+ * Author: Daniel P. Berrange <berrange at 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;
+}
diff --git a/qemud/dispatch.h b/qemud/dispatch.h
new file mode 100644
index 0000000..9ab6148
--- /dev/null
+++ b/qemud/dispatch.h
@@ -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 at redhat.com>
+ * Author: Daniel P. Berrange <berrange at 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__ */
diff --git a/qemud/qemud.c b/qemud/qemud.c
index da20aa9..d300c56 100644
--- a/qemud/qemud.c
+++ b/qemud/qemud.c
@@ -54,6 +54,8 @@
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
 #include "qemud.h"
+#include "dispatch.h"
+
 #include "util.h"
 #include "remote_internal.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)
 {
     struct qemud_client_message *tmp = *queue;
diff --git a/qemud/qemud.h b/qemud/qemud.h
index 8880337..c8273cb 100644
--- a/qemud/qemud.h
+++ b/qemud/qemud.h
@@ -200,10 +200,6 @@ void qemudLog(int priority, const char *fmt, ...)
     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,
                              struct qemud_client *client,
@@ -214,12 +210,9 @@ void qemudDispatchClientFailure(struct qemud_client *client);
 void
 qemudClientMessageQueuePush(struct qemud_client_message **queue,
                             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
diff --git a/qemud/remote.c b/qemud/remote.c
index 1071c21..d0bc677 100644
--- a/qemud/remote.c
+++ b/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.
  *
@@ -48,18 +48,17 @@
 #include <polkit-dbus/polkit-dbus.h>
 #endif
 
+#include "remote.h"
+#include "dispatch.h"
+
 #include "libvirt_internal.h"
 #include "datatypes.h"
-#include "qemud.h"
 #include "memory.h"
 #include "util.h"
 
 #define VIR_FROM_THIS VIR_FROM_REMOTE
 #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 virNetworkPtr get_nonnull_network (virConnectPtr conn, remote_nonnull_network network);
 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_node_device (remote_nonnull_node_device *dev_dst, virNodeDevicePtr dev_src);
 
-#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;
+#include "remote_dispatch_prototypes.h"
 
 static const dispatch_data const dispatch_table[] = {
 #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 */
 static void
 remoteDispatchDomainEventSend (struct qemud_client *client,
@@ -122,276 +97,6 @@ remoteDispatchDomainEventSend (struct qemud_client *client,
                                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,
                             virDomainPtr dom,
diff --git a/qemud/remote.h b/qemud/remote.h
new file mode 100644
index 0000000..e3ee696
--- /dev/null
+++ b/qemud/remote.h
@@ -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 at redhat.com>
+ * Author: Daniel P. Berrange <berrange at 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__ */
-- 
1.6.2.5


-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list