changeset 127:ed287ae023f2

client: handle dispatching of RPC handlers generically Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Sun, 18 Oct 2015 09:42:33 -0400
parents 490342afe46b
children 3e57d8dd41b5
files src/client/CMakeLists.txt src/client/cmd_nop.c src/client/cmds.c src/client/cmds.h src/client/main.c
diffstat 5 files changed, 179 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- a/src/client/CMakeLists.txt	Sun Oct 18 08:34:04 2015 -0400
+++ b/src/client/CMakeLists.txt	Sun Oct 18 09:42:33 2015 -0400
@@ -22,6 +22,9 @@
 
 add_executable(nomad-client
 	main.c
+	cmds.c
+
+	# assorted RPC handlers
 	cmd_nop.c
 )
 
--- a/src/client/cmd_nop.c	Sun Oct 18 08:34:04 2015 -0400
+++ b/src/client/cmd_nop.c	Sun Oct 18 09:42:33 2015 -0400
@@ -22,7 +22,7 @@
 
 #include "cmds.h"
 
-int cmd_nop(void)
+int cmd_nop(union cmd *cmd)
 {
 	return 0;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/client/cmds.c	Sun Oct 18 09:42:33 2015 -0400
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2015 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <nomad/error.h>
+#include <nomad/rpc_fs.h>
+
+#include "cmds.h"
+
+#define CMD(op, what, hndlr)				\
+	{						\
+		.name = #op,				\
+		.opcode = (op),				\
+		.handler = (hndlr),			\
+	}
+
+static const struct cmdtbl {
+	const char *name;
+	uint16_t opcode;
+	int (*handler)(union cmd *);
+	size_t reqoff;
+	size_t resoff;
+
+	/*
+	 * We cheat a bit and make the arg void * even though it has a more
+	 * specific type (e.g., xdr_login_req).
+	 */
+	bool_t (*req)(XDR *, void *);
+	bool_t (*res)(XDR *, void *);
+} cmdtbl[] = {
+	CMD        (NRPC_NOP,           nop,           cmd_nop),
+};
+
+#define MAP_ERRNO(errno)		\
+	case errno:			\
+		cmd.err = NERR_##errno;	\
+		break
+
+static bool send_response(XDR *xdr, int fd, int err)
+{
+	struct rpc_header_res cmd;
+	int ret;
+
+	switch (err) {
+		MAP_ERRNO(ENOENT);
+		MAP_ERRNO(EEXIST);
+		case 0:
+			cmd.err = NERR_SUCCESS;
+			break;
+		default:
+			fprintf(stderr, "%s cannot map errno %d (%s) to NERR_*\n",
+				__func__, err, strerror(err));
+			cmd.err = NERR_UNKNOWN_ERROR;
+			break;
+	}
+
+	xdr_destroy(xdr);
+	xdrfd_create(xdr, fd, XDR_ENCODE);
+
+	ret = xdr_rpc_header_res(xdr, &cmd);
+	if (!ret)
+		return false; /* failed to send */
+
+	if (cmd.err != NERR_SUCCESS)
+		return false; /* RPC failed */
+
+	return true; /* all good */
+}
+
+static bool fetch_args(XDR *xdr, const struct cmdtbl *def, void *cmd)
+{
+	if (!def->req(xdr, cmd + def->reqoff))
+		return false;
+
+	return true;
+}
+
+static bool send_returns(XDR *xdr, const struct cmdtbl *def, void *cmd)
+{
+	if (!def->res(xdr, cmd + def->resoff))
+		return false;
+
+	return true;
+}
+
+bool process_connection(int fd)
+{
+	struct rpc_header_req hdr;
+	union cmd cmd;
+	bool ok = false;
+	size_t i;
+	XDR xdr;
+
+	memset(&hdr, 0, sizeof(struct rpc_header_req));
+	memset(&cmd, 0, sizeof(union cmd));
+
+	xdrfd_create(&xdr, fd, XDR_DECODE);
+
+	if (!xdr_rpc_header_req(&xdr, &hdr))
+		goto out;
+
+	printf("got opcode %u\n", hdr.opcode);
+
+	for (i = 0; i < ARRAY_LEN(cmdtbl); i++) {
+		const struct cmdtbl *def = &cmdtbl[i];
+		int ret;
+
+		if (def->opcode != hdr.opcode)
+			continue;
+
+		/*
+		 * we found the command handler
+		 */
+		printf("opcode decoded as: %s\n", def->name);
+
+		/* fetch arguments */
+		if (def->req) {
+			ok = fetch_args(&xdr, def, &cmd);
+			if (!ok) {
+				printf("failed to fetch args\n");
+				goto out;
+			}
+		}
+
+		/* invoke the handler */
+		ret = def->handler(&cmd);
+
+		/* send back the response header */
+		ok = send_response(&xdr, fd, ret);
+
+		/* send back the response payload */
+		if (ok && def->res)
+			ok = send_returns(&xdr, def, &cmd);
+
+		goto out;
+	}
+
+	send_response(&xdr, fd, ENOTSUP);
+
+out:
+	xdr_destroy(&xdr);
+
+	return ok;
+}
--- a/src/client/cmds.h	Sun Oct 18 08:34:04 2015 -0400
+++ b/src/client/cmds.h	Sun Oct 18 09:42:33 2015 -0400
@@ -23,6 +23,15 @@
 #ifndef __NOMAD_CLIENT_CMDS_H
 #define __NOMAD_CLIENT_CMDS_H
 
-int cmd_nop(void);
+#include <nomad/rpc_fs.h>
+
+union cmd {
+	/* nop - no req & no res */
+};
+
+extern bool process_connection(int fd);
+
+/* RPC handlers */
+extern int cmd_nop(union cmd *cmd);
 
 #endif
--- a/src/client/main.c	Sun Oct 18 08:34:04 2015 -0400
+++ b/src/client/main.c	Sun Oct 18 09:42:33 2015 -0400
@@ -28,78 +28,16 @@
 #include <nomad/types.h>
 #include <nomad/objstore.h>
 #include <nomad/connsvc.h>
-#include <nomad/rpc_fs.h>
 
 #include "cmds.h"
 
 #define CLIENT_DAEMON_PORT	2323
 
-#define MAP_ERRNO(errno)		\
-	case errno:			\
-		cmd.err = NERR_##errno;	\
-		break
-
-static bool send_response(XDR *xdr, int fd, int err)
-{
-	struct rpc_header_res cmd;
-	int ret;
-
-	switch (err) {
-		MAP_ERRNO(ENOENT);
-		MAP_ERRNO(EEXIST);
-		case 0:
-			cmd.err = NERR_SUCCESS;
-			break;
-		default:
-			fprintf(stderr, "%s cannot map errno %d (%s) to NERR_*\n",
-				__func__, err, strerror(err));
-			cmd.err = NERR_UNKNOWN_ERROR;
-			break;
-	}
-
-	xdr_destroy(xdr);
-	xdrfd_create(xdr, fd, XDR_ENCODE);
-
-	ret = xdr_rpc_header_res(xdr, &cmd);
-
-	return ret ? true : false;
-}
-
-static bool process_command(int fd)
-{
-	struct rpc_header_req cmd;
-	bool ok = false;
-	int ret;
-	XDR xdr;
-
-	xdrfd_create(&xdr, fd, XDR_DECODE);
-
-	if (!xdr_rpc_header_req(&xdr, &cmd))
-		goto err;
-
-	printf("got opcode %u\n", cmd.opcode);
-
-	switch (cmd.opcode) {
-		case NRPC_NOP:
-			ret = cmd_nop();
-			ok = send_response(&xdr, fd, ret);
-			break;
-		default:
-			send_response(&xdr, fd, ENOTSUP);
-			break;
-	}
-
-err:
-	xdr_destroy(&xdr);
-
-	return ok;
-}
-
-static void process_connection(int fd, void *arg)
+static void connection_acceptor(int fd, void *arg)
 {
 	printf("%s: fd = %d, arg = %p\n", __func__, fd, arg);
 
-	while (process_command(fd))
+	while (process_connection(fd))
 		;
 }
 
@@ -146,7 +84,7 @@
 		goto err_vg;
 	}
 
-	ret = connsvc(NULL, CLIENT_DAEMON_PORT, process_connection, vg);
+	ret = connsvc(NULL, CLIENT_DAEMON_PORT, connection_acceptor, vg);
 
 	fprintf(stderr, "connsvc() = %d (%s)\n", ret, strerror(ret));