Просмотр исходного кода

Qdevice: Add IPC clients

Signed-off-by: Jan Friesse <jfriesse@redhat.com>
Jan Friesse 9 лет назад
Родитель
Сommit
91b1f44e8f

+ 2 - 0
corosync.spec.in

@@ -386,6 +386,7 @@ fi
 %defattr(-,root,root,-)
 %{_sbindir}/corosync-qdevice
 %{_sbindir}/corosync-qdevice-net-certutil
+%{_sbindir}/corosync-qdevice-tool
 %if %{with systemd}
 %{_unitdir}/corosync-qdevice.service
 %dir %{_datadir}/corosync
@@ -437,6 +438,7 @@ fi
 %defattr(-,root,root,-)
 %{_sbindir}/corosync-qnetd
 %{_sbindir}/corosync-qnetd-certutil
+%{_sbindir}/corosync-qnetd-tool
 %if %{with systemd}
 %{_unitdir}/corosync-qnetd.service
 %dir %{_datadir}/corosync

+ 2 - 1
qdevices/.gitignore

@@ -1,6 +1,7 @@
-corosync-qdevice-net
 corosync-qdevice
+corosync-qdevice-tool
 corosync-qnetd-certutil
 corosync-qdevice-net-certutil
 corosync-qnetd
+corosync-qnetd-tool
 *.test

+ 8 - 1
qdevices/Makefile.am

@@ -35,7 +35,8 @@ if BUILD_QDEVICES
 
 SUBDIRS			=
 
-sbin_PROGRAMS		= corosync-qnetd corosync-qdevice
+sbin_PROGRAMS		= corosync-qnetd corosync-qdevice corosync-qnetd-tool \
+                          corosync-qdevice-tool
 
 sbin_SCRIPTS            = corosync-qnetd-certutil corosync-qdevice-net-certutil
 
@@ -99,6 +100,12 @@ corosync_qdevice_SOURCES = corosync-qdevice.c \
                            qdevice-config.h qnet-config.h qdevice-net-disconnect-reason.h \
                            qdevice-model-type.h
 
+corosync_qnetd_tool_SOURCES = corosync-qnetd-tool.c unix-socket.c unix-socket.h dynar.c dynar.h \
+                              dynar-str.c dynar-str.h
+
+corosync_qdevice_tool_SOURCES = corosync-qdevice-tool.c unix-socket.c unix-socket.h dynar.c dynar.h \
+                                dynar-str.c dynar-str.h
+
 corosync_qnetd_CFLAGS		= $(nss_CFLAGS)
 corosync_qnetd_LDADD		= $(nss_LIBS)
 

+ 280 - 0
qdevices/corosync-qdevice-tool.c

@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2015-2016 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Jan Friesse (jfriesse@redhat.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the Red Hat, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "qdevice-config.h"
+
+#include "dynar.h"
+#include "dynar-str.h"
+#include "utils.h"
+#include "unix-socket.h"
+
+#define IPC_READ_BUF_SIZE	512
+
+enum qdevice_tool_operation {
+	QDEVICE_TOOL_OPERATION_NONE,
+	QDEVICE_TOOL_OPERATION_SHUTDOWN,
+	QDEVICE_TOOL_OPERATION_STATUS,
+};
+
+enum qdevice_tool_exit_code {
+	QDEVICE_TOOL_EXIT_CODE_NO_ERROR = 0,
+	QDEVICE_TOOL_EXIT_CODE_USAGE = 1,
+	QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR = 2,
+	QDEVICE_TOOL_EXIT_CODE_SOCKET_CONNECT = 3,
+	QDEVICE_TOOL_EXIT_CODE_QDEVICE_RETURNED_ERROR = 4,
+};
+
+static void
+usage(void)
+{
+
+	printf("usage: %s [-Hhsv] [-p qdevice_ipc_socket_path]\n",
+	    QDEVICE_TOOL_PROGRAM_NAME);
+}
+
+static void
+cli_parse(int argc, char * const argv[], enum qdevice_tool_operation *operation,
+    int *verbose, char **socket_path)
+{
+	int ch;
+
+	*operation = QDEVICE_TOOL_OPERATION_NONE;
+	*verbose = 0;
+	*socket_path = strdup(QDEVICE_LOCAL_SOCKET_FILE);
+
+	if (*socket_path == NULL) {
+		errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR,
+		    "Can't alloc memory for socket path string");
+	}
+
+	while ((ch = getopt(argc, argv, "Hhsvp:")) != -1) {
+		switch (ch) {
+		case 'H':
+			*operation = QDEVICE_TOOL_OPERATION_SHUTDOWN;
+			break;
+		case 's':
+			*operation = QDEVICE_TOOL_OPERATION_STATUS;
+			break;
+		case 'v':
+			*verbose = 1;
+			break;
+		case 'p':
+			free(*socket_path);
+			*socket_path = strdup(optarg);
+			if (*socket_path == NULL) {
+				errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR,
+				    "Can't alloc memory for socket path string");
+			}
+			break;
+		case 'h':
+		case '?':
+			usage();
+			exit(QDEVICE_TOOL_EXIT_CODE_USAGE);
+			break;
+		}
+	}
+
+	if (*operation == QDEVICE_TOOL_OPERATION_NONE) {
+		usage();
+		exit(QDEVICE_TOOL_EXIT_CODE_USAGE);
+	}
+}
+
+static int
+store_command(struct dynar *str, enum qdevice_tool_operation operation, int verbose)
+{
+	const char *nline = "\n\0";
+	const int nline_len = 2;
+
+	switch (operation) {
+	case QDEVICE_TOOL_OPERATION_NONE:
+		errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Unhandled operation none");
+		break;
+	case QDEVICE_TOOL_OPERATION_SHUTDOWN:
+		if (dynar_str_cat(str, "shutdown ") != 0) {
+			return (-1);
+		}
+		break;
+	case QDEVICE_TOOL_OPERATION_STATUS:
+		if (dynar_str_cat(str, "status ") != 0) {
+			return (-1);
+		}
+		break;
+	}
+
+	if (verbose) {
+		if (dynar_str_cat(str, "verbose ") != 0) {
+			return (-1);
+		}
+	}
+
+	if (dynar_cat(str, nline, nline_len) != 0) {
+		return (-1);
+	}
+
+	return (0);
+}
+
+/*
+ * -1 - Internal error (can't alloc memory)
+ *  0 - No error
+ *  1 - IPC returned error
+ *  2 - Unknown status line
+ */
+static int
+read_ipc_reply(FILE *f)
+{
+	struct dynar read_str;
+	int ch;
+	int status_readed;
+	int res;
+	static const char *ok_str = "OK";
+	static const char *err_str = "Error";
+	int err_set;
+	char c;
+
+	dynar_init(&read_str, IPC_READ_BUF_SIZE);
+
+	status_readed = 0;
+	err_set = 0;
+	res = 0;
+
+	while ((ch = fgetc(f)) != EOF) {
+		if (status_readed) {
+			putc(ch, (err_set ? stderr : stdout));
+		} else {
+			if (ch == '\r') {
+			} else if (ch == '\n') {
+				status_readed = 1;
+
+				c = '\0';
+				if (dynar_cat(&read_str, &c, sizeof(c)) != 0) {
+					res = -1;
+					goto exit_destroy;
+				}
+
+				if (strcasecmp(dynar_data(&read_str), ok_str) == 0) {
+				} else if (strcasecmp(dynar_data(&read_str), err_str) == 0) {
+					err_set = 1;
+					res = 1;
+					fprintf(stderr, "Error: ");
+				} else {
+					res = 2;
+					goto exit_destroy;
+				}
+			} else {
+				c = ch;
+				if (dynar_cat(&read_str, &c, sizeof(c)) != 0) {
+					res = -1;
+					goto exit_destroy;
+				}
+			}
+		}
+	}
+
+exit_destroy:
+	dynar_destroy(&read_str);
+
+	return (res);
+}
+
+int
+main(int argc, char * const argv[])
+{
+	enum qdevice_tool_operation operation;
+	int verbose;
+	char *socket_path;
+	int sock_fd;
+	FILE *sock;
+	struct dynar send_str;
+	int res;
+	int exit_code;
+
+	exit_code = QDEVICE_TOOL_EXIT_CODE_NO_ERROR;
+
+	cli_parse(argc, argv, &operation, &verbose, &socket_path);
+
+	dynar_init(&send_str, QDEVICE_IPC_MAX_RECEIVE_SIZE);
+
+	sock_fd = unix_socket_client_create(socket_path, 0);
+	if (sock_fd == -1) {
+		err(QDEVICE_TOOL_EXIT_CODE_SOCKET_CONNECT,
+		    "Can't connect to QDevice socket (is QDevice running?)");
+	}
+
+	sock = fdopen(sock_fd, "w+t");
+	if (sock == NULL) {
+		err(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't open QDevice socket fd");
+	}
+
+	if (store_command(&send_str, operation, verbose) != 0) {
+		errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't store command");
+	}
+
+	if (fprintf(sock, "%s", dynar_data(&send_str)) != strlen(dynar_data(&send_str)) ||
+	    fflush(sock) != 0) {
+		errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't send command");
+	}
+
+	res = read_ipc_reply(sock);
+	switch (res) {
+	case -1:
+		errx(QDEVICE_TOOL_EXIT_CODE_INTERNAL_ERROR, "Internal error during IPC status line read");
+		break;
+	case 0:
+		break;
+	case 1:
+		exit_code = QDEVICE_TOOL_EXIT_CODE_QDEVICE_RETURNED_ERROR;
+		break;
+	case 2:
+		errx(QDEVICE_TOOL_EXIT_CODE_SOCKET_CONNECT, "Unknown status line returned by IPC server");
+		break;
+	}
+
+	if (fclose(sock) != 0) {
+		warn("Can't close QDevice socket");
+	}
+
+	free(socket_path);
+	dynar_destroy(&send_str);
+
+	return (exit_code);
+}

+ 309 - 0
qdevices/corosync-qnetd-tool.c

@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2015-2016 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Jan Friesse (jfriesse@redhat.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the Red Hat, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "qnet-config.h"
+
+#include "dynar.h"
+#include "dynar-str.h"
+#include "utils.h"
+#include "unix-socket.h"
+
+#define IPC_READ_BUF_SIZE	512
+
+enum qnetd_tool_operation {
+	QNETD_TOOL_OPERATION_NONE,
+	QNETD_TOOL_OPERATION_SHUTDOWN,
+	QNETD_TOOL_OPERATION_STATUS,
+	QNETD_TOOL_OPERATION_LIST,
+};
+
+enum qnetd_tool_exit_code {
+	QNETD_TOOL_EXIT_CODE_NO_ERROR = 0,
+	QNETD_TOOL_EXIT_CODE_USAGE = 1,
+	QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR = 2,
+	QNETD_TOOL_EXIT_CODE_SOCKET_CONNECT = 3,
+	QNETD_TOOL_EXIT_CODE_QNETD_RETURNED_ERROR = 4,
+};
+
+static void
+usage(void)
+{
+
+	printf("usage: %s [-Hhlsv] [-c cluster_name] [-p qnetd_ipc_socket_path]\n",
+	    QNETD_TOOL_PROGRAM_NAME);
+}
+
+static void
+cli_parse(int argc, char * const argv[], enum qnetd_tool_operation *operation,
+    int *verbose, char **cluster_name, char **socket_path)
+{
+	int ch;
+
+	*operation = QNETD_TOOL_OPERATION_NONE;
+	*verbose = 0;
+	*cluster_name = NULL;
+	*socket_path = strdup(QNETD_LOCAL_SOCKET_FILE);
+
+	if (*socket_path == NULL) {
+		errx(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR,
+		    "Can't alloc memory for socket path string");
+	}
+
+	while ((ch = getopt(argc, argv, "Hhlsvc:p:")) != -1) {
+		switch (ch) {
+		case 'H':
+			*operation = QNETD_TOOL_OPERATION_SHUTDOWN;
+			break;
+		case 'l':
+			*operation = QNETD_TOOL_OPERATION_LIST;
+			break;
+		case 's':
+			*operation = QNETD_TOOL_OPERATION_STATUS;
+			break;
+		case 'v':
+			*verbose = 1;
+			break;
+		case 'c':
+			free(*cluster_name);
+			*cluster_name = strdup(optarg);
+			if (*cluster_name == NULL) {
+				errx(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR,
+				    "Can't alloc memory for cluster name string");
+			}
+			break;
+		case 'p':
+			free(*socket_path);
+			*socket_path = strdup(optarg);
+			if (*socket_path == NULL) {
+				errx(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR,
+				    "Can't alloc memory for socket path string");
+			}
+			break;
+		case 'h':
+		case '?':
+			usage();
+			exit(QNETD_TOOL_EXIT_CODE_USAGE);
+			break;
+		}
+	}
+
+	if (*operation == QNETD_TOOL_OPERATION_NONE) {
+		usage();
+		exit(QNETD_TOOL_EXIT_CODE_USAGE);
+	}
+}
+
+static int
+store_command(struct dynar *str, enum qnetd_tool_operation operation, int verbose,
+    const char *cluster_name)
+{
+	const char *nline = "\n\0";
+	const int nline_len = 2;
+
+	switch (operation) {
+	case QNETD_TOOL_OPERATION_NONE:
+		errx(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR, "Unhandled operation none");
+		break;
+	case QNETD_TOOL_OPERATION_SHUTDOWN:
+		if (dynar_str_cat(str, "shutdown ") != 0) {
+			return (-1);
+		}
+		break;
+	case QNETD_TOOL_OPERATION_STATUS:
+		if (dynar_str_cat(str, "status ") != 0) {
+			return (-1);
+		}
+		break;
+	case QNETD_TOOL_OPERATION_LIST:
+		if (dynar_str_cat(str, "list ") != 0) {
+			return (-1);
+		}
+		break;
+	}
+
+	if (verbose) {
+		if (dynar_str_cat(str, "verbose ") != 0) {
+			return (-1);
+		}
+	}
+
+	if (cluster_name != NULL) {
+		if (dynar_str_cat(str, "cluster ") != 0 ||
+		    dynar_str_quote_cat(str, cluster_name) != 0 ||
+		    dynar_str_cat(str, " ") != 0) {
+			return (-1);
+		}
+	}
+
+	if (dynar_cat(str, nline, nline_len) != 0) {
+		return (-1);
+	}
+
+	return (0);
+}
+
+/*
+ * -1 - Internal error (can't alloc memory)
+ *  0 - No error
+ *  1 - IPC returned error
+ *  2 - Unknown status line
+ */
+static int
+read_ipc_reply(FILE *f)
+{
+	struct dynar read_str;
+	int ch;
+	int status_readed;
+	int res;
+	static const char *ok_str = "OK";
+	static const char *err_str = "Error";
+	int err_set;
+	char c;
+
+	dynar_init(&read_str, IPC_READ_BUF_SIZE);
+
+	status_readed = 0;
+	err_set = 0;
+	res = 0;
+
+	while ((ch = fgetc(f)) != EOF) {
+		if (status_readed) {
+			putc(ch, (err_set ? stderr : stdout));
+		} else {
+			if (ch == '\r') {
+			} else if (ch == '\n') {
+				status_readed = 1;
+
+				c = '\0';
+				if (dynar_cat(&read_str, &c, sizeof(c)) != 0) {
+					res = -1;
+					goto exit_destroy;
+				}
+
+				if (strcasecmp(dynar_data(&read_str), ok_str) == 0) {
+				} else if (strcasecmp(dynar_data(&read_str), err_str) == 0) {
+					err_set = 1;
+					res = 1;
+					fprintf(stderr, "Error: ");
+				} else {
+					res = 2;
+					goto exit_destroy;
+				}
+			} else {
+				c = ch;
+				if (dynar_cat(&read_str, &c, sizeof(c)) != 0) {
+					res = -1;
+					goto exit_destroy;
+				}
+			}
+		}
+	}
+
+exit_destroy:
+	dynar_destroy(&read_str);
+
+	return (res);
+}
+
+int
+main(int argc, char * const argv[])
+{
+	enum qnetd_tool_operation operation;
+	int verbose;
+	char *cluster_name;
+	char *socket_path;
+	int sock_fd;
+	FILE *sock;
+	struct dynar send_str;
+	int res;
+	int exit_code;
+
+	exit_code = QNETD_TOOL_EXIT_CODE_NO_ERROR;
+
+	cli_parse(argc, argv, &operation, &verbose, &cluster_name, &socket_path);
+
+	dynar_init(&send_str, QNETD_IPC_MAX_RECEIVE_SIZE);
+
+	sock_fd = unix_socket_client_create(socket_path, 0);
+	if (sock_fd == -1) {
+		err(QNETD_TOOL_EXIT_CODE_SOCKET_CONNECT,
+		    "Can't connect to qnetd socket (is QNetd running?)");
+	}
+
+	sock = fdopen(sock_fd, "w+t");
+	if (sock == NULL) {
+		err(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't open QNetd socket fd");
+	}
+
+	if (store_command(&send_str, operation, verbose, cluster_name) != 0) {
+		errx(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't store command");
+	}
+
+	if (fprintf(sock, "%s", dynar_data(&send_str)) != strlen(dynar_data(&send_str)) ||
+	    fflush(sock) != 0) {
+		errx(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR, "Can't send command");
+	}
+
+	res = read_ipc_reply(sock);
+	switch (res) {
+	case -1:
+		errx(QNETD_TOOL_EXIT_CODE_INTERNAL_ERROR, "Internal error during IPC status line read");
+		break;
+	case 0:
+		break;
+	case 1:
+		exit_code = QNETD_TOOL_EXIT_CODE_QNETD_RETURNED_ERROR;
+		break;
+	case 2:
+		errx(QNETD_TOOL_EXIT_CODE_SOCKET_CONNECT, "Unknown status line returned by IPC server");
+		break;
+	}
+
+	if (fclose(sock) != 0) {
+		warn("Can't close QNetd socket");
+	}
+
+	free(cluster_name);
+	free(socket_path);
+	dynar_destroy(&send_str);
+
+	return (exit_code);
+}

+ 4 - 0
qdevices/corosync-qnetd.c

@@ -386,7 +386,11 @@ cli_parse(int argc, char * const argv[], char **host_addr, uint16_t *host_port,
 			}
 			break;
 		case 'l':
+			free(*host_addr);
 			*host_addr = strdup(optarg);
+			if (*host_addr == NULL) {
+				errx(1, "Can't alloc memory for host addr string");
+			}
 			break;
 		case 'm':
 			errno = 0;

+ 2 - 0
qdevices/qdevice-config.h

@@ -74,6 +74,8 @@ extern "C" {
 #define QDEVICE_IPC_MAX_RECEIVE_SIZE		(4*1024)
 #define QDEVICE_IPC_MAX_SEND_SIZE		(64*1024)
 
+#define QDEVICE_TOOL_PROGRAM_NAME		"corosync-qdevice-tool"
+
 #ifdef __cplusplus
 }
 #endif

+ 3 - 0
qdevices/qnet-config.h

@@ -84,6 +84,9 @@ extern "C" {
 #define QDEVICE_NET_MAX_MSG_RECEIVE_SIZE	(1 << 24)
 
 #define QNETD_NSS_SERVER_CN			"Qnetd Server"
+
+#define QNETD_TOOL_PROGRAM_NAME			"corosync-qnetd-tool"
+
 #define QDEVICE_NET_NSS_CLIENT_CERT_NICKNAME	"Cluster Cert"
 
 #define QDEVICE_NET_MAX_SEND_BUFFERS		10

+ 39 - 0
qdevices/unix-socket.c

@@ -103,6 +103,45 @@ unix_socket_server_create(const char *path, int non_blocking, int backlog)
 	return (s);
 }
 
+int
+unix_socket_client_create(const char *path, int non_blocking)
+{
+	int s;
+	struct sockaddr_un sun;
+
+	if (strlen(path) >= sizeof(sun.sun_path)) {
+		errno = ENAMETOOLONG;
+		return (-1);
+	}
+
+	if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+		return (-1);
+	}
+
+	memset(&sun, 0, sizeof(sun));
+	sun.sun_family = AF_UNIX;
+
+	strncpy(sun.sun_path, path, sizeof(sun.sun_path));
+
+	if (non_blocking) {
+		if (unix_socket_set_non_blocking(s) != 0) {
+			close(s);
+
+			return (-1);
+		}
+	}
+
+	if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) != 0) {
+		close(s);
+
+		return (-1);
+	}
+
+	return (s);
+}
+
+
+
 int
 unix_socket_server_destroy(int sock, const char *path)
 {

+ 2 - 0
qdevices/unix-socket.h

@@ -44,6 +44,8 @@ extern "C" {
 
 extern int		unix_socket_server_create(const char *path, int non_blocking, int backlog);
 
+extern int		unix_socket_client_create(const char *path, int non_blocking);
+
 extern int		unix_socket_server_destroy(int sock, const char *path);
 
 extern int		unix_socket_server_accept(int sock, int non_blocking);