/*
* 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
* 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
*/
/*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <syslog.h>
#include <unistd.h>
#include <netdb.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>
"Note: nodename must be the same on both nodes\n"
/*
* static functions
*/
static void daemonInit(void);
static void killHandler();
/*
* globals
*/
int log_debug = 0;
int fore_ground = 0;
int proxy_hdl;
/*
* killHandler
*
* Terminates this process on SIGQUIT, SIGINT, SIGTERM
*/
/* ARGSUSED */
static void
{
exit(0);
}
/*
* doorHandler
*
* Recieve data from the local proxy port provider and relay
* it to the peer node.
*/
/* ARGSUSED */
void
void *cookie,
char *args,
{
}
}
if (result == 0)
}
static int
{
int ret = 0;
int ns;
"postMsg() no transport handle");
exit(1);
}
(void) pthread_mutex_lock(&send_mutex);
(void) pthread_mutex_unlock(&send_mutex);
if (ret == 0)
}
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 {
int pq_num_threads = 0;
int pq_avail_threads = 0;
/*ARGSUSED*/
void *
{
int rc;
(void) pthread_mutex_lock(&pq_mutex);
(void) pthread_mutex_unlock(&pq_mutex);
for (;;) {
(void) pthread_mutex_lock(&pq_mutex);
}
(void) pthread_mutex_unlock(&pq_mutex);
/* Relay the message to the local kernel */
if (rc != STMF_STATUS_SUCCESS) {
/* XXX die ? */
}
}
/*NOTREACHED*/
return (NULL);
}
/*
* Receive data from peer and queue it up for the proxy driver.
*/
int message_count = 0;
static void
{
int rc;
/* first receive the length of the message */
errno);
exit(1);
}
if (log_debug) {
}
errno);
exit(1);
}
/* Eat the first message from peer */
if (message_count++ == 0) {
return;
}
/* Queue the message to the driver */
(void) pthread_mutex_lock(&pq_mutex);
} else {
/* add to the tail */
}
/* 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);
if (rc != 0) {
"pthread_create() call failed: %d", rc);
if (pq_num_threads == 0) {
/* never created a thread */
}
}
}
}
/*
* Initialization for a daemon process
*/
static void
daemonInit(void)
{
int devnull;
if (fore_ground)
return;
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.
*/
}
(void) setsid();
(void) chdir("/");
(void) umask(0);
if (devnull < 0) {
exit(1);
}
}
void
{
/*
* XXX inform the parent about the service state
* For now, just exit on error.
*/
if (rc != 0)
}
static int
{
int drv_door_fd;
int stmf_ret;
/*
* Create communication channel for the driver.
*/
perror("door_create");
"could not create door: errno %d", errno);
return (SMF_EXIT_ERR_FATAL);
}
if (stmf_ret != STMF_STATUS_SUCCESS) {
perror("pppt ioctl: door install");
"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
{
int rc;
int c;
int node = 0;
int node_override = 0;
int server_node = 0;
int server_match = 0;
extern char *optarg;
int stmf_ret;
switch (c) {
case 'd':
log_debug = 1;
break;
case 'f':
fore_ground = 1;
break;
case 'n':
node_override = 1;
break;
default:
/*
* Should never happen from smf
*/
break;
}
}
/*
* After the options, only the server argument should remain.
*/
}
perror("gethostname");
exit(1);
}
/*
* Not ipaddr, try hostname match.
*/
} else {
/*
* see if this is our ip address
*/
}
if (server_match) {
server_node = 1;
if (!node_override)
node = 1;
}
/*
* Allow SIGQUIT, SIGINT and SIGTERM signals to terminate us
*/
/* Install the signal handler */
/* block all signals */
(void) sigfillset(&sigmask);
/* unblock SIGQUIT, SIGINT, SIGTERM */
/* time to go backstage */
daemonInit();
if ((rc = open_proxy_driver()) != 0)
/*
* 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.
*/
"socket() call failed: %d", errno);
exit(1);
}
/* The first message is a greeting */
/* Read the greeting from peer node */
/*
* Set the alua state in stmf. No need to keep
* the device open since the proxy driver has a reference.
*/
if (stmf_ret != STMF_STATUS_SUCCESS) {
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 */
}
}