/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
*/
/*
* Copyright (c) 1999-2001 by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <thread.h>
#include <synch.h>
#include <signal.h>
#include <slp-internal.h>
/*
* Cached parameters and thread synchronization
*/
/* synch for the FD management thread */
static int ipc_used;
static int ipc_thr_running;
static void close_ipc();
static void get_localhost_sin();
static void ipc_manage_thr();
/*
* Locking should be handled by the caller
*/
int terr;
int retries = 0;
if (slpdfd)
return (SLP_OK);
/* Make sure the local host's sockaddr_in is set */
if (!local_sin) {
if (!local_sin) {
slpdfd = 0;
return (SLP_INTERNAL_SYSTEM_ERROR);
}
}
for (;;) {
int errno_kept;
slpdfd = 0;
return (SLP_INTERNAL_SYSTEM_ERROR);
}
sizeof (*local_sin)) == 0) {
break;
}
/* else error condition */
if (retries++ == 2) {
if (errno_kept == ECONNREFUSED)
"is slpd running?");
slpdfd = 0;
return (SLP_NETWORK_ERROR);
} else {
/* back off a little */
(void) sleep(1);
}
}
/* We now know slpd is reachable; start the management thread */
if (!ipc_thr_running) {
if ((terr = thr_create(
0, NULL,
(void *(*)(void *)) ipc_manage_thr,
"could not start thread: %s",
return (SLP_INTERNAL_SYSTEM_ERROR);
}
}
ipc_thr_running = 1;
return (SLP_OK);
}
static void close_ipc() {
(void) mutex_lock(&ipc_lock);
if (!slpdfd) {
(void) mutex_unlock(&ipc_lock);
return;
}
slpdfd = 0;
(void) mutex_unlock(&ipc_lock);
}
/*
* Sends 'msg' to slpd, placing the response in 'reply'. Caller should
* free memory associated with 'reply'. All IPC is handled transparantly
* by this call. Note that this call is a wrapper for slp_send2slpd_iov.
* Returns SLP_NETWORK_ERROR if slpd is unreachable, SLP_OK otherwise.
*/
}
int retries = 0;
(void) mutex_lock(&ipc_lock);
/* is the connection open? */
if (!slpdfd) {
(void) mutex_unlock(&ipc_lock);
return (err);
}
}
/* populate the msghdr for sendmsg */
msghdr->msg_namelen = 0;
msghdr->msg_accrightslen = 0;
/*
* If slpd has been restarted while this connection is
* still open, we will get a SIGPIPE when we try to write
* to it. So we need to ignore SIGPIPEs for the duration of
* the communication with slpd.
*/
switch (errno) {
case EINTR:
case ENOBUFS:
case ENOSR:
continue;
case EBADF:
case ECONNRESET:
case ENOTCONN:
default:
(void) mutex_unlock(&ipc_lock);
close_ipc();
if (retries++) {
"could not talk to slpd: %s",
goto done;
}
/* try re-opening the connection to slpd */
(void) mutex_lock(&ipc_lock);
continue;
} else {
goto done;
}
}
}
/*
* On error slpd may close the socket; there can be a race
* condition here where a following call (attempting to reuse
* the socket) may send to slpd before it has closed the socket.
* To prevent this, we must also close the socket on error.
*/
(void) mutex_unlock(&ipc_lock);
close_ipc();
(void) mutex_lock(&ipc_lock);
}
/* notify ipc thread of call */
(void) mutex_lock(&ipc_wait_lock);
ipc_used = 1;
(void) cond_signal(&ipc_wait_var);
(void) mutex_unlock(&ipc_wait_lock);
(void) mutex_unlock(&ipc_lock);
done:
/* restore original signal disposition for SIGPIPE */
return (err);
}
/*
* Sets up a sockaddr_in pointing at slpd.
* After the first call, the address of slpd is cached in local_sin.
*
* side effect: local_sin is set to an address for slpd.
*/
static void get_localhost_sin() {
(void) mutex_lock(&lhlock);
if (local_sin) {
(void) mutex_unlock(&lhlock);
return;
}
goto done;
}
done:
(void) mutex_unlock(&lhlock);
}
/*
* IPC management: the FD to slpd is kept open and cached to improve
* performance on successive calls. The IPC management thread waits
* on a condition variable; the condition is if an IPC call has been
* made. If so, the thread advances the FD's expiration by IPC_FD_LIFETIME
* and continues waiting for the next IPC call. After the FD has expired,
* the thread closes IPC and shuts itself down.
*/
static void ipc_manage_thr() {
(void) mutex_lock(&ipc_wait_lock);
ipc_used = 0;
while (ipc_used == 0) {
int err;
&timeout);
/* shutdown */
close_ipc();
ipc_thr_running = 0;
(void) mutex_unlock(&ipc_wait_lock);
} else {
/* reset condition variable */
ipc_used = 0;
}
}
}