The remoteDispatchClientRequest() method is currently hardwired to
assume there is only one type of incoming message, a method call.
To allow for alternate types of incoming messags, the code that is
specific to method calls is being split into a separate method
remoteDispatchClientCall
* qemud/dispatch.c: Move method call specific code out into
remoteDispatchClientCall. Add a helper remoteSerializeError
for returning error messages to client
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
qemud/dispatch.c | 208 ++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 170 insertions(+), 38 deletions(-)
diff --git a/qemud/dispatch.c b/qemud/dispatch.c
index a4e6c3e..1ccca10 100644
--- a/qemud/dispatch.c
+++ b/qemud/dispatch.c
@@ -23,10 +23,11 @@
#include <config.h>
-
#include "dispatch.h"
#include "remote.h"
+#include "memory.h"
+
/* Convert a libvirt virError object into wire format */
static void
remoteDispatchCopyError (remote_error *rerr,
@@ -122,6 +123,101 @@ void remoteDispatchConnError (remote_error *rerr,
remoteDispatchGenericError(rerr);
}
+static int
+remoteSerializeError(struct qemud_client *client,
+ remote_error *rerr,
+ int program,
+ int version,
+ int procedure,
+ int direction,
+ int serial)
+{
+ XDR xdr;
+ unsigned int len;
+ struct qemud_client_message *msg = NULL;
+
+ if (VIR_ALLOC(msg) < 0)
+ goto fatal_error;
+
+ /* Return header. */
+ msg->hdr.prog = program;
+ msg->hdr.vers = version;
+ msg->hdr.proc = procedure;
+ msg->hdr.direction = direction;
+ msg->hdr.serial = serial;
+ msg->hdr.status = REMOTE_ERROR;
+
+ msg->bufferLength = sizeof(msg->buffer);
+
+ /* Serialise the return header. */
+ xdrmem_create (&xdr,
+ msg->buffer,
+ msg->bufferLength,
+ XDR_ENCODE);
+
+ len = 0; /* We'll come back and write this later. */
+ if (!xdr_u_int (&xdr, &len))
+ goto xdr_error;
+
+ if (!xdr_remote_message_header (&xdr, &msg->hdr))
+ goto xdr_error;
+
+ /* Error was not set, so synthesize a generic error message. */
+ if (rerr->code == 0)
+ remoteDispatchGenericError(rerr);
+
+ if (!xdr_remote_error (&xdr, rerr))
+ goto xdr_error;
+
+ /* Write the length word. */
+ len = xdr_getpos (&xdr);
+ if (xdr_setpos (&xdr, 0) == 0)
+ goto xdr_error;
+
+ if (!xdr_u_int (&xdr, &len))
+ goto xdr_error;
+
+ xdr_destroy (&xdr);
+
+ msg->bufferLength = len;
+ msg->bufferOffset = 0;
+
+ /* Put reply on end of tx queue to send out */
+ qemudClientMessageQueuePush(&client->tx, msg);
+ qemudUpdateClientEvent(client);
+ xdr_free((xdrproc_t)xdr_remote_error, (char *)rerr);
+
+ return 0;
+
+xdr_error:
+ xdr_destroy(&xdr);
+fatal_error:
+ xdr_free((xdrproc_t)xdr_remote_error, (char *)rerr);
+ return -1;
+}
+
+
+/*
+ * @client: the client to send the error to
+ * @rerr: the error object to send
+ * @req: the message this error is in reply to
+ *
+ * Send an error message to the client
+ *
+ * Returns 0 if the error was sent, -1 upon fatal error
+ */
+static int
+remoteSerializeReplyError(struct qemud_client *client,
+ remote_error *rerr,
+ remote_message_header *req) {
+ return remoteSerializeError(client,
+ rerr,
+ req->prog,
+ req->vers,
+ req->proc,
+ REMOTE_REPLY,
+ req->serial);
+}
/*
* @msg: the complete incoming message, whose header to decode
@@ -216,6 +312,12 @@ cleanup:
}
+int
+remoteDispatchClientCall (struct qemud_server *server,
+ struct qemud_client *client,
+ struct qemud_client_message *msg);
+
+
/*
* @server: the unlocked server object
* @client: the locked client object
@@ -234,44 +336,73 @@ remoteDispatchClientRequest (struct qemud_server *server,
struct qemud_client *client,
struct qemud_client_message *msg)
{
- XDR xdr;
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);
-
/* Check version, etc. */
if (msg->hdr.prog != REMOTE_PROGRAM) {
remoteDispatchFormatError (&rerr,
_("program mismatch (actual %x, expected
%x)"),
msg->hdr.prog, REMOTE_PROGRAM);
- goto rpc_error;
+ goto error;
}
if (msg->hdr.vers != REMOTE_PROTOCOL_VERSION) {
remoteDispatchFormatError (&rerr,
_("version mismatch (actual %x, expected
%x)"),
msg->hdr.vers, REMOTE_PROTOCOL_VERSION);
- goto rpc_error;
- }
- if (msg->hdr.direction != REMOTE_CALL) {
- remoteDispatchFormatError (&rerr, _("direction (%d) !=
REMOTE_CALL"),
- (int) msg->hdr.direction);
- goto rpc_error;
+ goto error;
}
if (msg->hdr.status != REMOTE_OK) {
remoteDispatchFormatError (&rerr, _("status (%d) != REMOTE_OK"),
(int) msg->hdr.status);
- goto rpc_error;
+ goto error;
+ }
+
+ switch (msg->hdr.direction) {
+ case REMOTE_CALL:
+ return remoteDispatchClientCall(server, client, msg);
+
+ default:
+ remoteDispatchFormatError (&rerr, _("direction (%d) !=
REMOTE_CALL"),
+ (int) msg->hdr.direction);
}
+error:
+ return remoteSerializeReplyError(client, &rerr, &msg->hdr);
+}
+
+
+/*
+ * @server: the unlocked server object
+ * @client: the locked client object
+ * @msg: the complete incoming method call, with header already decoded
+ *
+ * This method is used to dispatch an message representing an
+ * incoming method call from a client. It decodes the payload
+ * to obtain method call arguments, invokves the method and
+ * then sends a reply packet with the return values
+ *
+ * Returns 0 if the reply was sent, or -1 upon fatal error
+ */
+int
+remoteDispatchClientCall (struct qemud_server *server,
+ struct qemud_client *client,
+ struct qemud_client_message *msg)
+{
+ XDR xdr;
+ 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);
+
/* If client is marked as needing auth, don't allow any RPC ops,
* except for authentication ones
*/
@@ -332,7 +463,8 @@ remoteDispatchClientRequest (struct qemud_server *server,
xdr_free (data->args_filter, (char*)&args);
-rpc_error:
+ if (rv < 0)
+ goto rpc_error;
/* Return header. We're re-using same message object, so
* only need to tweak direction/status fields */
@@ -341,10 +473,10 @@ rpc_error:
/*msg->hdr.proc = msg->hdr.proc;*/
msg->hdr.direction = REMOTE_REPLY;
/*msg->hdr.serial = msg->hdr.serial;*/
- msg->hdr.status = rv < 0 ? REMOTE_ERROR : REMOTE_OK;
+ msg->hdr.status = REMOTE_OK;
if (remoteEncodeClientMessageHeader(msg) < 0) {
- if (rv == 0) xdr_free (data->ret_filter, (char*)&ret);
+ xdr_free (data->ret_filter, (char*)&ret);
goto fatal_error;
}
@@ -356,32 +488,24 @@ rpc_error:
XDR_ENCODE);
if (xdr_setpos(&xdr, msg->bufferOffset) == 0)
- goto fatal_error;
+ goto xdr_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);
- }
+ /* Serialise reply data */
+ if (!((data->ret_filter) (&xdr, &ret)))
+ goto xdr_error;
/* Update the length word. */
msg->bufferOffset += xdr_getpos (&xdr);
len = msg->bufferOffset;
if (xdr_setpos (&xdr, 0) == 0)
- goto fatal_error;
+ goto xdr_error;
if (!xdr_u_int (&xdr, &len))
- goto fatal_error;
+ goto xdr_error;
xdr_destroy (&xdr);
+ xdr_free (data->ret_filter, (char*)&ret);
/* Reset ready for I/O */
msg->bufferLength = len;
@@ -393,9 +517,17 @@ rpc_error:
return 0;
-fatal_error:
+rpc_error:
+ /* Semi-bad stuff happened, we can still try to send back
+ * an RPC error message to client */
+ return remoteSerializeReplyError(client, &rerr, &msg->hdr);
+
+
+xdr_error:
/* Seriously bad stuff happened, so we'll kill off this client
and not send back any RPC error */
+ xdr_free (data->ret_filter, (char*)&ret);
xdr_destroy (&xdr);
+fatal_error:
return -1;
}
--
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 :|