summaryrefslogtreecommitdiff
path: root/usr/src/cmd/stmfproxy
diff options
context:
space:
mode:
authorJohn Forte <John.Forte@Sun.COM>2009-10-06 19:56:15 -0700
committerJohn Forte <John.Forte@Sun.COM>2009-10-06 19:56:15 -0700
commit450396635f70344c58b6b1e4db38cf17ff34445c (patch)
treefa089b0718400774602b3f29e7e9b326795e2a9b /usr/src/cmd/stmfproxy
parentbd963cb9a079e6b9cd23645670bf4b0185cbfe4c (diff)
downloadillumos-joyent-450396635f70344c58b6b1e4db38cf17ff34445c.tar.gz
PSARC/2009/465 COMSTAR ALUA active/standby support
6862774 Add support for ALUA to COMSTAR 6878583 mem leak in stmfGetLuResource() 6850890 stmfTargetProperties.protocol is not populated for stmfGetTargetProperties()
Diffstat (limited to 'usr/src/cmd/stmfproxy')
-rw-r--r--usr/src/cmd/stmfproxy/Makefile55
-rw-r--r--usr/src/cmd/stmfproxy/aluaadm/Makefile80
-rw-r--r--usr/src/cmd/stmfproxy/aluaadm/aluaadm.c240
-rw-r--r--usr/src/cmd/stmfproxy/stmfproxy/Makefile103
-rw-r--r--usr/src/cmd/stmfproxy/stmfproxy/stmfproxy.c541
-rw-r--r--usr/src/cmd/stmfproxy/stmfproxy/stmfproxy.xml112
6 files changed, 1131 insertions, 0 deletions
diff --git a/usr/src/cmd/stmfproxy/Makefile b/usr/src/cmd/stmfproxy/Makefile
new file mode 100644
index 0000000000..26cfe571f4
--- /dev/null
+++ b/usr/src/cmd/stmfproxy/Makefile
@@ -0,0 +1,55 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/aluademo/Makefile
+#
+
+include ../Makefile.cmd
+
+SUBDIRS = stmfproxy aluaadm
+
+all := TARGET= all
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+lint := TARGET= lint
+cstyle := TARGET= cstyle
+check := TARGET= check
+
+.KEEP_STATE:
+
+all install cstyle lint : $(SUBDIRS)
+
+check: stmfproxy
+
+clean: $(SUBDIRS)
+
+clobber: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/Makefile.msg.targ
diff --git a/usr/src/cmd/stmfproxy/aluaadm/Makefile b/usr/src/cmd/stmfproxy/aluaadm/Makefile
new file mode 100644
index 0000000000..45f528e84d
--- /dev/null
+++ b/usr/src/cmd/stmfproxy/aluaadm/Makefile
@@ -0,0 +1,80 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+# cmd/iscsid/Makefile
+#
+
+PROG = aluaadm
+
+include ../../Makefile.cmd
+
+COMMONBASE = ../../../common
+
+DEMOBINFILES = \
+ $(PROG)
+
+ROOTDEMODIR = $(ROOT)/usr/demo/comstar
+ROOTDEMOBINDIR = $(ROOTDEMODIR)/bin
+ROOTDEMOFILES = $(DEMOFILES:%=$(ROOTDEMODIR)/%)
+ROOTDEMOBINFILES = $(DEMOBINFILES:%=$(ROOTDEMOBINDIR)/%)
+
+LOCAL_OBJS = aluaadm.o
+LOCAL_SRCS = $(LOCAL_OBJS:%.o=%.c)
+COMMON_OBJS = cmdparse.o
+COMMON_SRCS = $(COMMON_OBJS:%.o=$(COMMONBASE)/cmdparse/%.c)
+OBJS = $(LOCAL_OBJS) $(COMMON_OBJS)
+SRCS = $(LOCAL_SRCS) $(COMMON_SRCS)
+
+CPPFLAGS += -I. -I$(COMMONBASE)/cmdparse
+LDLIBS += -lstmf
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+clean:
+ $(RM) $(OBJS)
+
+install: all $(ROOTDEMOBINFILES)
+
+$(ROOTDEMODIR) $(ROOTDEMOBINDIR):
+ $(INS.dir)
+
+$(ROOTDEMODIR)/% $(ROOTDEMOBINDIR)/% : %
+ $(INS.file)
+
+$(ROOTDEMOBINFILES): $(ROOTDEMOBINDIR)
+
+cmdparse.o: $(COMMONBASE)/cmdparse/cmdparse.c
+ $(COMPILE.c) -o $@ $(COMMONBASE)/cmdparse/cmdparse.c
+ $(POST_PROCESS_O)
+
+lint: lint_SRCS
+
+include ../../Makefile.targ
diff --git a/usr/src/cmd/stmfproxy/aluaadm/aluaadm.c b/usr/src/cmd/stmfproxy/aluaadm/aluaadm.c
new file mode 100644
index 0000000000..5fa1504793
--- /dev/null
+++ b/usr/src/cmd/stmfproxy/aluaadm/aluaadm.c
@@ -0,0 +1,240 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <libintl.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+#include <assert.h>
+#include <getopt.h>
+#include <cmdparse.h>
+#include <libstmf.h>
+#include <signal.h>
+#include <pthread.h>
+#include <locale.h>
+
+static char *getExecBasename(char *);
+static int setLuStandbyFunc(int, char **, cmdOptions_t *, void *);
+static int disableAluaFunc(int, char **, cmdOptions_t *, void *);
+static int enableAluaFunc(int, char **, cmdOptions_t *, void *);
+
+#define OPERANDSTRING_LU "LU-name"
+#define OPERANDSTRING_NODE_ID "node ID (0 or 1)"
+
+#define VERSION_STRING_MAJOR "1"
+#define VERSION_STRING_MINOR "0"
+#define VERSION_STRING_MAX_LEN 10
+
+#define GUID_INPUT 32
+
+/* tables set up based on cmdparse instructions */
+
+/* add new options here */
+optionTbl_t longOptions[] = {
+ {NULL, 0, 0, 0}
+};
+
+/*
+ * Add new subcommands here
+ */
+subCommandProps_t subcommands[] = {
+ {"standby", setLuStandbyFunc, NULL, NULL, NULL,
+ OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, NULL},
+ {"disable", disableAluaFunc, NULL, NULL, NULL,
+ OPERAND_NONE, NULL, NULL},
+ {"enable", enableAluaFunc, NULL, NULL, NULL,
+ OPERAND_MANDATORY_SINGLE, OPERANDSTRING_NODE_ID, NULL},
+ {NULL, 0, NULL, NULL, 0, NULL, 0, NULL, NULL}
+};
+
+/* globals */
+char *cmdName;
+
+/*
+ * setLuStandbyFunc
+ *
+ * Purpose: set lu to standby
+ *
+ */
+/*ARGSUSED*/
+static int
+setLuStandbyFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ char sGuid[GUID_INPUT + 1];
+ stmfGuid inGuid;
+ unsigned int guid[sizeof (stmfGuid)];
+ int i;
+ int ret = 0;
+
+ if (strlen(operands[0]) != GUID_INPUT) {
+ (void) fprintf(stderr, "%s: %s: %s %d %s\n", cmdName,
+ operands[0], gettext("must be"), GUID_INPUT,
+ gettext("hexadecimal digits long"));
+ return (1);
+ }
+
+ bcopy(operands[0], sGuid, GUID_INPUT);
+
+ for (i = 0; i < GUID_INPUT; i++)
+ sGuid[i] = tolower(sGuid[i]);
+ sGuid[i] = 0;
+
+ (void) sscanf(sGuid, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
+ &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
+ &guid[6], &guid[7], &guid[8], &guid[9], &guid[10], &guid[11],
+ &guid[12], &guid[13], &guid[14], &guid[15]);
+
+ for (i = 0; i < sizeof (stmfGuid); i++) {
+ inGuid.guid[i] = guid[i];
+ }
+
+ ret = stmfLuStandby(&inGuid);
+ if (ret != STMF_STATUS_SUCCESS) {
+ switch (ret) {
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ break;
+ case STMF_ERROR_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[0], gettext("not found"));
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("unknown error"));
+ break;
+ }
+ }
+ return (ret);
+}
+
+/*
+ * disableAluaFunc
+ *
+ * Purpose: disable alua mode
+ *
+ */
+/*ARGSUSED*/
+static int
+disableAluaFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ return (stmfSetAluaState(B_FALSE, 0));
+}
+
+/*
+ * enableAluaFunc
+ *
+ * Purpose: enable alua mode
+ *
+ */
+/*ARGSUSED*/
+static int
+enableAluaFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ uint8_t node_id = 0;
+ if (operands[0][1] == '1') {
+ node_id = 1;
+ }
+ return (stmfSetAluaState(B_TRUE, node_id));
+}
+
+
+/*
+ * input:
+ * execFullName - exec name of program (argv[0])
+ *
+ * copied from usr/src/cmd/zoneadm/zoneadm.c in OS/Net
+ * (changed name to lowerCamelCase to keep consistent with this file)
+ *
+ * Returns:
+ * command name portion of execFullName
+ */
+static char *
+getExecBasename(char *execFullname)
+{
+ char *lastSlash, *execBasename;
+
+ /* guard against '/' at end of command invocation */
+ for (;;) {
+ lastSlash = strrchr(execFullname, '/');
+ if (lastSlash == NULL) {
+ execBasename = execFullname;
+ break;
+ } else {
+ execBasename = lastSlash + 1;
+ if (*execBasename == '\0') {
+ *lastSlash = '\0';
+ continue;
+ }
+ break;
+ }
+ }
+ return (execBasename);
+}
+
+int
+main(int argc, char *argv[])
+{
+ synTables_t synTables;
+ char versionString[VERSION_STRING_MAX_LEN];
+ int ret;
+ int funcRet;
+ void *subcommandArgs = NULL;
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain(TEXT_DOMAIN);
+ /* set global command name */
+ cmdName = getExecBasename(argv[0]);
+
+ (void) snprintf(versionString, VERSION_STRING_MAX_LEN, "%s.%s",
+ VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
+ synTables.versionString = versionString;
+ synTables.longOptionTbl = &longOptions[0];
+ synTables.subCommandPropsTbl = &subcommands[0];
+
+ ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ return (funcRet);
+} /* end main */
diff --git a/usr/src/cmd/stmfproxy/stmfproxy/Makefile b/usr/src/cmd/stmfproxy/stmfproxy/Makefile
new file mode 100644
index 0000000000..73d75ce1df
--- /dev/null
+++ b/usr/src/cmd/stmfproxy/stmfproxy/Makefile
@@ -0,0 +1,103 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+# cmd/stmfproxy/stmfproxy/Makefile
+#
+
+PROG = svc-stmfproxy
+
+COMMONBASE = ../../common
+
+include ../../Makefile.cmd
+
+DEMOFILES = \
+ stmfproxy.xml
+
+DEMOBINFILES = \
+ $(PROG)
+
+ROOTDEMODIR = $(ROOT)/usr/demo/comstar
+ROOTDEMOBINDIR = $(ROOTDEMODIR)/bin
+ROOTDEMOFILES = $(DEMOFILES:%=$(ROOTDEMODIR)/%)
+ROOTDEMOBINFILES = $(DEMOBINFILES:%=$(ROOTDEMOBINDIR)/%)
+
+PRODUCT= $(PROG)
+SRCS= $(OBJS:%.o=./%.c)
+OBJS= stmfproxy.o
+LLOBJS= $(OBJS:%.o=%.ll)
+#POFILES= $(OBJS:%.o=%.po)
+#POFILE= stmfproxy.po
+
+$(ROOTDEMODIR)/stmfproxy.xml := FILEMODE = 0444
+
+
+CCVERBOSE =
+LDLIBS += -lnsl -lstmf -lstmfproxy
+CPPFLAGS += -I. -I$(COMMONBASE)/cmdparse
+
+# Uncomment the following to help with debugging
+#CFLAGS += -g
+#i386_COPTFLAG=
+#i386_CCOPTFLAG=
+
+.KEEP_STATE:
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+LINTFLAGS += -erroff=E_FUNC_HAS_NO_RETURN_STMT
+LINTFLAGS += -erroff=E_BAD_PTR_CAST_ALIGN
+
+.PARALLEL: $(OBJS)
+
+all: $(PROG)
+
+clean:
+ $(RM) $(PROG) $(OBJS) $(LLOBJS)
+
+lint: lint_SRCS
+
+#$(POFILE): $(POFILES)
+# $(RM) $@
+# cat $(POFILES) > $@
+
+install: all $(ROOTDEMOFILES) $(ROOTDEMOBINFILES)
+
+$(ROOTDEMODIR) $(ROOTDEMOBINDIR):
+ $(INS.dir)
+
+$(ROOTDEMODIR)/% $(ROOTDEMOBINDIR)/% : %
+ $(INS.file)
+
+$(ROOTDEMOFILES): $(ROOTDEMODIR)
+
+$(ROOTDEMOBINFILES): $(ROOTDEMOBINDIR)
+
+check: $(CHKMANIFEST)
+ $(CSTYLE) -pPc $(SRCS:%=%)
+
+
+include ../../Makefile.targ
diff --git a/usr/src/cmd/stmfproxy/stmfproxy/stmfproxy.c b/usr/src/cmd/stmfproxy/stmfproxy/stmfproxy.c
new file mode 100644
index 0000000000..38115c2b51
--- /dev/null
+++ b/usr/src/cmd/stmfproxy/stmfproxy/stmfproxy.c
@@ -0,0 +1,541 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/stat.h>
+#include <sys/sdt.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <libnvpair.h>
+#include <libstmf.h>
+#include <door.h>
+#include <pthread.h>
+#include <libscf.h>
+#include <locale.h>
+#include <sys/stmf_ioctl.h>
+#include <sys/pppt_ioctl.h>
+#include <libstmfproxy.h>
+
+#define PPPT_NODE "/devices/pseudo/pppt@0:pppt"
+#define USAGE "Usage: %s [-d][-f][-n nodeid] nodename\n" \
+ "Note: nodename must be the same on both nodes\n"
+
+
+/*
+ * static functions
+ */
+static void daemonInit(void);
+static void killHandler();
+static int postMsg(uint_t nelem, uchar_t *aluaMsg);
+
+
+/*
+ * globals
+ */
+void *t_handle; /* transport handle */
+char aluaNode[256]; /* one of the two alua peers */
+char myNode[256]; /* this hostname */
+int log_debug = 0;
+int fore_ground = 0;
+int proxy_hdl;
+pt_ops_t *pt_ops;
+
+/*
+ * killHandler
+ *
+ * Terminates this process on SIGQUIT, SIGINT, SIGTERM
+ */
+/* ARGSUSED */
+static void
+killHandler(int sig)
+{
+ exit(0);
+}
+
+/*
+ * doorHandler
+ *
+ * Recieve data from the local proxy port provider and relay
+ * it to the peer node.
+ */
+/* ARGSUSED */
+void
+doorHandler(
+ void *cookie,
+ char *args,
+ size_t alen,
+ door_desc_t *ddp,
+ uint_t ndid)
+{
+ uint32_t result = 0;
+
+ if (ddp != NULL || ndid != 0) {
+ syslog(LOG_DAEMON|LOG_WARNING,
+ "descriptor passed to door %p %d", ddp, ndid);
+ result = EINVAL;
+ }
+
+ if (args == NULL || alen == 0) {
+ syslog(LOG_DAEMON|LOG_WARNING,
+ "empty message passed to door %p %d", args, alen);
+ result = EFAULT;
+ }
+
+ if (result == 0)
+ result = postMsg((uint_t)alen, (uchar_t *)args);
+ (void) door_return((char *)&result, sizeof (result), NULL, 0);
+
+ syslog(LOG_DAEMON|LOG_WARNING, "door_return FAILED %d", errno);
+ exit(errno);
+}
+
+static int
+postMsg(uint_t nelem, uchar_t *aluaMsg)
+{
+ uint32_t buflen;
+ uchar_t *buf;
+ int ret = 0;
+ int ns;
+
+ if (t_handle == NULL) {
+ syslog(LOG_DAEMON|LOG_WARNING,
+ "postMsg() no transport handle");
+ exit(1);
+ }
+
+ buf = malloc(nelem + sizeof (buflen));
+
+ buflen = htonl(nelem); /* length in network byte order */
+ bcopy(&buflen, buf, sizeof (buflen));
+ bcopy(aluaMsg, buf + sizeof (buflen), nelem);
+
+ ns = pt_ops->stmf_proxy_send(t_handle, buf, nelem + sizeof (buflen));
+ if (ns != nelem + sizeof (buflen)) {
+ ret = errno;
+ if (ret == 0)
+ ret = ENOTTY; /* something bogus */
+ syslog(LOG_DAEMON|LOG_CRIT, "send() call failed: %d", ret);
+ }
+ free(buf);
+ return (ret);
+}
+
+/*
+ * Multi-thread the data path from the peer node to the local
+ * proxy port provider. During discover, there can be a large
+ * burst of messages from the peer node proportional to the number
+ * of LUs. Multiple threads allow these messages to be processed
+ * simultaneously.
+ */
+typedef struct pppt_drv_queue {
+ struct pppt_drv_queue *next;
+ uint32_t buflen;
+ uchar_t *buf;
+} pppt_drv_queue_t;
+
+pppt_drv_queue_t *pq_head = NULL;
+pthread_mutex_t pq_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t pq_cond = PTHREAD_COND_INITIALIZER;
+int pq_num_threads = 0;
+int pq_avail_threads = 0;
+
+/*ARGSUSED*/
+void *
+push_to_drv(void *arg)
+{
+ pppt_drv_queue_t *pq;
+ int rc;
+
+ (void) pthread_mutex_lock(&pq_mutex);
+ pq_num_threads++;
+ (void) pthread_mutex_unlock(&pq_mutex);
+ for (;;) {
+ (void) pthread_mutex_lock(&pq_mutex);
+ while (pq_head == NULL) {
+ pq_avail_threads++;
+ (void) pthread_cond_wait(&pq_cond, &pq_mutex);
+ pq_avail_threads--;
+ }
+ pq = pq_head;
+ pq_head = pq->next;
+ pq->next = NULL;
+ (void) pthread_mutex_unlock(&pq_mutex);
+ /* Relay the message to the local kernel */
+ rc = stmfPostProxyMsg(proxy_hdl, (void *)pq->buf, pq->buflen);
+ if (rc != STMF_STATUS_SUCCESS) {
+ /* XXX die ? */
+ syslog(LOG_DAEMON|LOG_CRIT, "ioctl failed - %d", errno);
+ }
+ free(pq->buf);
+ free(pq);
+ }
+ /*NOTREACHED*/
+ return (NULL);
+}
+
+/*
+ * Receive data from peer and queue it up for the proxy driver.
+ */
+int message_count = 0;
+static void
+relay_peer_msg()
+{
+ uint32_t buflen;
+ pppt_drv_queue_t *pq, *tmpq;
+ pthread_t tid;
+ int rc;
+
+
+ /* first receive the length of the message */
+ if ((pt_ops->stmf_proxy_recv(t_handle, (uchar_t *)&buflen,
+ sizeof (buflen))) != sizeof (buflen)) {
+ syslog(LOG_DAEMON|LOG_WARNING, "recv() call failed: %d",
+ errno);
+ exit(1);
+ }
+
+ pq = malloc(sizeof (*pq));
+ pq->next = NULL;
+ pq->buflen = ntohl(buflen);
+ pq->buf = malloc(pq->buflen+4);
+ if (log_debug) {
+ syslog(LOG_DAEMON|LOG_DEBUG,
+ "recvMsg: size of buffer - %d", (int)pq->buflen);
+ }
+
+ if ((pt_ops->stmf_proxy_recv(t_handle, pq->buf, pq->buflen)) !=
+ pq->buflen) {
+ syslog(LOG_DAEMON|LOG_WARNING, "recv() call failed: %d",
+ errno);
+ exit(1);
+ }
+
+ /* Eat the first message from peer */
+ if (message_count++ == 0) {
+ *(pq->buf+pq->buflen) = 0;
+ free(pq->buf);
+ free(pq);
+ return;
+ }
+
+ /* Queue the message to the driver */
+ (void) pthread_mutex_lock(&pq_mutex);
+ if (pq_head == NULL) {
+ pq_head = pq;
+ } else {
+ /* add to the tail */
+ tmpq = pq_head;
+ while (tmpq->next != NULL)
+ tmpq = tmpq->next;
+ tmpq->next = pq;
+ }
+
+ /* Make sure there is a thread to service this message */
+ if (pq_avail_threads) {
+ /* wake an available thread */
+ (void) pthread_cond_signal(&pq_cond);
+ (void) pthread_mutex_unlock(&pq_mutex);
+ } else {
+ /* no threads available, create a new thread */
+ (void) pthread_mutex_unlock(&pq_mutex);
+ rc = pthread_create(&tid, NULL, push_to_drv, NULL);
+ if (rc != 0) {
+ syslog(LOG_DAEMON|LOG_WARNING,
+ "pthread_create() call failed: %d", rc);
+ if (pq_num_threads == 0) {
+ /* never created a thread */
+ exit(rc);
+ }
+ }
+ }
+}
+
+/*
+ * Initialization for a daemon process
+ */
+static void
+daemonInit(void)
+{
+ pid_t pid;
+ int devnull;
+
+ if (fore_ground)
+ return;
+
+ if ((pid = fork()) < 0) {
+ syslog(LOG_DAEMON|LOG_CRIT, "Could not fork(). Exiting");
+ exit(1);
+ } else if (pid != 0) {
+ /*
+ * XXX
+ * Simple approach for now - let the service go online.
+ * Later, set-up a pipe to the child and wait until the
+ * child indicates service is setup.
+ */
+ exit(SMF_EXIT_OK);
+ }
+
+ (void) setsid();
+
+ (void) chdir("/");
+
+ (void) umask(0);
+
+
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull < 0) {
+ syslog(LOG_DAEMON|LOG_CRIT,
+ "Failed to open /dev/null. Exiting");
+ exit(1);
+ }
+
+ (void) dup2(devnull, STDIN_FILENO);
+ (void) dup2(devnull, STDOUT_FILENO);
+ (void) dup2(devnull, STDERR_FILENO);
+ (void) close(devnull);
+}
+
+void
+daemon_fini(int rc)
+{
+ /*
+ * XXX inform the parent about the service state
+ * For now, just exit on error.
+ */
+ if (rc != 0)
+ exit(rc);
+}
+
+static int
+open_proxy_driver()
+{
+ int drv_door_fd;
+ int stmf_ret;
+
+ /*
+ * Create communication channel for the driver.
+ */
+ if ((drv_door_fd = door_create(doorHandler, NULL, 0)) < 0) {
+ perror("door_create");
+ syslog(LOG_DAEMON|LOG_DEBUG,
+ "could not create door: errno %d", errno);
+ return (SMF_EXIT_ERR_FATAL);
+ }
+
+ stmf_ret = stmfInitProxyDoor(&proxy_hdl, drv_door_fd);
+ if (stmf_ret != STMF_STATUS_SUCCESS) {
+ perror("pppt ioctl: door install");
+ syslog(LOG_DAEMON|LOG_DEBUG,
+ "could not install door: errno %d", errno);
+ return (SMF_EXIT_ERR_FATAL);
+ }
+
+ return (SMF_EXIT_OK);
+}
+
+/*
+ * daemon entry
+ *
+ * parse arguments
+ * create resources to talk to child
+ * if !foreground
+ * daemonize, run as child
+ * open proxy driver
+ * install door in proxy driver
+ * create socket
+ * if server-side
+ * bind socket
+ * if !foreground
+ * inform parent things aok
+ * if parent
+ * exit(SMF_EXIT_OK)
+ * if server-side
+ * accept
+ * if client-side
+ * connect
+ * send hello
+ * recv hello
+ * loop on recieve
+ * XXX anyway to check in envp that we are started by SMF?
+ */
+int
+main(int argc, char *argv[])
+{
+ struct sockaddr_in sin;
+ int rc;
+ struct sigaction act;
+ sigset_t sigmask;
+ int c;
+ int node = 0;
+ int node_override = 0;
+ int server_node = 0;
+ int server_match = 0;
+ extern char *optarg;
+ int stmf_ret;
+
+ (void) setlocale(LC_ALL, "");
+ openlog("stmfproxy", LOG_PID, LOG_DAEMON);
+ (void) setlogmask(LOG_UPTO(LOG_INFO));
+
+ while ((c = getopt(argc, argv, "dfn:")) != -1) {
+ switch (c) {
+ case 'd':
+ (void) setlogmask(LOG_UPTO(LOG_DEBUG));
+ log_debug = 1;
+ break;
+ case 'f':
+ fore_ground = 1;
+ break;
+ case 'n':
+ node_override = 1;
+ node = atoi(optarg);
+ break;
+ default:
+ /*
+ * Should never happen from smf
+ */
+ (void) fprintf(stderr, USAGE, argv[0]);
+ exit(SMF_EXIT_ERR_CONFIG);
+ break;
+ }
+ }
+ /*
+ * After the options, only the server argument should remain.
+ */
+ if (optind != argc-1) {
+ (void) fprintf(stderr, USAGE, argv[0]);
+ exit(SMF_EXIT_ERR_CONFIG);
+ }
+ (void) strcpy(aluaNode, argv[optind]);
+ syslog(LOG_DAEMON|LOG_DEBUG, "aluaNode %s", aluaNode);
+ if (gethostname(myNode, 255)) {
+ perror("gethostname");
+ exit(1);
+ }
+ if ((inet_aton(aluaNode, &sin.sin_addr)) == 0) {
+ /*
+ * Not ipaddr, try hostname match.
+ */
+ server_match = (strcmp(aluaNode, myNode)) ? 0 : 1;
+ } else {
+ /*
+ * see if this is our ip address
+ */
+ (void) fprintf(stderr, "Sorry, cannot use ip adress format\n");
+ }
+ if (server_match) {
+ server_node = 1;
+ if (!node_override)
+ node = 1;
+ }
+
+
+ /*
+ * Allow SIGQUIT, SIGINT and SIGTERM signals to terminate us
+ */
+ act.sa_handler = killHandler;
+ (void) sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+
+ /* Install the signal handler */
+ (void) sigaction(SIGQUIT, &act, NULL);
+ (void) sigaction(SIGINT, &act, NULL);
+ (void) sigaction(SIGTERM, &act, NULL);
+ (void) sigaction(SIGHUP, &act, NULL);
+
+ /* block all signals */
+ (void) sigfillset(&sigmask);
+
+ /* unblock SIGQUIT, SIGINT, SIGTERM */
+ (void) sigdelset(&sigmask, SIGQUIT);
+ (void) sigdelset(&sigmask, SIGINT);
+ (void) sigdelset(&sigmask, SIGTERM);
+ (void) sigdelset(&sigmask, SIGHUP);
+
+ (void) sigprocmask(SIG_SETMASK, &sigmask, NULL);
+
+ /* time to go backstage */
+ daemonInit();
+
+ if ((rc = open_proxy_driver()) != 0)
+ daemon_fini(rc);
+
+ if ((rc = stmf_proxy_transport_init("sockets", &pt_ops)) != 0)
+ daemon_fini(rc);
+
+ /*
+ * Establish connection
+ *
+ * At this point, the parent has exited and the service
+ * is online. But there are no real proxy services until
+ * this connect call succeeds. That could take a long time if
+ * the peer node is down.
+ */
+ t_handle = pt_ops->stmf_proxy_connect(server_node, aluaNode);
+ if (t_handle == NULL) {
+ syslog(LOG_DAEMON|LOG_WARNING,
+ "socket() call failed: %d", errno);
+ exit(1);
+ }
+
+ /* The first message is a greeting */
+ (void) postMsg((uint_t)strlen(myNode)+1, (uchar_t *)myNode);
+ /* Read the greeting from peer node */
+ relay_peer_msg();
+ /*
+ * Set the alua state in stmf. No need to keep
+ * the device open since the proxy driver has a reference.
+ */
+ stmf_ret = stmfSetAluaState(B_TRUE, node);
+ if (stmf_ret != STMF_STATUS_SUCCESS) {
+ syslog(LOG_DAEMON|LOG_CRIT, "stmf ioctl failed - %x", stmf_ret);
+ exit(1);
+ }
+
+ /* service is online */
+ daemon_fini(0);
+
+ /*
+ * Loop relaying data from the peer daemon to the local kernel.
+ * Data coming from the local kernel is handled asynchronously
+ * by the door server.
+ */
+ for (;;) { /* loop forever */
+ relay_peer_msg();
+ }
+}
diff --git a/usr/src/cmd/stmfproxy/stmfproxy/stmfproxy.xml b/usr/src/cmd/stmfproxy/stmfproxy/stmfproxy.xml
new file mode 100644
index 0000000000..32913ba0be
--- /dev/null
+++ b/usr/src/cmd/stmfproxy/stmfproxy/stmfproxy.xml
@@ -0,0 +1,112 @@
+<?xml version='1.0'?>
+<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
+
+<!--
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ Service manifests for the stmfproxy daemon
+-->
+
+<service_bundle type='manifest' name='SUNWstmfu:svc-stmfproxy'>
+
+<service
+ name='system/stmfproxy'
+ type='service'
+ version='1'>
+
+ <single_instance/>
+
+ <dependency
+ name='stmf'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/stmf' />
+ </dependency>
+
+ <!--
+ Set a timeout of -1 to signify to inetd that we don't want
+ to timeout this service, since the forked process is the
+ one that does the services work. This is the case for most/all
+ legacy inetd services; for services written to take advantage
+ of Greenlines capabilities, the start method should fork
+ off a process to handle the request and return a success code.
+ -->
+ <exec_method
+ type='method'
+ name='start'
+ exec='/usr/demo/comstar/bin/svc-stmfproxy %{config/proxy_host}'
+ timeout_seconds='600'>
+ <method_context>
+ <method_credential
+ user='root'
+ group='root'
+ privileges='basic,sys_devices'
+ />
+ </method_context>
+ </exec_method>
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill'
+ timeout_seconds='600'>
+ <method_context>
+ <method_credential
+ user='root'
+ group='root'
+ privileges='basic,sys_devices'
+ />
+ </method_context>
+ </exec_method>
+
+ <property_group name='config' type='application' >
+ <stability value='Unstable' />
+ <propval name='proxy_host' type='astring'
+ value='no:host:set' />
+ <propval name='proxy_port' type='integer'
+ value='6543' />
+ </property_group>
+
+ <!--
+ Create an enabled instance.
+ -->
+ <instance
+ name='default'
+ enabled='false' >
+ </instance>
+
+ <stability value='Evolving' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ stmfproxy daemon
+ </loctext>
+ </common_name>
+
+ </template>
+</service>
+
+</service_bundle>