[Ocfs2-tools-devel] [PATCH 10/39] libo2cb: Add the client protocol files.

Joel Becker joel.becker at oracle.com
Fri Mar 14 16:52:33 PDT 2008


The control daemon protocol is added to libo2cb.  It is only built when
libcman is detected.

Signed-off-by: Joel Becker <joel.becker at oracle.com>
---
 include/o2cb/Makefile            |    2 +-
 include/o2cb/o2cb_client_proto.h |   66 ++++++++++
 libo2cb/Makefile                 |    9 +-
 libo2cb/client_proto.c           |  265 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 340 insertions(+), 2 deletions(-)
 create mode 100644 include/o2cb/o2cb_client_proto.h
 create mode 100644 libo2cb/client_proto.c

diff --git a/include/o2cb/Makefile b/include/o2cb/Makefile
index 59bfd7c..4fc0542 100644
--- a/include/o2cb/Makefile
+++ b/include/o2cb/Makefile
@@ -6,7 +6,7 @@ HFILES_GEN = o2cb_err.h
 
 all: $(HFILES_GEN)
 
-HFILES = o2cb.h ocfs2_nodemanager.h ocfs2_heartbeat.h
+HFILES = o2cb.h ocfs2_nodemanager.h ocfs2_heartbeat.h o2cb_client_proto.h
 
 HEADERS_SUBDIR = o2cb
 HEADERS = $(HFILES) $(HFILES_GEN)
diff --git a/include/o2cb/o2cb_client_proto.h b/include/o2cb/o2cb_client_proto.h
new file mode 100644
index 0000000..61df7c3
--- /dev/null
+++ b/include/o2cb/o2cb_client_proto.h
@@ -0,0 +1,66 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ */
+
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+/*
+ * Copyright (C) 2007 Oracle.  All rights reserved.
+ *
+ *  This copyrighted material is made available to anyone wishing to use,
+ *  modify, copy, or redistribute it subject to the terms and conditions
+ *  of the GNU General Public License v.2.
+ */
+
+#ifndef __O2CB_CLIENT_PROTO_H
+#define __O2CB_CLIENT_PROTO_H
+
+#ifdef HAVE_CMAN
+
+/* Basic communication properties */
+#define OCFS2_CONTROLD_MAXLINE		256
+#define OCFS2_CONTROLD_MAXARGS		16
+#define OCFS2_CONTROLD_SOCK_PATH	"ocfs2_controld_sock"
+#define O2CB_CONTROLD_SOCK_PATH		"o2cb_controld_sock"
+
+/* Client messages */
+typedef enum {
+	CM_MOUNT,
+	CM_MRESULT,
+	CM_UNMOUNT,
+	CM_STATUS,
+} client_message;
+
+int client_listen(const char *path);
+int client_connect(const char *path);
+
+static inline int ocfs2_client_listen(void)
+{
+	return client_listen(OCFS2_CONTROLD_SOCK_PATH);
+}
+
+static inline int ocfs2_client_connect(void)
+{
+	return client_connect(OCFS2_CONTROLD_SOCK_PATH);
+}
+
+const char *message_to_string(client_message message);
+int send_message(int fd, client_message message, ...);
+int receive_message(int fd, char *buf, client_message *message,
+		    char **argv);
+int receive_message_full(int fd, char *buf, client_message *message,
+			 char **argv, char **rest);
+
+#endif  /* HAVE_CMAN */
+
+#endif  /* __O2CB_CLIENT_PROTO_H */
diff --git a/libo2cb/Makefile b/libo2cb/Makefile
index 6d36ad2..9aa27c2 100644
--- a/libo2cb/Makefile
+++ b/libo2cb/Makefile
@@ -33,6 +33,8 @@ CFILES = 		\
 	o2cb_abi.c	\
 	o2cb_crc32.c
 
+PROTO_CFILES = client_proto.c
+
 HFILES =			\
 	o2cb_abi.h		\
 	o2cb_crc32.h
@@ -42,6 +44,11 @@ HFILES_GEN = o2cb_err.h
 OBJS = $(subst .c,.o,$(CFILES)) \
 	o2cb_err.o
 
+ifneq ($(BUILD_CMAN_SUPPORT),)
+DEFINES += -DHAVE_CMAN
+OBJS += $(subst .c,.o,$(PROTO_CFILES))
+endif
+
 $(OBJS): $(HFILES_GEN)
 
 o2cb_err.c o2cb_err.h: o2cb_err.et
@@ -52,7 +59,7 @@ libo2cb.a: $(OBJS)
 	$(AR) r $@ $^
 	$(RANLIB) $@
 
-DIST_FILES = $(CFILES) $(HFILES) o2cb_err.et
+DIST_FILES = $(CFILES) $(PROTO_CFILES) $(HFILES) o2cb_err.et
 
 CLEAN_RULES = clean-err
 
diff --git a/libo2cb/client_proto.c b/libo2cb/client_proto.c
new file mode 100644
index 0000000..a152cfa
--- /dev/null
+++ b/libo2cb/client_proto.c
@@ -0,0 +1,265 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * Copyright (C) 2007 Oracle.  All rights reserved.
+ *
+ *  This copyrighted material is made available to anyone wishing to use,
+ *  modify, copy, or redistribute it subject to the terms and conditions
+ *  of the GNU General Public License v.2.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "o2cb/o2cb_client_proto.h"
+
+struct client_message {
+	char *cm_command;
+	int cm_argcount;
+	char *cm_format;
+};
+
+#define BEGIN_MESSAGES(_list) struct client_message _list[] = {
+#define END_MESSAGES(_list) }; \
+	int _list##_len = sizeof(_list) / sizeof(_list[0]);
+#define DEFINE_MESSAGE(_name, _argcount, _format) [CM_##_name] = {	\
+	.cm_command = #_name, 				\
+	.cm_argcount = _argcount,			\
+	.cm_format = #_name " " _format,		\
+},
+
+BEGIN_MESSAGES(message_list)
+DEFINE_MESSAGE(MOUNT, 5, "%s %s %s %s %s")
+DEFINE_MESSAGE(MRESULT, 4, "%s %s %d %s")
+DEFINE_MESSAGE(UNMOUNT, 3, "%s %s %s")
+DEFINE_MESSAGE(STATUS, 2, "%d %s")
+END_MESSAGES(message_list)
+
+const char *message_to_string(client_message message)
+{
+	return message_list[message].cm_command;
+}
+
+/* No short reads allowed */
+static int full_read(int fd, void *buf, size_t count)
+{
+	size_t off = 0;
+	ssize_t rc = 0;
+
+	while (off < count) {
+		rc = read(fd, buf + off, count - off);
+		if (rc == 0)
+			return -EPIPE;
+		if (rc == -1) {
+			rc = -errno;
+			if (rc == -EINTR)
+				continue;
+			break;
+		}
+		off += rc;
+		rc = 0;
+	}
+	return rc;
+}
+
+/* No short writes allowed */
+static int full_write(int fd, void *buf, size_t count)
+{
+	size_t off = 0;
+	ssize_t rc = 0;
+
+	while (off < count) {
+		rc = write(fd, buf + off, count - off);
+		if (rc == 0)
+			return -EPIPE;
+		if (rc == -1) {
+			rc = -errno;
+			if (rc == -EINTR)
+				continue;
+			break;
+		}
+		off += rc;
+		rc = 0;
+	}
+	return rc;
+}
+
+int send_message(int fd, client_message message, ...)
+{
+	int rc;
+	va_list args;
+	char mbuf[OCFS2_CONTROLD_MAXLINE];
+
+	memset(mbuf, 0, OCFS2_CONTROLD_MAXLINE);
+	va_start(args, message);
+	rc = vsnprintf(mbuf, OCFS2_CONTROLD_MAXLINE,
+		       message_list[message].cm_format, args);
+	va_end(args);
+	if (rc >= OCFS2_CONTROLD_MAXLINE)
+		rc = -E2BIG;
+	else
+		rc = full_write(fd, mbuf, OCFS2_CONTROLD_MAXLINE);
+
+	return rc;
+}
+
+static char *get_args(char *buf, int *argc, char **argv, char sep, int want)
+{
+	char *p = buf, *rp = NULL;
+	int i = 0;
+
+	/* Skip the first word, which is the command */
+	p = strchr(buf, sep);
+	if (!p)
+		goto out;
+	p += 1;
+	argv[0] = p;
+
+	for (i = 1; i < OCFS2_CONTROLD_MAXARGS; i++) {
+		p = strchr(p, sep);
+		if (!p) {
+			rp = p + 1;
+			break;
+		}
+
+		if (want == i)
+			break;
+
+		*p = '\0';
+		p += 1;
+		argv[i] = p;
+	}
+
+out:
+	if (argc)
+		*argc = i;
+
+	/* Terminate the list, the caller expects us to */
+	argv[i] = NULL;
+
+	/* we ended by hitting \0, return the point following that */
+	if (!rp)
+		rp = strchr(buf, '\0') + 1;
+
+	return rp;
+}
+
+int receive_message_full(int fd, char *buf, client_message *message,
+			 char **argv, char **rest)
+{
+	int i, rc, len, count;
+	client_message msg;
+	char *r;
+
+	rc = full_read(fd, buf, OCFS2_CONTROLD_MAXLINE);
+	if (rc)
+		goto out;
+
+	/* Safety first */
+	buf[OCFS2_CONTROLD_MAXLINE - 1] = '\0';
+	/* fprintf(stderr, "Got messsage \"%s\"\n", buf); */
+
+
+	for (i = 0; i < message_list_len; i++) {
+		len = strlen(message_list[i].cm_command);
+		if (!strncmp(buf, message_list[i].cm_command, len) &&
+		    (buf[len] == ' '))
+			break;
+	}
+	if (i >= message_list_len) {
+		rc = -EBADMSG;
+		goto out;
+	}
+	msg = i;
+
+	r = get_args(buf, &count, argv, ' ',
+		     message_list[msg].cm_argcount);
+	if (count != message_list[msg].cm_argcount) {
+		rc = -EBADMSG;
+	} else {
+		/* for (i = 0; i < count; i++)
+			fprintf(stderr, "Arg %d: \"%s\"\n", i, argv[i]); */
+		if (message)
+			*message = msg;
+		if (rest)
+			*rest = r;
+	}
+
+out:
+	return rc;
+}
+
+int receive_message(int fd, char *buf, client_message *message, char **argv)
+{
+	return receive_message_full(fd, buf, message, argv, NULL);
+}
+
+int client_listen(const char *path)
+{
+	struct sockaddr_un addr;
+	socklen_t addrlen;
+	int rv, s;
+
+	/* we listen for new client connections on socket s */
+
+	s = socket(AF_LOCAL, SOCK_STREAM, 0);
+	if (s < 0) {
+		/* log_error("socket error %d %d", s, errno); */
+		return s;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_LOCAL;
+	strcpy(&addr.sun_path[1], path);
+	addrlen = sizeof(sa_family_t) + strlen(addr.sun_path+1) + 1;
+
+	rv = bind(s, (struct sockaddr *) &addr, addrlen);
+	if (rv < 0) {
+		/* log_error("bind error %d %d", rv, errno); */
+		close(s);
+		return rv;
+	}
+
+	rv = listen(s, 5);
+	if (rv < 0) {
+		/* log_error("listen error %d %d", rv, errno); */
+		close(s);
+		return rv;
+	}
+
+	/* log_debug("listen %d", s); */
+
+	return s;
+}
+
+int client_connect(const char *path)
+{
+	struct sockaddr_un sun;
+	socklen_t addrlen;
+	int rv, fd;
+
+	fd = socket(PF_UNIX, SOCK_STREAM, 0);
+	if (fd < 0) {
+		fd = -errno;
+		goto out;
+	}
+
+	memset(&sun, 0, sizeof(sun));
+	sun.sun_family = AF_UNIX;
+	strcpy(&sun.sun_path[1], path);
+	addrlen = sizeof(sa_family_t) + strlen(sun.sun_path+1) + 1;
+
+	rv = connect(fd, (struct sockaddr *) &sun, addrlen);
+	if (rv < 0) {
+		close(fd);
+		fd = -errno;
+	}
+ out:
+	return fd;
+}
-- 
1.5.3.8




More information about the Ocfs2-tools-devel mailing list