1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright (c) 1999-2001 by Sun Microsystems, Inc. 24*7c478bd9Sstevel@tonic-gate * All rights reserved. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <stdio.h> 30*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 33*7c478bd9Sstevel@tonic-gate #include <string.h> 34*7c478bd9Sstevel@tonic-gate #include <errno.h> 35*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 36*7c478bd9Sstevel@tonic-gate #include <unistd.h> 37*7c478bd9Sstevel@tonic-gate #include <syslog.h> 38*7c478bd9Sstevel@tonic-gate #include <thread.h> 39*7c478bd9Sstevel@tonic-gate #include <synch.h> 40*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 41*7c478bd9Sstevel@tonic-gate #include <signal.h> 42*7c478bd9Sstevel@tonic-gate #include <slp-internal.h> 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate #define IPC_FD_LIFETIME 30 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate /* 47*7c478bd9Sstevel@tonic-gate * Cached parameters and thread synchronization 48*7c478bd9Sstevel@tonic-gate */ 49*7c478bd9Sstevel@tonic-gate static int slpdfd; /* cached FD to slpd */ 50*7c478bd9Sstevel@tonic-gate static mutex_t ipc_lock = DEFAULTMUTEX; /* serializes IPC */ 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate /* synch for the FD management thread */ 53*7c478bd9Sstevel@tonic-gate static mutex_t ipc_wait_lock = DEFAULTMUTEX; 54*7c478bd9Sstevel@tonic-gate static cond_t ipc_wait_var; 55*7c478bd9Sstevel@tonic-gate static int ipc_used; 56*7c478bd9Sstevel@tonic-gate static int ipc_thr_running; 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate static struct sockaddr_in *local_sin; /* slpd addr, set on first use */ 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate static SLPError open_ipc(); 61*7c478bd9Sstevel@tonic-gate static void close_ipc(); 62*7c478bd9Sstevel@tonic-gate static void get_localhost_sin(); 63*7c478bd9Sstevel@tonic-gate static void ipc_manage_thr(); 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate /* 66*7c478bd9Sstevel@tonic-gate * Locking should be handled by the caller 67*7c478bd9Sstevel@tonic-gate */ 68*7c478bd9Sstevel@tonic-gate static SLPError open_ipc() { 69*7c478bd9Sstevel@tonic-gate int terr; 70*7c478bd9Sstevel@tonic-gate int retries = 0; 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate if (slpdfd) 73*7c478bd9Sstevel@tonic-gate return (SLP_OK); 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate /* Make sure the local host's sockaddr_in is set */ 76*7c478bd9Sstevel@tonic-gate if (!local_sin) { 77*7c478bd9Sstevel@tonic-gate get_localhost_sin(); 78*7c478bd9Sstevel@tonic-gate if (!local_sin) { 79*7c478bd9Sstevel@tonic-gate slpdfd = 0; 80*7c478bd9Sstevel@tonic-gate return (SLP_INTERNAL_SYSTEM_ERROR); 81*7c478bd9Sstevel@tonic-gate } 82*7c478bd9Sstevel@tonic-gate } 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate for (;;) { 85*7c478bd9Sstevel@tonic-gate int errno_kept; 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate if ((slpdfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 88*7c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_open_ipc", 89*7c478bd9Sstevel@tonic-gate "could not create socket: %s", strerror(errno)); 90*7c478bd9Sstevel@tonic-gate slpdfd = 0; 91*7c478bd9Sstevel@tonic-gate return (SLP_INTERNAL_SYSTEM_ERROR); 92*7c478bd9Sstevel@tonic-gate } 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate if (connect(slpdfd, (struct sockaddr *)local_sin, 96*7c478bd9Sstevel@tonic-gate sizeof (*local_sin)) == 0) { 97*7c478bd9Sstevel@tonic-gate break; 98*7c478bd9Sstevel@tonic-gate } 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate /* else error condition */ 101*7c478bd9Sstevel@tonic-gate errno_kept = errno; /* in case errno is reset by slp_err */ 102*7c478bd9Sstevel@tonic-gate if (retries++ == 2) { 103*7c478bd9Sstevel@tonic-gate slp_err(LOG_INFO, 0, "slp_open_ipc", 104*7c478bd9Sstevel@tonic-gate "could not connect to slpd: %s", strerror(errno)); 105*7c478bd9Sstevel@tonic-gate if (errno_kept == ECONNREFUSED) 106*7c478bd9Sstevel@tonic-gate slp_err(LOG_INFO, 0, "slp_open_ipc", 107*7c478bd9Sstevel@tonic-gate "is slpd running?"); 108*7c478bd9Sstevel@tonic-gate (void) close(slpdfd); 109*7c478bd9Sstevel@tonic-gate slpdfd = 0; 110*7c478bd9Sstevel@tonic-gate return (SLP_NETWORK_ERROR); 111*7c478bd9Sstevel@tonic-gate } else { 112*7c478bd9Sstevel@tonic-gate /* back off a little */ 113*7c478bd9Sstevel@tonic-gate (void) close(slpdfd); 114*7c478bd9Sstevel@tonic-gate (void) sleep(1); 115*7c478bd9Sstevel@tonic-gate } 116*7c478bd9Sstevel@tonic-gate } 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate /* We now know slpd is reachable; start the management thread */ 119*7c478bd9Sstevel@tonic-gate if (!ipc_thr_running) { 120*7c478bd9Sstevel@tonic-gate if ((terr = thr_create( 121*7c478bd9Sstevel@tonic-gate 0, NULL, 122*7c478bd9Sstevel@tonic-gate (void *(*)(void *)) ipc_manage_thr, 123*7c478bd9Sstevel@tonic-gate NULL, 0, NULL)) != 0) { 124*7c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_open_ipc", 125*7c478bd9Sstevel@tonic-gate "could not start thread: %s", 126*7c478bd9Sstevel@tonic-gate strerror(terr)); 127*7c478bd9Sstevel@tonic-gate return (SLP_INTERNAL_SYSTEM_ERROR); 128*7c478bd9Sstevel@tonic-gate } 129*7c478bd9Sstevel@tonic-gate } 130*7c478bd9Sstevel@tonic-gate ipc_thr_running = 1; 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate return (SLP_OK); 133*7c478bd9Sstevel@tonic-gate } 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate static void close_ipc() { 136*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&ipc_lock); 137*7c478bd9Sstevel@tonic-gate if (!slpdfd) { 138*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&ipc_lock); 139*7c478bd9Sstevel@tonic-gate return; 140*7c478bd9Sstevel@tonic-gate } 141*7c478bd9Sstevel@tonic-gate (void) close(slpdfd); 142*7c478bd9Sstevel@tonic-gate slpdfd = 0; 143*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&ipc_lock); 144*7c478bd9Sstevel@tonic-gate } 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate /* 147*7c478bd9Sstevel@tonic-gate * Sends 'msg' to slpd, placing the response in 'reply'. Caller should 148*7c478bd9Sstevel@tonic-gate * free memory associated with 'reply'. All IPC is handled transparantly 149*7c478bd9Sstevel@tonic-gate * by this call. Note that this call is a wrapper for slp_send2slpd_iov. 150*7c478bd9Sstevel@tonic-gate * Returns SLP_NETWORK_ERROR if slpd is unreachable, SLP_OK otherwise. 151*7c478bd9Sstevel@tonic-gate */ 152*7c478bd9Sstevel@tonic-gate SLPError slp_send2slpd(const char *msg, char **reply) { 153*7c478bd9Sstevel@tonic-gate struct iovec iov[1]; 154*7c478bd9Sstevel@tonic-gate iov->iov_base = (caddr_t)msg; 155*7c478bd9Sstevel@tonic-gate iov->iov_len = slp_get_length(msg); 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate return (slp_send2slpd_iov(iov, 1, reply)); 158*7c478bd9Sstevel@tonic-gate } 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate SLPError slp_send2slpd_iov(struct iovec *msg, int iovlen, char **reply) { 161*7c478bd9Sstevel@tonic-gate SLPError err; 162*7c478bd9Sstevel@tonic-gate int retries = 0; 163*7c478bd9Sstevel@tonic-gate struct msghdr msghdr[1]; 164*7c478bd9Sstevel@tonic-gate struct sigaction new, old; 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate *reply = NULL; 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&ipc_lock); 169*7c478bd9Sstevel@tonic-gate /* is the connection open? */ 170*7c478bd9Sstevel@tonic-gate if (!slpdfd) { 171*7c478bd9Sstevel@tonic-gate if ((err = open_ipc()) != SLP_OK) { 172*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&ipc_lock); 173*7c478bd9Sstevel@tonic-gate return (err); 174*7c478bd9Sstevel@tonic-gate } 175*7c478bd9Sstevel@tonic-gate } 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate /* populate the msghdr for sendmsg */ 178*7c478bd9Sstevel@tonic-gate msghdr->msg_name = NULL; 179*7c478bd9Sstevel@tonic-gate msghdr->msg_namelen = 0; 180*7c478bd9Sstevel@tonic-gate msghdr->msg_iov = msg; 181*7c478bd9Sstevel@tonic-gate msghdr->msg_iovlen = iovlen; 182*7c478bd9Sstevel@tonic-gate msghdr->msg_accrights = NULL; 183*7c478bd9Sstevel@tonic-gate msghdr->msg_accrightslen = 0; 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate /* 186*7c478bd9Sstevel@tonic-gate * If slpd has been restarted while this connection is 187*7c478bd9Sstevel@tonic-gate * still open, we will get a SIGPIPE when we try to write 188*7c478bd9Sstevel@tonic-gate * to it. So we need to ignore SIGPIPEs for the duration of 189*7c478bd9Sstevel@tonic-gate * the communication with slpd. 190*7c478bd9Sstevel@tonic-gate */ 191*7c478bd9Sstevel@tonic-gate new.sa_handler = SIG_IGN; 192*7c478bd9Sstevel@tonic-gate new.sa_flags = 0; 193*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&new.sa_mask); 194*7c478bd9Sstevel@tonic-gate (void) sigaction(SIGPIPE, &new, &old); /* preserve old disposition */ 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate while (sendmsg(slpdfd, msghdr, 0) == -1) { 197*7c478bd9Sstevel@tonic-gate int errno_kept = errno; 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate switch (errno) { 200*7c478bd9Sstevel@tonic-gate case EINTR: 201*7c478bd9Sstevel@tonic-gate case ENOBUFS: 202*7c478bd9Sstevel@tonic-gate case ENOSR: 203*7c478bd9Sstevel@tonic-gate continue; 204*7c478bd9Sstevel@tonic-gate case EBADF: 205*7c478bd9Sstevel@tonic-gate case ECONNRESET: 206*7c478bd9Sstevel@tonic-gate case ENOTCONN: 207*7c478bd9Sstevel@tonic-gate default: 208*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&ipc_lock); 209*7c478bd9Sstevel@tonic-gate close_ipc(); 210*7c478bd9Sstevel@tonic-gate if (retries++) { 211*7c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_send2slpd", 212*7c478bd9Sstevel@tonic-gate "could not talk to slpd: %s", 213*7c478bd9Sstevel@tonic-gate strerror(errno_kept)); 214*7c478bd9Sstevel@tonic-gate err = SLP_NETWORK_ERROR; 215*7c478bd9Sstevel@tonic-gate goto done; 216*7c478bd9Sstevel@tonic-gate } 217*7c478bd9Sstevel@tonic-gate /* try re-opening the connection to slpd */ 218*7c478bd9Sstevel@tonic-gate if (open_ipc() == SLP_OK) { 219*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&ipc_lock); 220*7c478bd9Sstevel@tonic-gate continue; 221*7c478bd9Sstevel@tonic-gate } else { 222*7c478bd9Sstevel@tonic-gate err = SLP_NETWORK_ERROR; 223*7c478bd9Sstevel@tonic-gate goto done; 224*7c478bd9Sstevel@tonic-gate } 225*7c478bd9Sstevel@tonic-gate } 226*7c478bd9Sstevel@tonic-gate } 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate err = slp_tcp_read(slpdfd, reply); 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate /* 231*7c478bd9Sstevel@tonic-gate * On error slpd may close the socket; there can be a race 232*7c478bd9Sstevel@tonic-gate * condition here where a following call (attempting to reuse 233*7c478bd9Sstevel@tonic-gate * the socket) may send to slpd before it has closed the socket. 234*7c478bd9Sstevel@tonic-gate * To prevent this, we must also close the socket on error. 235*7c478bd9Sstevel@tonic-gate */ 236*7c478bd9Sstevel@tonic-gate if (err == SLP_OK && slp_get_errcode(*reply) != 0) { 237*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&ipc_lock); 238*7c478bd9Sstevel@tonic-gate close_ipc(); 239*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&ipc_lock); 240*7c478bd9Sstevel@tonic-gate } 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate /* notify ipc thread of call */ 243*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&ipc_wait_lock); 244*7c478bd9Sstevel@tonic-gate ipc_used = 1; 245*7c478bd9Sstevel@tonic-gate (void) cond_signal(&ipc_wait_var); 246*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&ipc_wait_lock); 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&ipc_lock); 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate done: 251*7c478bd9Sstevel@tonic-gate /* restore original signal disposition for SIGPIPE */ 252*7c478bd9Sstevel@tonic-gate (void) sigaction(SIGPIPE, &old, NULL); 253*7c478bd9Sstevel@tonic-gate return (err); 254*7c478bd9Sstevel@tonic-gate } 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate /* 257*7c478bd9Sstevel@tonic-gate * Sets up a sockaddr_in pointing at slpd. 258*7c478bd9Sstevel@tonic-gate * After the first call, the address of slpd is cached in local_sin. 259*7c478bd9Sstevel@tonic-gate * 260*7c478bd9Sstevel@tonic-gate * side effect: local_sin is set to an address for slpd. 261*7c478bd9Sstevel@tonic-gate */ 262*7c478bd9Sstevel@tonic-gate static void get_localhost_sin() { 263*7c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 264*7c478bd9Sstevel@tonic-gate static mutex_t lhlock = DEFAULTMUTEX; 265*7c478bd9Sstevel@tonic-gate 266*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&lhlock); 267*7c478bd9Sstevel@tonic-gate if (local_sin) { 268*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&lhlock); 269*7c478bd9Sstevel@tonic-gate return; 270*7c478bd9Sstevel@tonic-gate } 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate if (!(sin = calloc(1, sizeof (*sin)))) { 273*7c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "get_localhost_sin", "out of memory"); 274*7c478bd9Sstevel@tonic-gate goto done; 275*7c478bd9Sstevel@tonic-gate } 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate IN_SET_LOOPBACK_ADDR(sin); 278*7c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 279*7c478bd9Sstevel@tonic-gate sin->sin_port = htons(SLP_PORT); 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate done: 282*7c478bd9Sstevel@tonic-gate local_sin = sin; 283*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&lhlock); 284*7c478bd9Sstevel@tonic-gate } 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate /* 287*7c478bd9Sstevel@tonic-gate * IPC management: the FD to slpd is kept open and cached to improve 288*7c478bd9Sstevel@tonic-gate * performance on successive calls. The IPC management thread waits 289*7c478bd9Sstevel@tonic-gate * on a condition variable; the condition is if an IPC call has been 290*7c478bd9Sstevel@tonic-gate * made. If so, the thread advances the FD's expiration by IPC_FD_LIFETIME 291*7c478bd9Sstevel@tonic-gate * and continues waiting for the next IPC call. After the FD has expired, 292*7c478bd9Sstevel@tonic-gate * the thread closes IPC and shuts itself down. 293*7c478bd9Sstevel@tonic-gate */ 294*7c478bd9Sstevel@tonic-gate static void ipc_manage_thr() { 295*7c478bd9Sstevel@tonic-gate timestruc_t timeout; 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate timeout.tv_nsec = 0; 298*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&ipc_wait_lock); 299*7c478bd9Sstevel@tonic-gate ipc_used = 0; 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate while (ipc_used == 0) { 302*7c478bd9Sstevel@tonic-gate int err; 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate timeout.tv_sec = IPC_FD_LIFETIME; 305*7c478bd9Sstevel@tonic-gate err = cond_reltimedwait(&ipc_wait_var, &ipc_wait_lock, 306*7c478bd9Sstevel@tonic-gate &timeout); 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate if (err == ETIME) { 309*7c478bd9Sstevel@tonic-gate /* shutdown */ 310*7c478bd9Sstevel@tonic-gate close_ipc(); 311*7c478bd9Sstevel@tonic-gate ipc_thr_running = 0; 312*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&ipc_wait_lock); 313*7c478bd9Sstevel@tonic-gate thr_exit(NULL); 314*7c478bd9Sstevel@tonic-gate } else { 315*7c478bd9Sstevel@tonic-gate /* reset condition variable */ 316*7c478bd9Sstevel@tonic-gate ipc_used = 0; 317*7c478bd9Sstevel@tonic-gate } 318*7c478bd9Sstevel@tonic-gate } 319*7c478bd9Sstevel@tonic-gate } 320