xref: /onnv-gate/usr/src/cmd/avs/rdc/sndrd.c (revision 11576:b23c42c0c9d6)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
21*11576SSurya.Prakki@Sun.COM 
227836SJohn.Forte@Sun.COM /*
23*11576SSurya.Prakki@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247836SJohn.Forte@Sun.COM  * Use is subject to license terms.
257836SJohn.Forte@Sun.COM  */
267836SJohn.Forte@Sun.COM 
277836SJohn.Forte@Sun.COM /*
287836SJohn.Forte@Sun.COM  * Network SNDR/ncall-ip server - based on nfsd
297836SJohn.Forte@Sun.COM  */
307836SJohn.Forte@Sun.COM #include <sys/types.h>
317836SJohn.Forte@Sun.COM #include <rpc/types.h>
327836SJohn.Forte@Sun.COM #include <errno.h>
337836SJohn.Forte@Sun.COM #include <netdb.h>
347836SJohn.Forte@Sun.COM #include <sys/socket.h>
357836SJohn.Forte@Sun.COM #include <netconfig.h>
367836SJohn.Forte@Sun.COM #include <stropts.h>
377836SJohn.Forte@Sun.COM #include <fcntl.h>
387836SJohn.Forte@Sun.COM #include <stdio.h>
397836SJohn.Forte@Sun.COM #include <strings.h>
407836SJohn.Forte@Sun.COM #include <signal.h>
417836SJohn.Forte@Sun.COM #include <unistd.h>
427836SJohn.Forte@Sun.COM #include <stdlib.h>
437836SJohn.Forte@Sun.COM #include <netdir.h>
447836SJohn.Forte@Sun.COM #include <rpc/rpc_com.h>
457836SJohn.Forte@Sun.COM #include <rpc/rpc.h>
467836SJohn.Forte@Sun.COM #include <tiuser.h>
477836SJohn.Forte@Sun.COM #include <netinet/tcp.h>
487836SJohn.Forte@Sun.COM #include <netinet/in.h>
497836SJohn.Forte@Sun.COM #include <syslog.h>
507836SJohn.Forte@Sun.COM #include <locale.h>
517836SJohn.Forte@Sun.COM #include <langinfo.h>
527836SJohn.Forte@Sun.COM #include <libintl.h>
537836SJohn.Forte@Sun.COM #include <libgen.h>
547836SJohn.Forte@Sun.COM #include <deflt.h>
557836SJohn.Forte@Sun.COM #include <sys/resource.h>
567836SJohn.Forte@Sun.COM 
577836SJohn.Forte@Sun.COM #include <sys/nsctl/nsctl.h>
587836SJohn.Forte@Sun.COM 
597836SJohn.Forte@Sun.COM #ifdef	__NCALL__
607836SJohn.Forte@Sun.COM 
617836SJohn.Forte@Sun.COM #include <sys/ncall/ncall.h>
627836SJohn.Forte@Sun.COM #include <sys/ncall/ncall_ip.h>
637836SJohn.Forte@Sun.COM #include <sys/nsctl/libncall.h>
647836SJohn.Forte@Sun.COM 
657836SJohn.Forte@Sun.COM #define	RDC_POOL_CREATE	NC_IOC_POOL_CREATE
667836SJohn.Forte@Sun.COM #define	RDC_POOL_RUN	NC_IOC_POOL_RUN
677836SJohn.Forte@Sun.COM #define	RDC_POOL_WAIT	NC_IOC_POOL_WAIT
687836SJohn.Forte@Sun.COM #define	RDC_PROGRAM	NCALL_PROGRAM
697836SJohn.Forte@Sun.COM #define	RDC_SERVICE	"ncall"
707836SJohn.Forte@Sun.COM #undef RDC_SVCPOOL_ID	/* We are overloading this value */
717836SJohn.Forte@Sun.COM #define	RDC_SVCPOOL_ID	NCALL_SVCPOOL_ID
727836SJohn.Forte@Sun.COM #define	RDC_SVC_NAME	"NCALL"
737836SJohn.Forte@Sun.COM #define	RDC_VERS_MIN	NCALL_VERS_MIN
747836SJohn.Forte@Sun.COM #define	RDC_VERS_MAX	NCALL_VERS_MAX
757836SJohn.Forte@Sun.COM 
767836SJohn.Forte@Sun.COM #else	/* !__NCALL__ */
777836SJohn.Forte@Sun.COM 
787836SJohn.Forte@Sun.COM #include <sys/nsctl/rdc_ioctl.h>
797836SJohn.Forte@Sun.COM #include <sys/nsctl/rdc_io.h>
807836SJohn.Forte@Sun.COM #include <sys/nsctl/librdc.h>
817836SJohn.Forte@Sun.COM 
827836SJohn.Forte@Sun.COM #define	RDC_SERVICE	"rdc"
837836SJohn.Forte@Sun.COM #define	RDC_SVC_NAME	"RDC"
847836SJohn.Forte@Sun.COM 
857836SJohn.Forte@Sun.COM #endif	/* __NCALL__ */
867836SJohn.Forte@Sun.COM 
877836SJohn.Forte@Sun.COM #define	RDCADMIN	"/etc/default/sndr"
887836SJohn.Forte@Sun.COM 
897836SJohn.Forte@Sun.COM #include <nsctl.h>
907836SJohn.Forte@Sun.COM 
917836SJohn.Forte@Sun.COM struct conn_ind {
927836SJohn.Forte@Sun.COM 	struct conn_ind *conn_next;
937836SJohn.Forte@Sun.COM 	struct conn_ind *conn_prev;
947836SJohn.Forte@Sun.COM 	struct t_call   *conn_call;
957836SJohn.Forte@Sun.COM };
967836SJohn.Forte@Sun.COM 
977836SJohn.Forte@Sun.COM struct conn_entry {
987836SJohn.Forte@Sun.COM 	bool_t			closing;
997836SJohn.Forte@Sun.COM 	struct netconfig	nc;
1007836SJohn.Forte@Sun.COM };
1017836SJohn.Forte@Sun.COM 
1027836SJohn.Forte@Sun.COM static char *progname;
1037836SJohn.Forte@Sun.COM static struct conn_entry *conn_polled;
1047836SJohn.Forte@Sun.COM static int num_conns;			/* Current number of connections */
1057836SJohn.Forte@Sun.COM static struct pollfd *poll_array;	/* array of poll descriptors for poll */
1067836SJohn.Forte@Sun.COM static size_t num_fds = 0;		/* number of transport fds opened */
1077836SJohn.Forte@Sun.COM static void poll_for_action();
1087836SJohn.Forte@Sun.COM static void remove_from_poll_list(int);
1097836SJohn.Forte@Sun.COM static int do_poll_cots_action(int, int);
1107836SJohn.Forte@Sun.COM static int do_poll_clts_action(int, int);
1117836SJohn.Forte@Sun.COM static void add_to_poll_list(int, struct netconfig *);
1127836SJohn.Forte@Sun.COM static int bind_to_provider(char *, char *, struct netbuf **,
1137836SJohn.Forte@Sun.COM     struct netconfig **);
1147836SJohn.Forte@Sun.COM static int set_addrmask(int, struct netconfig *, struct netbuf *);
1157836SJohn.Forte@Sun.COM static void conn_close_oldest(void);
1167836SJohn.Forte@Sun.COM static boolean_t conn_get(int, struct netconfig *, struct conn_ind **);
1177836SJohn.Forte@Sun.COM static void cots_listen_event(int, int);
1187836SJohn.Forte@Sun.COM static int discon_get(int, struct netconfig *, struct conn_ind **);
1197836SJohn.Forte@Sun.COM static int nofile_increase(int);
1207836SJohn.Forte@Sun.COM static int is_listen_fd_index(int);
1217836SJohn.Forte@Sun.COM #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
1227836SJohn.Forte@Sun.COM static int sndrsvcpool(int);
1237836SJohn.Forte@Sun.COM static int svcwait(int id);
1247836SJohn.Forte@Sun.COM #endif
1257836SJohn.Forte@Sun.COM 
1267836SJohn.Forte@Sun.COM 
1277836SJohn.Forte@Sun.COM /*
1287836SJohn.Forte@Sun.COM  * RPC protocol block.  Useful for passing registration information.
1297836SJohn.Forte@Sun.COM  */
1307836SJohn.Forte@Sun.COM struct protob {
1317836SJohn.Forte@Sun.COM 	char *serv;		/* ASCII service name, e.g. "RDC" */
1327836SJohn.Forte@Sun.COM 	int versmin;		/* minimum version no. to be registered */
1337836SJohn.Forte@Sun.COM 	int versmax;		/* maximum version no. to be registered */
1347836SJohn.Forte@Sun.COM 	int program;		/* program no. to be registered */
1357836SJohn.Forte@Sun.COM 	struct protob *next;	/* next entry on list */
1367836SJohn.Forte@Sun.COM };
1377836SJohn.Forte@Sun.COM 
1387836SJohn.Forte@Sun.COM 
1397836SJohn.Forte@Sun.COM 
1407836SJohn.Forte@Sun.COM static size_t end_listen_fds;
1417836SJohn.Forte@Sun.COM static int debugflg = 0;
1427836SJohn.Forte@Sun.COM static int max_conns_allowed = -1;
1437836SJohn.Forte@Sun.COM static int listen_backlog = 10;
1447836SJohn.Forte@Sun.COM static char *trans_provider = (char *)NULL;
1457836SJohn.Forte@Sun.COM static int rdcsvc(int, struct netbuf, struct netconfig *);
1467836SJohn.Forte@Sun.COM 
1477836SJohn.Forte@Sun.COM /* used by cots_listen_event() */
1487836SJohn.Forte@Sun.COM static int (*Mysvc)(int, struct netbuf, struct netconfig *) = rdcsvc;
1497836SJohn.Forte@Sun.COM 
1507836SJohn.Forte@Sun.COM /*
1517836SJohn.Forte@Sun.COM  * Determine valid semantics for rdc.
1527836SJohn.Forte@Sun.COM  */
1537836SJohn.Forte@Sun.COM #define	OK_TPI_TYPE(_nconf)	\
1547836SJohn.Forte@Sun.COM 	(_nconf->nc_semantics == NC_TPI_CLTS || \
1557836SJohn.Forte@Sun.COM 	_nconf->nc_semantics == NC_TPI_COTS || \
1567836SJohn.Forte@Sun.COM 	_nconf->nc_semantics == NC_TPI_COTS_ORD)
1577836SJohn.Forte@Sun.COM 
1587836SJohn.Forte@Sun.COM #define	BE32_TO_U32(a)		\
1597836SJohn.Forte@Sun.COM 	((((uint32_t)((uchar_t *)a)[0] & 0xFF) << (uint32_t)24) |\
1607836SJohn.Forte@Sun.COM 	(((uint32_t)((uchar_t *)a)[1] & 0xFF) << (uint32_t)16) |\
1617836SJohn.Forte@Sun.COM 	(((uint32_t)((uchar_t *)a)[2] & 0xFF) << (uint32_t)8)  |\
1627836SJohn.Forte@Sun.COM 	((uint32_t)((uchar_t *)a)[3] & 0xFF))
1637836SJohn.Forte@Sun.COM 
1647836SJohn.Forte@Sun.COM #ifdef DEBUG
1657836SJohn.Forte@Sun.COM /*
1667836SJohn.Forte@Sun.COM  * Only support UDP in DEBUG mode for now
1677836SJohn.Forte@Sun.COM  */
1687836SJohn.Forte@Sun.COM static	char *defaultproviders[] = { "/dev/tcp", "/dev/tcp6", "/dev/udp",
1697836SJohn.Forte@Sun.COM 		"/dev/udp6", NULL };
1707836SJohn.Forte@Sun.COM #else
1717836SJohn.Forte@Sun.COM static	char *defaultproviders[] = { "/dev/tcp6", "/dev/tcp", NULL };
1727836SJohn.Forte@Sun.COM #endif
1737836SJohn.Forte@Sun.COM 
1747836SJohn.Forte@Sun.COM /*
1757836SJohn.Forte@Sun.COM  * Number of elements to add to the poll array on each allocation.
1767836SJohn.Forte@Sun.COM  */
1777836SJohn.Forte@Sun.COM #define	POLL_ARRAY_INC_SIZE	64
1787836SJohn.Forte@Sun.COM #define	NOFILE_INC_SIZE		64
1797836SJohn.Forte@Sun.COM 
1807836SJohn.Forte@Sun.COM #ifdef	__NCALL__
1817836SJohn.Forte@Sun.COM const char *rdc_devr = "/dev/ncallip";
1827836SJohn.Forte@Sun.COM #else
1837836SJohn.Forte@Sun.COM const char *rdc_devr = "/dev/rdc";
1847836SJohn.Forte@Sun.COM #endif
1857836SJohn.Forte@Sun.COM 
1867836SJohn.Forte@Sun.COM static int rdc_fdr;
1877836SJohn.Forte@Sun.COM static int
1887836SJohn.Forte@Sun.COM 
open_rdc(void)1897836SJohn.Forte@Sun.COM open_rdc(void)
1907836SJohn.Forte@Sun.COM {
1917836SJohn.Forte@Sun.COM 	int fd = open(rdc_devr, O_RDONLY);
1927836SJohn.Forte@Sun.COM 
1937836SJohn.Forte@Sun.COM 	if (fd < 0)
1947836SJohn.Forte@Sun.COM 		return (-1);
1957836SJohn.Forte@Sun.COM 
1967836SJohn.Forte@Sun.COM 	return (rdc_fdr = fd);
1977836SJohn.Forte@Sun.COM }
1987836SJohn.Forte@Sun.COM 
1997836SJohn.Forte@Sun.COM static int
sndrsys(int type,void * arg)2007836SJohn.Forte@Sun.COM sndrsys(int type, void *arg)
2017836SJohn.Forte@Sun.COM {
2027836SJohn.Forte@Sun.COM 	int ret = -1;
2037836SJohn.Forte@Sun.COM 	if (!rdc_fdr && open_rdc() < 0) { /* open failed */
2047836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "open_rdc() failed: %m\n");
2057836SJohn.Forte@Sun.COM 	} else {
2067836SJohn.Forte@Sun.COM 		if ((ret = ioctl(rdc_fdr, type, arg)) < 0) {
2077836SJohn.Forte@Sun.COM 			syslog(LOG_ERR, "ioctl(rdc_ioctl) failed: %m\n");
2087836SJohn.Forte@Sun.COM 		}
2097836SJohn.Forte@Sun.COM 	}
2107836SJohn.Forte@Sun.COM 	return (ret);
2117836SJohn.Forte@Sun.COM }
2127836SJohn.Forte@Sun.COM 
2137836SJohn.Forte@Sun.COM int
rdc_transport_open(struct netconfig * nconf)2147836SJohn.Forte@Sun.COM rdc_transport_open(struct netconfig *nconf)
2157836SJohn.Forte@Sun.COM {
2167836SJohn.Forte@Sun.COM 	int fd;
2177836SJohn.Forte@Sun.COM 	struct strioctl	strioc;
2187836SJohn.Forte@Sun.COM 
2197836SJohn.Forte@Sun.COM 	if ((nconf == (struct netconfig *)NULL) ||
2207836SJohn.Forte@Sun.COM 	    (nconf->nc_device == (char *)NULL)) {
2217836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "No netconfig device");
2227836SJohn.Forte@Sun.COM 		return (-1);
2237836SJohn.Forte@Sun.COM 	}
2247836SJohn.Forte@Sun.COM 
2257836SJohn.Forte@Sun.COM 	/*
2267836SJohn.Forte@Sun.COM 	 * Open the transport device.
2277836SJohn.Forte@Sun.COM 	 */
2287836SJohn.Forte@Sun.COM 	fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL);
2297836SJohn.Forte@Sun.COM 	if (fd == -1)  {
2307836SJohn.Forte@Sun.COM 		if (t_errno == TSYSERR && errno == EMFILE &&
2317836SJohn.Forte@Sun.COM 				(nofile_increase(0) == 0)) {
2327836SJohn.Forte@Sun.COM 			/* Try again with a higher NOFILE limit. */
2337836SJohn.Forte@Sun.COM 			fd = t_open(nconf->nc_device, O_RDWR,
2347836SJohn.Forte@Sun.COM 				(struct t_info *)NULL);
2357836SJohn.Forte@Sun.COM 		}
2367836SJohn.Forte@Sun.COM 		if (fd == -1) {
2377836SJohn.Forte@Sun.COM 			if (t_errno == TSYSERR) {
2387836SJohn.Forte@Sun.COM 				syslog(LOG_ERR, "t_open failed: %m");
2397836SJohn.Forte@Sun.COM 			} else {
2407836SJohn.Forte@Sun.COM 				syslog(LOG_ERR, "t_open failed: %s",
2417836SJohn.Forte@Sun.COM 				    t_errlist[t_errno]);
2427836SJohn.Forte@Sun.COM 			}
2437836SJohn.Forte@Sun.COM 			return (-1);
2447836SJohn.Forte@Sun.COM 		}
2457836SJohn.Forte@Sun.COM 	}
2467836SJohn.Forte@Sun.COM 
2477836SJohn.Forte@Sun.COM 	/*
2487836SJohn.Forte@Sun.COM 	 * Pop timod because the RPC module must be as close as possible
2497836SJohn.Forte@Sun.COM 	 * to the transport.
2507836SJohn.Forte@Sun.COM 	 */
2517836SJohn.Forte@Sun.COM 	if (ioctl(fd, I_POP, 0) < 0) {
2527836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "I_POP of timod failed: %m");
2537836SJohn.Forte@Sun.COM 		if (t_close(fd) == -1) {
2547836SJohn.Forte@Sun.COM 			if (t_errno == TSYSERR) {
2557836SJohn.Forte@Sun.COM 				syslog(LOG_ERR, "t_close failed on %d: %m", fd);
2567836SJohn.Forte@Sun.COM 			} else {
2577836SJohn.Forte@Sun.COM 				syslog(LOG_ERR, "t_close failed on %d: %s",
2587836SJohn.Forte@Sun.COM 				    fd, t_errlist[t_errno]);
2597836SJohn.Forte@Sun.COM 			}
2607836SJohn.Forte@Sun.COM 		}
2617836SJohn.Forte@Sun.COM 		return (-1);
2627836SJohn.Forte@Sun.COM 	}
2637836SJohn.Forte@Sun.COM 
2647836SJohn.Forte@Sun.COM 	if (nconf->nc_semantics == NC_TPI_CLTS) {
2657836SJohn.Forte@Sun.COM 		/*
2667836SJohn.Forte@Sun.COM 		 * Push rpcmod to filter data traffic to KRPC.
2677836SJohn.Forte@Sun.COM 		 */
2687836SJohn.Forte@Sun.COM 		if (ioctl(fd, I_PUSH, "rpcmod") < 0) {
2697836SJohn.Forte@Sun.COM 			syslog(LOG_ERR, "I_PUSH of rpcmod failed: %m");
2707836SJohn.Forte@Sun.COM 			(void) t_close(fd);
2717836SJohn.Forte@Sun.COM 			return (-1);
2727836SJohn.Forte@Sun.COM 		}
2737836SJohn.Forte@Sun.COM 	} else {
2747836SJohn.Forte@Sun.COM 		if (ioctl(fd, I_PUSH, "rpcmod") < 0) {
2757836SJohn.Forte@Sun.COM 			syslog(LOG_ERR, "I_PUSH of CONS rpcmod failed: %m");
2767836SJohn.Forte@Sun.COM 			if (t_close(fd) == -1) {
2777836SJohn.Forte@Sun.COM 				if (t_errno == TSYSERR) {
2787836SJohn.Forte@Sun.COM 					syslog(LOG_ERR,
2797836SJohn.Forte@Sun.COM 						"t_close failed on %d: %m", fd);
2807836SJohn.Forte@Sun.COM 				} else {
2817836SJohn.Forte@Sun.COM 					syslog(LOG_ERR,
2827836SJohn.Forte@Sun.COM 						"t_close failed on %d: %s",
2837836SJohn.Forte@Sun.COM 						fd, t_errlist[t_errno]);
2847836SJohn.Forte@Sun.COM 				}
2857836SJohn.Forte@Sun.COM 			}
2867836SJohn.Forte@Sun.COM 			return (-1);
2877836SJohn.Forte@Sun.COM 		}
2887836SJohn.Forte@Sun.COM 
2897836SJohn.Forte@Sun.COM 		strioc.ic_cmd = RPC_SERVER;
2907836SJohn.Forte@Sun.COM 		strioc.ic_dp = (char *)0;
2917836SJohn.Forte@Sun.COM 		strioc.ic_len = 0;
2927836SJohn.Forte@Sun.COM 		strioc.ic_timout = -1;
2937836SJohn.Forte@Sun.COM 		/* Tell CONS rpcmod to act like a server stream. */
2947836SJohn.Forte@Sun.COM 		if (ioctl(fd, I_STR, &strioc) < 0) {
2957836SJohn.Forte@Sun.COM 			syslog(LOG_ERR, "CONS rpcmod set-up ioctl failed: %m");
2967836SJohn.Forte@Sun.COM 			if (t_close(fd) == -1) {
2977836SJohn.Forte@Sun.COM 				if (t_errno == TSYSERR) {
2987836SJohn.Forte@Sun.COM 					syslog(LOG_ERR,
2997836SJohn.Forte@Sun.COM 						"t_close failed on %d: %m", fd);
3007836SJohn.Forte@Sun.COM 				} else {
3017836SJohn.Forte@Sun.COM 					syslog(LOG_ERR,
3027836SJohn.Forte@Sun.COM 						"t_close failed on %d: %s",
3037836SJohn.Forte@Sun.COM 						fd, t_errlist[t_errno]);
3047836SJohn.Forte@Sun.COM 				}
3057836SJohn.Forte@Sun.COM 			}
3067836SJohn.Forte@Sun.COM 			return (-1);
3077836SJohn.Forte@Sun.COM 		}
3087836SJohn.Forte@Sun.COM 	}
3097836SJohn.Forte@Sun.COM 
3107836SJohn.Forte@Sun.COM 	/*
3117836SJohn.Forte@Sun.COM 	 * Re-push timod so that we will still be doing TLI
3127836SJohn.Forte@Sun.COM 	 * operations on the descriptor.
3137836SJohn.Forte@Sun.COM 	 */
3147836SJohn.Forte@Sun.COM 	if (ioctl(fd, I_PUSH, "timod") < 0) {
3157836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "I_PUSH of timod failed: %m");
3167836SJohn.Forte@Sun.COM 		if (t_close(fd) == -1) {
3177836SJohn.Forte@Sun.COM 			if (t_errno == TSYSERR) {
3187836SJohn.Forte@Sun.COM 				syslog(LOG_ERR, "t_close failed on %d: %m", fd);
3197836SJohn.Forte@Sun.COM 			} else {
3207836SJohn.Forte@Sun.COM 				syslog(LOG_ERR, "t_close failed on %d: %s",
3217836SJohn.Forte@Sun.COM 				    fd, t_errlist[t_errno]);
3227836SJohn.Forte@Sun.COM 			}
3237836SJohn.Forte@Sun.COM 		}
3247836SJohn.Forte@Sun.COM 		return (-1);
3257836SJohn.Forte@Sun.COM 	}
3267836SJohn.Forte@Sun.COM 
3277836SJohn.Forte@Sun.COM 	return (fd);
3287836SJohn.Forte@Sun.COM }
3297836SJohn.Forte@Sun.COM 
3307836SJohn.Forte@Sun.COM 
3317836SJohn.Forte@Sun.COM void
rdcd_log_tli_error(char * tli_name,int fd,struct netconfig * nconf)3327836SJohn.Forte@Sun.COM rdcd_log_tli_error(char *tli_name, int fd, struct netconfig *nconf)
3337836SJohn.Forte@Sun.COM {
3347836SJohn.Forte@Sun.COM 	int error;
3357836SJohn.Forte@Sun.COM 
3367836SJohn.Forte@Sun.COM 	/*
3377836SJohn.Forte@Sun.COM 	 * Save the error code across syslog(), just in case syslog()
3387836SJohn.Forte@Sun.COM 	 * gets its own error and, therefore, overwrites errno.
3397836SJohn.Forte@Sun.COM 	 */
3407836SJohn.Forte@Sun.COM 	error = errno;
3417836SJohn.Forte@Sun.COM 	if (t_errno == TSYSERR) {
3427836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "%s(file descriptor %d/transport %s) %m",
3437836SJohn.Forte@Sun.COM 		    tli_name, fd, nconf->nc_proto);
3447836SJohn.Forte@Sun.COM 	} else {
3457836SJohn.Forte@Sun.COM 		syslog(LOG_ERR,
3467836SJohn.Forte@Sun.COM 		    "%s(file descriptor %d/transport %s) TLI error %d",
3477836SJohn.Forte@Sun.COM 		    tli_name, fd, nconf->nc_proto, t_errno);
3487836SJohn.Forte@Sun.COM 	}
3497836SJohn.Forte@Sun.COM 	errno = error;
3507836SJohn.Forte@Sun.COM }
3517836SJohn.Forte@Sun.COM 
3527836SJohn.Forte@Sun.COM /*
3537836SJohn.Forte@Sun.COM  * Called to set up service over a particular transport
3547836SJohn.Forte@Sun.COM  */
3557836SJohn.Forte@Sun.COM void
do_one(char * provider,char * proto,struct protob * protobp0,int (* svc)(int,struct netbuf,struct netconfig *))3567836SJohn.Forte@Sun.COM do_one(char *provider, char *proto, struct protob *protobp0,
3577836SJohn.Forte@Sun.COM 	int (*svc)(int, struct netbuf, struct netconfig *))
3587836SJohn.Forte@Sun.COM {
3597836SJohn.Forte@Sun.COM 	struct netbuf *retaddr;
3607836SJohn.Forte@Sun.COM 	struct netconfig *retnconf;
3617836SJohn.Forte@Sun.COM 	struct netbuf addrmask;
3627836SJohn.Forte@Sun.COM 	int vers;
3637836SJohn.Forte@Sun.COM 	int sock;
3647836SJohn.Forte@Sun.COM 
3657836SJohn.Forte@Sun.COM 	if (provider) {
3667836SJohn.Forte@Sun.COM 		sock = bind_to_provider(provider, protobp0->serv, &retaddr,
3677836SJohn.Forte@Sun.COM 		    &retnconf);
3687836SJohn.Forte@Sun.COM 	} else {
3697836SJohn.Forte@Sun.COM 		(void) syslog(LOG_ERR,
3707836SJohn.Forte@Sun.COM 	"Cannot establish %s service over %s: transport setup problem.",
3717836SJohn.Forte@Sun.COM 		    protobp0->serv, provider ? provider : proto);
3727836SJohn.Forte@Sun.COM 		return;
3737836SJohn.Forte@Sun.COM 	}
3747836SJohn.Forte@Sun.COM 
3757836SJohn.Forte@Sun.COM 	if (sock == -1) {
3767836SJohn.Forte@Sun.COM 		if ((Is_ipv6present() &&
3777836SJohn.Forte@Sun.COM 		(strcmp(provider, "/dev/tcp6") == 0)) ||
3787836SJohn.Forte@Sun.COM 		(!Is_ipv6present() && (strcmp(provider, "/dev/tcp") == 0)))
3797836SJohn.Forte@Sun.COM 			(void) syslog(LOG_ERR,
3807836SJohn.Forte@Sun.COM 			    "Cannot establish %s service over %s: transport "
3817836SJohn.Forte@Sun.COM 				"setup problem.",
3827836SJohn.Forte@Sun.COM 				protobp0->serv, provider ? provider : proto);
3837836SJohn.Forte@Sun.COM 		return;
3847836SJohn.Forte@Sun.COM 	}
3857836SJohn.Forte@Sun.COM 
3867836SJohn.Forte@Sun.COM 	if (set_addrmask(sock, retnconf, &addrmask) < 0) {
3877836SJohn.Forte@Sun.COM 		(void) syslog(LOG_ERR,
3887836SJohn.Forte@Sun.COM 		    "Cannot set address mask for %s", retnconf->nc_netid);
3897836SJohn.Forte@Sun.COM 		return;
3907836SJohn.Forte@Sun.COM 	}
3917836SJohn.Forte@Sun.COM 
3927836SJohn.Forte@Sun.COM 
3937836SJohn.Forte@Sun.COM 	/*
3947836SJohn.Forte@Sun.COM 	 * Register all versions of the programs in the protocol block list
3957836SJohn.Forte@Sun.COM 	 */
3967836SJohn.Forte@Sun.COM 	for (vers = protobp0->versmin; vers <= protobp0->versmax; vers++) {
3977836SJohn.Forte@Sun.COM 		(void) rpcb_unset(protobp0->program, vers, retnconf);
3987836SJohn.Forte@Sun.COM 		(void) rpcb_set(protobp0->program, vers, retnconf, retaddr);
3997836SJohn.Forte@Sun.COM 	}
4007836SJohn.Forte@Sun.COM 
4017836SJohn.Forte@Sun.COM 	if (retnconf->nc_semantics == NC_TPI_CLTS) {
4027836SJohn.Forte@Sun.COM 		/* Don't drop core if supporting module(s) aren't loaded. */
4037836SJohn.Forte@Sun.COM 		(void) signal(SIGSYS, SIG_IGN);
4047836SJohn.Forte@Sun.COM 
4057836SJohn.Forte@Sun.COM 		/*
4067836SJohn.Forte@Sun.COM 		 * svc() doesn't block, it returns success or failure.
4077836SJohn.Forte@Sun.COM 		 */
4087836SJohn.Forte@Sun.COM 		if ((*svc)(sock, addrmask, retnconf) < 0) {
4097836SJohn.Forte@Sun.COM 			(void) syslog(LOG_ERR,
4107836SJohn.Forte@Sun.COM "Cannot establish %s service over <file desc. %d, protocol %s> : %m. Exiting",
4117836SJohn.Forte@Sun.COM 				protobp0->serv, sock, retnconf->nc_proto);
4127836SJohn.Forte@Sun.COM 			exit(1);
4137836SJohn.Forte@Sun.COM 		}
4147836SJohn.Forte@Sun.COM 	}
4157836SJohn.Forte@Sun.COM 	/*
4167836SJohn.Forte@Sun.COM 	 * We successfully set up the server over this transport.
4177836SJohn.Forte@Sun.COM 	 * Add this descriptor to the one being polled on.
4187836SJohn.Forte@Sun.COM 	 */
4197836SJohn.Forte@Sun.COM 	add_to_poll_list(sock, retnconf);
4207836SJohn.Forte@Sun.COM }
4217836SJohn.Forte@Sun.COM 
4227836SJohn.Forte@Sun.COM /*
4237836SJohn.Forte@Sun.COM  * Set up the SNDR/ncall-ip service over all the available transports.
4247836SJohn.Forte@Sun.COM  * Returns -1 for failure, 0 for success.
4257836SJohn.Forte@Sun.COM  */
4267836SJohn.Forte@Sun.COM int
do_all(struct protob * protobp,int (* svc)(int,struct netbuf,struct netconfig *))4277836SJohn.Forte@Sun.COM do_all(struct protob *protobp,
4287836SJohn.Forte@Sun.COM 	int (*svc)(int, struct netbuf, struct netconfig *))
4297836SJohn.Forte@Sun.COM {
4307836SJohn.Forte@Sun.COM 	struct netconfig *nconf;
4317836SJohn.Forte@Sun.COM 	NCONF_HANDLE *nc;
4327836SJohn.Forte@Sun.COM 
4337836SJohn.Forte@Sun.COM 	if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
4347836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "setnetconfig failed: %m");
4357836SJohn.Forte@Sun.COM 		return (-1);
4367836SJohn.Forte@Sun.COM 	}
4377836SJohn.Forte@Sun.COM 	while (nconf = getnetconfig(nc)) {
4387836SJohn.Forte@Sun.COM 		if ((nconf->nc_flag & NC_VISIBLE) &&
4397836SJohn.Forte@Sun.COM 		    strcmp(nconf->nc_protofmly, "loopback") != 0 &&
4407836SJohn.Forte@Sun.COM 		    OK_TPI_TYPE(nconf))
4417836SJohn.Forte@Sun.COM 			do_one(nconf->nc_device, nconf->nc_proto,
4427836SJohn.Forte@Sun.COM 				protobp, svc);
4437836SJohn.Forte@Sun.COM 	}
4447836SJohn.Forte@Sun.COM 	(void) endnetconfig(nc);
4457836SJohn.Forte@Sun.COM 	return (0);
4467836SJohn.Forte@Sun.COM }
4477836SJohn.Forte@Sun.COM 
4487836SJohn.Forte@Sun.COM /*
4497836SJohn.Forte@Sun.COM  * Read the /etc/default/sndr configuration file to determine if the
4507836SJohn.Forte@Sun.COM  * client has been configured for number of threads, backlog or transport
4517836SJohn.Forte@Sun.COM  * provider.
4527836SJohn.Forte@Sun.COM  */
4537836SJohn.Forte@Sun.COM 
4547836SJohn.Forte@Sun.COM static void
read_default(void)4557836SJohn.Forte@Sun.COM read_default(void)
4567836SJohn.Forte@Sun.COM {
4577836SJohn.Forte@Sun.COM 	char *defval, *tmp_str;
4587836SJohn.Forte@Sun.COM 	int errno;
4597836SJohn.Forte@Sun.COM 	int tmp;
4607836SJohn.Forte@Sun.COM 
4617836SJohn.Forte@Sun.COM 	/* Fail silently if error in opening the default rdc config file */
4627836SJohn.Forte@Sun.COM 	if ((defopen(RDCADMIN)) == 0) {
4637836SJohn.Forte@Sun.COM 		if ((defval = defread("SNDR_THREADS=")) != NULL) {
4647836SJohn.Forte@Sun.COM 			errno = 0;
4657836SJohn.Forte@Sun.COM 			tmp = strtol(defval, (char **)NULL, 10);
4667836SJohn.Forte@Sun.COM 			if (errno == 0) {
4677836SJohn.Forte@Sun.COM 				max_conns_allowed = tmp;
4687836SJohn.Forte@Sun.COM 			}
4697836SJohn.Forte@Sun.COM 		}
4707836SJohn.Forte@Sun.COM 		if ((defval = defread("SNDR_LISTEN_BACKLOG=")) != NULL) {
4717836SJohn.Forte@Sun.COM 			errno = 0;
4727836SJohn.Forte@Sun.COM 			tmp = strtol(defval, (char **)NULL, 10);
4737836SJohn.Forte@Sun.COM 			if (errno == 0) {
4747836SJohn.Forte@Sun.COM 				listen_backlog = tmp;
4757836SJohn.Forte@Sun.COM 			}
4767836SJohn.Forte@Sun.COM 		}
4777836SJohn.Forte@Sun.COM 		if ((defval = defread("SNDR_TRANSPORT=")) != NULL) {
4787836SJohn.Forte@Sun.COM 			errno = 0;
4797836SJohn.Forte@Sun.COM 			tmp_str = strdup(defval);
4807836SJohn.Forte@Sun.COM 			if (errno == 0) {
4817836SJohn.Forte@Sun.COM 				trans_provider = tmp_str;
4827836SJohn.Forte@Sun.COM 			}
4837836SJohn.Forte@Sun.COM 		}
4847836SJohn.Forte@Sun.COM 		/* close defaults file */
485*11576SSurya.Prakki@Sun.COM 		(void) defopen(NULL);
4867836SJohn.Forte@Sun.COM 	}
4877836SJohn.Forte@Sun.COM }
4887836SJohn.Forte@Sun.COM #ifdef lint
4897836SJohn.Forte@Sun.COM int
sndrd_lintmain(int ac,char ** av)4907836SJohn.Forte@Sun.COM sndrd_lintmain(int ac, char **av)
4917836SJohn.Forte@Sun.COM #else
4927836SJohn.Forte@Sun.COM int
4937836SJohn.Forte@Sun.COM main(int ac, char **av)
4947836SJohn.Forte@Sun.COM #endif
4957836SJohn.Forte@Sun.COM {
4967836SJohn.Forte@Sun.COM 	const char *dir = "/";
4977836SJohn.Forte@Sun.COM 	int allflag = 0;
4987836SJohn.Forte@Sun.COM 	int pid;
4997836SJohn.Forte@Sun.COM 	int i, rc;
5007836SJohn.Forte@Sun.COM 	struct protob *protobp0, *protobp;
5017836SJohn.Forte@Sun.COM 	char **providerp;
5027836SJohn.Forte@Sun.COM 	char *required;
5037836SJohn.Forte@Sun.COM #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
5047836SJohn.Forte@Sun.COM 	int maxservers;
5057836SJohn.Forte@Sun.COM #endif
5067836SJohn.Forte@Sun.COM 
5077836SJohn.Forte@Sun.COM 	(void) setlocale(LC_ALL, "");
5087836SJohn.Forte@Sun.COM #ifdef	__NCALL__
5097836SJohn.Forte@Sun.COM 	(void) textdomain("ncall");
5107836SJohn.Forte@Sun.COM #else
5117836SJohn.Forte@Sun.COM 	(void) textdomain("rdc");
5127836SJohn.Forte@Sun.COM #endif
5137836SJohn.Forte@Sun.COM 
5147836SJohn.Forte@Sun.COM 	progname = basename(av[0]);
5157836SJohn.Forte@Sun.COM 
5167836SJohn.Forte@Sun.COM #ifdef	__NCALL__
5177836SJohn.Forte@Sun.COM 	rc = ncall_check_release(&required);
5187836SJohn.Forte@Sun.COM #else
5197836SJohn.Forte@Sun.COM 	rc = rdc_check_release(&required);
5207836SJohn.Forte@Sun.COM #endif
5217836SJohn.Forte@Sun.COM 	if (rc < 0) {
5227836SJohn.Forte@Sun.COM 		(void) fprintf(stderr,
5237836SJohn.Forte@Sun.COM 		    gettext("%s: unable to determine the current "
5247836SJohn.Forte@Sun.COM 		    "Solaris release: %s\n"), progname, strerror(errno));
5257836SJohn.Forte@Sun.COM 		exit(1);
5267836SJohn.Forte@Sun.COM 	} else if (rc == FALSE) {
5277836SJohn.Forte@Sun.COM 		(void) fprintf(stderr,
5287836SJohn.Forte@Sun.COM 		    gettext("%s: incorrect Solaris release (requires %s)\n"),
5297836SJohn.Forte@Sun.COM 		    progname, required);
5307836SJohn.Forte@Sun.COM 		exit(1);
5317836SJohn.Forte@Sun.COM 	}
5327836SJohn.Forte@Sun.COM 
5337836SJohn.Forte@Sun.COM 	openlog(progname, LOG_PID|LOG_CONS, LOG_DAEMON);
5347836SJohn.Forte@Sun.COM 	read_default();
5357836SJohn.Forte@Sun.COM 
5367836SJohn.Forte@Sun.COM 	/*
5377836SJohn.Forte@Sun.COM 	 * Usage: <progname> [-c <number of threads>] [-t protocol] \
5387836SJohn.Forte@Sun.COM 	 *		[-d] [-l <listen backlog>]
5397836SJohn.Forte@Sun.COM 	 */
5407836SJohn.Forte@Sun.COM 	while ((i = getopt(ac, av, "ac:t:dl:")) != EOF) {
5417836SJohn.Forte@Sun.COM 		switch (i) {
5427836SJohn.Forte@Sun.COM 			case 'a':
5437836SJohn.Forte@Sun.COM 				allflag = 1;
5447836SJohn.Forte@Sun.COM 				break;
5457836SJohn.Forte@Sun.COM 			case 'c':
5467836SJohn.Forte@Sun.COM 				max_conns_allowed = atoi(optarg);
5477836SJohn.Forte@Sun.COM 				if (max_conns_allowed <= 0)
5487836SJohn.Forte@Sun.COM 					max_conns_allowed = 16;
5497836SJohn.Forte@Sun.COM 				break;
5507836SJohn.Forte@Sun.COM 
5517836SJohn.Forte@Sun.COM 			case 'd':
5527836SJohn.Forte@Sun.COM 				debugflg++;
5537836SJohn.Forte@Sun.COM 				break;
5547836SJohn.Forte@Sun.COM 
5557836SJohn.Forte@Sun.COM 			case 't':
5567836SJohn.Forte@Sun.COM 				trans_provider = optarg;
5577836SJohn.Forte@Sun.COM 				break;
5587836SJohn.Forte@Sun.COM 
5597836SJohn.Forte@Sun.COM 			case 'l':
5607836SJohn.Forte@Sun.COM 				listen_backlog = atoi(optarg);
5617836SJohn.Forte@Sun.COM 				if (listen_backlog < 0)
5627836SJohn.Forte@Sun.COM 					listen_backlog = 32;
5637836SJohn.Forte@Sun.COM 				break;
5647836SJohn.Forte@Sun.COM 
5657836SJohn.Forte@Sun.COM 			default:
5667836SJohn.Forte@Sun.COM 				syslog(LOG_ERR,
5677836SJohn.Forte@Sun.COM 				    "Usage: %s [-c <number of threads>] "
5687836SJohn.Forte@Sun.COM 				    "[-d] [-t protocol] "
5697836SJohn.Forte@Sun.COM 				    "[-l <listen backlog>]\n", progname);
5707836SJohn.Forte@Sun.COM 				exit(1);
5717836SJohn.Forte@Sun.COM 				break;
5727836SJohn.Forte@Sun.COM 		}
5737836SJohn.Forte@Sun.COM 	}
5747836SJohn.Forte@Sun.COM 
5757836SJohn.Forte@Sun.COM 	if (chroot(dir) < 0) {
5767836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "chroot failed: %m");
5777836SJohn.Forte@Sun.COM 		exit(1);
5787836SJohn.Forte@Sun.COM 	}
5797836SJohn.Forte@Sun.COM 
5807836SJohn.Forte@Sun.COM 	if (chdir(dir) < 0) {
5817836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "chdir failed: %m");
5827836SJohn.Forte@Sun.COM 		exit(1);
5837836SJohn.Forte@Sun.COM 	}
5847836SJohn.Forte@Sun.COM 
5857836SJohn.Forte@Sun.COM 	if (!debugflg) {
5867836SJohn.Forte@Sun.COM 		pid = fork();
5877836SJohn.Forte@Sun.COM 		if (pid < 0) {
5887836SJohn.Forte@Sun.COM 			syslog(LOG_ERR, "Fork failed\n");
5897836SJohn.Forte@Sun.COM 			exit(1);
5907836SJohn.Forte@Sun.COM 		}
5917836SJohn.Forte@Sun.COM 		if (pid != 0)
5927836SJohn.Forte@Sun.COM 			exit(0);
5937836SJohn.Forte@Sun.COM 
5947836SJohn.Forte@Sun.COM 		/*
5957836SJohn.Forte@Sun.COM 		 * Close existing file descriptors, open "/dev/null" as
5967836SJohn.Forte@Sun.COM 		 * standard input, output, and error, and detach from
5977836SJohn.Forte@Sun.COM 		 * controlling terminal.
5987836SJohn.Forte@Sun.COM 		 */
5997836SJohn.Forte@Sun.COM #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
6007836SJohn.Forte@Sun.COM 		/* use closefrom(3C) from PSARC/2000/193 when possible */
6017836SJohn.Forte@Sun.COM 		closefrom(0);
6027836SJohn.Forte@Sun.COM #else
6037836SJohn.Forte@Sun.COM 		for (i = 0; i < _NFILE; i++)
6047836SJohn.Forte@Sun.COM 			(void) close(i);
6057836SJohn.Forte@Sun.COM #endif
6067836SJohn.Forte@Sun.COM 		(void) open("/dev/null", O_RDONLY);
6077836SJohn.Forte@Sun.COM 		(void) open("/dev/null", O_WRONLY);
6087836SJohn.Forte@Sun.COM 		(void) dup(1);
6097836SJohn.Forte@Sun.COM 		(void) setsid();
6107836SJohn.Forte@Sun.COM 
6117836SJohn.Forte@Sun.COM 		/*
6127836SJohn.Forte@Sun.COM 		 * ignore all signals apart from SIGTERM.
6137836SJohn.Forte@Sun.COM 		 */
6147836SJohn.Forte@Sun.COM 		for (i = 1; i < _sys_nsig; i++)
6157836SJohn.Forte@Sun.COM 			(void) sigset(i, SIG_IGN);
6167836SJohn.Forte@Sun.COM 
6177836SJohn.Forte@Sun.COM 		(void) sigset(SIGTERM, SIG_DFL);
6187836SJohn.Forte@Sun.COM 	}
6197836SJohn.Forte@Sun.COM 
6207836SJohn.Forte@Sun.COM #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
6217836SJohn.Forte@Sun.COM 	/*
6227836SJohn.Forte@Sun.COM 	 * Set up kernel RPC thread pool for the SNDR/ncall-ip server.
6237836SJohn.Forte@Sun.COM 	 */
6247836SJohn.Forte@Sun.COM 	maxservers = (max_conns_allowed < 0 ? 16 : max_conns_allowed);
6257836SJohn.Forte@Sun.COM 	if (sndrsvcpool(maxservers)) {
6267836SJohn.Forte@Sun.COM 		(void) syslog(LOG_ERR,
6277836SJohn.Forte@Sun.COM 		    "Can't set up kernel %s service: %m. Exiting", progname);
6287836SJohn.Forte@Sun.COM 		exit(1);
6297836SJohn.Forte@Sun.COM 	}
6307836SJohn.Forte@Sun.COM 
6317836SJohn.Forte@Sun.COM 	/*
6327836SJohn.Forte@Sun.COM 	 * Set up blocked thread to do LWP creation on behalf of the kernel.
6337836SJohn.Forte@Sun.COM 	 */
6347836SJohn.Forte@Sun.COM 	if (svcwait(RDC_SVCPOOL_ID)) {
6357836SJohn.Forte@Sun.COM 		(void) syslog(LOG_ERR,
6367836SJohn.Forte@Sun.COM 		    "Can't set up %s pool creator: %m, Exiting", progname);
6377836SJohn.Forte@Sun.COM 		exit(1);
6387836SJohn.Forte@Sun.COM 	}
6397836SJohn.Forte@Sun.COM #endif
6407836SJohn.Forte@Sun.COM 
6417836SJohn.Forte@Sun.COM 	/*
6427836SJohn.Forte@Sun.COM 	 * Build a protocol block list for registration.
6437836SJohn.Forte@Sun.COM 	 */
6447836SJohn.Forte@Sun.COM 	protobp0 = protobp = (struct protob *)malloc(sizeof (struct protob));
6457836SJohn.Forte@Sun.COM 	protobp->serv = RDC_SVC_NAME;
6467836SJohn.Forte@Sun.COM 	protobp->versmin = RDC_VERS_MIN;
6477836SJohn.Forte@Sun.COM 	protobp->versmax = RDC_VERS_MAX;
6487836SJohn.Forte@Sun.COM 	protobp->program = RDC_PROGRAM;
6497836SJohn.Forte@Sun.COM 	protobp->next = (struct protob *)NULL;
6507836SJohn.Forte@Sun.COM 
6517836SJohn.Forte@Sun.COM 	if (allflag) {
6527836SJohn.Forte@Sun.COM 		if (do_all(protobp0, rdcsvc) == -1)
6537836SJohn.Forte@Sun.COM 			exit(1);
6547836SJohn.Forte@Sun.COM 	} else if (trans_provider)
6557836SJohn.Forte@Sun.COM 		do_one(trans_provider, NULL, protobp0, rdcsvc);
6567836SJohn.Forte@Sun.COM 	else {
6577836SJohn.Forte@Sun.COM 		for (providerp = defaultproviders;
6587836SJohn.Forte@Sun.COM 		    *providerp != NULL; providerp++) {
6597836SJohn.Forte@Sun.COM 			trans_provider = *providerp;
6607836SJohn.Forte@Sun.COM 			do_one(trans_provider, NULL, protobp0, rdcsvc);
6617836SJohn.Forte@Sun.COM 		}
6627836SJohn.Forte@Sun.COM 	}
6637836SJohn.Forte@Sun.COM 
6647836SJohn.Forte@Sun.COM done:
6657836SJohn.Forte@Sun.COM 	free(protobp);
6667836SJohn.Forte@Sun.COM 
6677836SJohn.Forte@Sun.COM 	end_listen_fds = num_fds;
6687836SJohn.Forte@Sun.COM 	/*
6697836SJohn.Forte@Sun.COM 	 * Poll for non-data control events on the transport descriptors.
6707836SJohn.Forte@Sun.COM 	 */
6717836SJohn.Forte@Sun.COM 	poll_for_action();
6727836SJohn.Forte@Sun.COM 
6737836SJohn.Forte@Sun.COM 	syslog(LOG_ERR, "%s fatal server error\n", progname);
6747836SJohn.Forte@Sun.COM 
6757836SJohn.Forte@Sun.COM 	return (-1);
6767836SJohn.Forte@Sun.COM }
6777836SJohn.Forte@Sun.COM 
6787836SJohn.Forte@Sun.COM static int
reuseaddr(int fd)6797836SJohn.Forte@Sun.COM reuseaddr(int fd)
6807836SJohn.Forte@Sun.COM {
6817836SJohn.Forte@Sun.COM 	struct t_optmgmt req, resp;
6827836SJohn.Forte@Sun.COM 	struct opthdr *opt;
6837836SJohn.Forte@Sun.COM 	char reqbuf[128];
6847836SJohn.Forte@Sun.COM 	int *ip;
6857836SJohn.Forte@Sun.COM 
6867836SJohn.Forte@Sun.COM 	/* LINTED pointer alignment */
6877836SJohn.Forte@Sun.COM 	opt = (struct opthdr *)reqbuf;
6887836SJohn.Forte@Sun.COM 	opt->level = SOL_SOCKET;
6897836SJohn.Forte@Sun.COM 	opt->name = SO_REUSEADDR;
6907836SJohn.Forte@Sun.COM 	opt->len = sizeof (int);
6917836SJohn.Forte@Sun.COM 
6927836SJohn.Forte@Sun.COM 	/* LINTED pointer alignment */
6937836SJohn.Forte@Sun.COM 	ip = (int *)&reqbuf[sizeof (struct opthdr)];
6947836SJohn.Forte@Sun.COM 	*ip = 1;
6957836SJohn.Forte@Sun.COM 
6967836SJohn.Forte@Sun.COM 	req.flags = T_NEGOTIATE;
6977836SJohn.Forte@Sun.COM 	req.opt.len = sizeof (struct opthdr) + opt->len;
6987836SJohn.Forte@Sun.COM 	req.opt.buf = (char *)opt;
6997836SJohn.Forte@Sun.COM 
7007836SJohn.Forte@Sun.COM 	resp.flags = 0;
7017836SJohn.Forte@Sun.COM 	resp.opt.buf = reqbuf;
7027836SJohn.Forte@Sun.COM 	resp.opt.maxlen = sizeof (reqbuf);
7037836SJohn.Forte@Sun.COM 
7047836SJohn.Forte@Sun.COM 	if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
7057836SJohn.Forte@Sun.COM 		if (t_errno == TSYSERR) {
7067836SJohn.Forte@Sun.COM 			syslog(LOG_ERR, "reuseaddr() t_optmgmt failed: %m\n");
7077836SJohn.Forte@Sun.COM 		} else {
7087836SJohn.Forte@Sun.COM 			syslog(LOG_ERR, "reuseaddr() t_optmgmt failed: %s\n",
7097836SJohn.Forte@Sun.COM 			    t_errlist[t_errno]);
7107836SJohn.Forte@Sun.COM 		}
7117836SJohn.Forte@Sun.COM 		return (-1);
7127836SJohn.Forte@Sun.COM 	}
7137836SJohn.Forte@Sun.COM 	return (0);
7147836SJohn.Forte@Sun.COM }
7157836SJohn.Forte@Sun.COM 
7167836SJohn.Forte@Sun.COM /*
7177836SJohn.Forte@Sun.COM  * poll on the open transport descriptors for events and errors.
7187836SJohn.Forte@Sun.COM  */
7197836SJohn.Forte@Sun.COM void
poll_for_action(void)7207836SJohn.Forte@Sun.COM poll_for_action(void)
7217836SJohn.Forte@Sun.COM {
7227836SJohn.Forte@Sun.COM 	int nfds;
7237836SJohn.Forte@Sun.COM 	int i;
7247836SJohn.Forte@Sun.COM 
7257836SJohn.Forte@Sun.COM 	/*
7267836SJohn.Forte@Sun.COM 	 * Keep polling until all transports have been closed. When this
7277836SJohn.Forte@Sun.COM 	 * happens, we return.
7287836SJohn.Forte@Sun.COM 	 */
7297836SJohn.Forte@Sun.COM 	while ((int)num_fds > 0) {
7307836SJohn.Forte@Sun.COM 		nfds = poll(poll_array, num_fds, INFTIM);
7317836SJohn.Forte@Sun.COM 		switch (nfds) {
7327836SJohn.Forte@Sun.COM 		case 0:
7337836SJohn.Forte@Sun.COM 			continue;
7347836SJohn.Forte@Sun.COM 
7357836SJohn.Forte@Sun.COM 		case -1:
7367836SJohn.Forte@Sun.COM 			/*
7377836SJohn.Forte@Sun.COM 			 * Some errors from poll could be
7387836SJohn.Forte@Sun.COM 			 * due to temporary conditions, and we try to
7397836SJohn.Forte@Sun.COM 			 * be robust in the face of them. Other
7407836SJohn.Forte@Sun.COM 			 * errors (should never happen in theory)
7417836SJohn.Forte@Sun.COM 			 * are fatal (eg. EINVAL, EFAULT).
7427836SJohn.Forte@Sun.COM 			 */
7437836SJohn.Forte@Sun.COM 			switch (errno) {
7447836SJohn.Forte@Sun.COM 			case EINTR:
7457836SJohn.Forte@Sun.COM 			    continue;
7467836SJohn.Forte@Sun.COM 
7477836SJohn.Forte@Sun.COM 			case EAGAIN:
7487836SJohn.Forte@Sun.COM 			case ENOMEM:
7497836SJohn.Forte@Sun.COM 				(void) sleep(10);
7507836SJohn.Forte@Sun.COM 				continue;
7517836SJohn.Forte@Sun.COM 
7527836SJohn.Forte@Sun.COM 			default:
7537836SJohn.Forte@Sun.COM 				(void) syslog(LOG_ERR,
7547836SJohn.Forte@Sun.COM 				    "poll failed: %m. Exiting");
7557836SJohn.Forte@Sun.COM 				exit(1);
7567836SJohn.Forte@Sun.COM 			}
7577836SJohn.Forte@Sun.COM 		default:
7587836SJohn.Forte@Sun.COM 			break;
7597836SJohn.Forte@Sun.COM 		}
7607836SJohn.Forte@Sun.COM 
7617836SJohn.Forte@Sun.COM 		/*
7627836SJohn.Forte@Sun.COM 		 * Go through the poll list looking for events.
7637836SJohn.Forte@Sun.COM 		 */
7647836SJohn.Forte@Sun.COM 		for (i = 0; i < num_fds && nfds > 0; i++) {
7657836SJohn.Forte@Sun.COM 			if (poll_array[i].revents) {
7667836SJohn.Forte@Sun.COM 				nfds--;
7677836SJohn.Forte@Sun.COM 				/*
7687836SJohn.Forte@Sun.COM 				 * We have a message, so try to read it.
7697836SJohn.Forte@Sun.COM 				 * Record the error return in errno,
7707836SJohn.Forte@Sun.COM 				 * so that syslog(LOG_ERR, "...%m")
7717836SJohn.Forte@Sun.COM 				 * dumps the corresponding error string.
7727836SJohn.Forte@Sun.COM 				 */
7737836SJohn.Forte@Sun.COM 				if (conn_polled[i].nc.nc_semantics ==
7747836SJohn.Forte@Sun.COM 				    NC_TPI_CLTS) {
7757836SJohn.Forte@Sun.COM 					errno = do_poll_clts_action(
7767836SJohn.Forte@Sun.COM 					    poll_array[i].fd, i);
7777836SJohn.Forte@Sun.COM 				} else {
7787836SJohn.Forte@Sun.COM 					errno = do_poll_cots_action(
7797836SJohn.Forte@Sun.COM 					    poll_array[i].fd, i);
7807836SJohn.Forte@Sun.COM 				}
7817836SJohn.Forte@Sun.COM 
7827836SJohn.Forte@Sun.COM 				if (errno == 0)
7837836SJohn.Forte@Sun.COM 					continue;
7847836SJohn.Forte@Sun.COM 				/*
7857836SJohn.Forte@Sun.COM 				 * Most returned error codes mean that there is
7867836SJohn.Forte@Sun.COM 				 * fatal condition which we can only deal with
7877836SJohn.Forte@Sun.COM 				 * by closing the transport.
7887836SJohn.Forte@Sun.COM 				 */
7897836SJohn.Forte@Sun.COM 				if (errno != EAGAIN && errno != ENOMEM) {
7907836SJohn.Forte@Sun.COM 					(void) syslog(LOG_ERR,
7917836SJohn.Forte@Sun.COM 					    "Error (%m) reading descriptor %d"
7927836SJohn.Forte@Sun.COM 					    "/transport %s. Closing it.",
7937836SJohn.Forte@Sun.COM 					    poll_array[i].fd,
7947836SJohn.Forte@Sun.COM 					    conn_polled[i].nc.nc_proto);
7957836SJohn.Forte@Sun.COM 					(void) t_close(poll_array[i].fd);
7967836SJohn.Forte@Sun.COM 					remove_from_poll_list(poll_array[i].fd);
7977836SJohn.Forte@Sun.COM 				} else if (errno == ENOMEM)
7987836SJohn.Forte@Sun.COM 					(void) sleep(5);
7997836SJohn.Forte@Sun.COM 			}
8007836SJohn.Forte@Sun.COM 		}
8017836SJohn.Forte@Sun.COM 	}
8027836SJohn.Forte@Sun.COM 
8037836SJohn.Forte@Sun.COM 	(void) syslog(LOG_ERR,
8047836SJohn.Forte@Sun.COM 	    "All transports have been closed with errors. Exiting.");
8057836SJohn.Forte@Sun.COM }
8067836SJohn.Forte@Sun.COM 
8077836SJohn.Forte@Sun.COM /*
8087836SJohn.Forte@Sun.COM  * Allocate poll/transport array entries for this descriptor.
8097836SJohn.Forte@Sun.COM  */
8107836SJohn.Forte@Sun.COM static void
add_to_poll_list(int fd,struct netconfig * nconf)8117836SJohn.Forte@Sun.COM add_to_poll_list(int fd, struct netconfig *nconf)
8127836SJohn.Forte@Sun.COM {
8137836SJohn.Forte@Sun.COM 	static int poll_array_size = 0;
8147836SJohn.Forte@Sun.COM 
8157836SJohn.Forte@Sun.COM 	/*
8167836SJohn.Forte@Sun.COM 	 * If the arrays are full, allocate new ones.
8177836SJohn.Forte@Sun.COM 	 */
8187836SJohn.Forte@Sun.COM 	if (num_fds == poll_array_size) {
8197836SJohn.Forte@Sun.COM 		struct pollfd *tpa;
8207836SJohn.Forte@Sun.COM 		struct conn_entry *tnp;
8217836SJohn.Forte@Sun.COM 
8227836SJohn.Forte@Sun.COM 		if (poll_array_size != 0) {
8237836SJohn.Forte@Sun.COM 			tpa = poll_array;
8247836SJohn.Forte@Sun.COM 			tnp = conn_polled;
8257836SJohn.Forte@Sun.COM 		} else
8267836SJohn.Forte@Sun.COM 			tpa = (struct pollfd *)0;
8277836SJohn.Forte@Sun.COM 
8287836SJohn.Forte@Sun.COM 		poll_array_size += POLL_ARRAY_INC_SIZE;
8297836SJohn.Forte@Sun.COM 
8307836SJohn.Forte@Sun.COM 		/*
8317836SJohn.Forte@Sun.COM 		 * Allocate new arrays.
8327836SJohn.Forte@Sun.COM 		 */
8337836SJohn.Forte@Sun.COM 		poll_array = (struct pollfd *)
8347836SJohn.Forte@Sun.COM 		    malloc(poll_array_size * sizeof (struct pollfd) + 256);
8357836SJohn.Forte@Sun.COM 		conn_polled = (struct conn_entry *)
8367836SJohn.Forte@Sun.COM 		    malloc(poll_array_size * sizeof (struct conn_entry) + 256);
8377836SJohn.Forte@Sun.COM 		if (poll_array == (struct pollfd *)NULL ||
8387836SJohn.Forte@Sun.COM 		    conn_polled == (struct conn_entry *)NULL) {
8397836SJohn.Forte@Sun.COM 			syslog(LOG_ERR, "malloc failed for poll array");
8407836SJohn.Forte@Sun.COM 			exit(1);
8417836SJohn.Forte@Sun.COM 		}
8427836SJohn.Forte@Sun.COM 
8437836SJohn.Forte@Sun.COM 		/*
8447836SJohn.Forte@Sun.COM 		 * Copy the data of the old ones into new arrays, and
8457836SJohn.Forte@Sun.COM 		 * free the old ones.
8467836SJohn.Forte@Sun.COM 		 * num_fds is guaranteed to be less than
8477836SJohn.Forte@Sun.COM 		 * poll_array_size, so this memcpy is safe.
8487836SJohn.Forte@Sun.COM 		 */
8497836SJohn.Forte@Sun.COM 		if (tpa) {
8507836SJohn.Forte@Sun.COM 			(void) memcpy((void *)poll_array, (void *)tpa,
8517836SJohn.Forte@Sun.COM 				num_fds * sizeof (struct pollfd));
8527836SJohn.Forte@Sun.COM 			(void) memcpy((void *)conn_polled, (void *)tnp,
8537836SJohn.Forte@Sun.COM 				num_fds * sizeof (struct conn_entry));
8547836SJohn.Forte@Sun.COM 			free((void *)tpa);
8557836SJohn.Forte@Sun.COM 			free((void *)tnp);
8567836SJohn.Forte@Sun.COM 		}
8577836SJohn.Forte@Sun.COM 	}
8587836SJohn.Forte@Sun.COM 
8597836SJohn.Forte@Sun.COM 	/*
8607836SJohn.Forte@Sun.COM 	 * Set the descriptor and event list. All possible events are
8617836SJohn.Forte@Sun.COM 	 * polled for.
8627836SJohn.Forte@Sun.COM 	 */
8637836SJohn.Forte@Sun.COM 	poll_array[num_fds].fd = fd;
8647836SJohn.Forte@Sun.COM 	poll_array[num_fds].events = POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI;
8657836SJohn.Forte@Sun.COM 
8667836SJohn.Forte@Sun.COM 	/*
8677836SJohn.Forte@Sun.COM 	 * Copy the transport data over too.
8687836SJohn.Forte@Sun.COM 	 */
8697836SJohn.Forte@Sun.COM 	conn_polled[num_fds].nc = *nconf;	/* structure copy */
8707836SJohn.Forte@Sun.COM 	conn_polled[num_fds].closing = 0;
8717836SJohn.Forte@Sun.COM 
8727836SJohn.Forte@Sun.COM 	/*
8737836SJohn.Forte@Sun.COM 	 * Set the descriptor to non-blocking. Avoids a race
8747836SJohn.Forte@Sun.COM 	 * between data arriving on the stream and then having it
8757836SJohn.Forte@Sun.COM 	 * flushed before we can read it.
8767836SJohn.Forte@Sun.COM 	 */
8777836SJohn.Forte@Sun.COM 	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
8787836SJohn.Forte@Sun.COM 		(void) syslog(LOG_ERR,
8797836SJohn.Forte@Sun.COM 		    "fcntl(file desc. %d/transport %s, F_SETFL, "
8807836SJohn.Forte@Sun.COM 		    "O_NONBLOCK): %m. Exiting",
8817836SJohn.Forte@Sun.COM 		    num_fds, nconf->nc_proto);
8827836SJohn.Forte@Sun.COM 		exit(1);
8837836SJohn.Forte@Sun.COM 	}
8847836SJohn.Forte@Sun.COM 
8857836SJohn.Forte@Sun.COM 	/*
8867836SJohn.Forte@Sun.COM 	 * Count this descriptor.
8877836SJohn.Forte@Sun.COM 	 */
8887836SJohn.Forte@Sun.COM 	++num_fds;
8897836SJohn.Forte@Sun.COM }
8907836SJohn.Forte@Sun.COM 
8917836SJohn.Forte@Sun.COM static void
remove_from_poll_list(int fd)8927836SJohn.Forte@Sun.COM remove_from_poll_list(int fd)
8937836SJohn.Forte@Sun.COM {
8947836SJohn.Forte@Sun.COM 	int i;
8957836SJohn.Forte@Sun.COM 	int num_to_copy;
8967836SJohn.Forte@Sun.COM 
8977836SJohn.Forte@Sun.COM 	for (i = 0; i < num_fds; i++) {
8987836SJohn.Forte@Sun.COM 		if (poll_array[i].fd == fd) {
8997836SJohn.Forte@Sun.COM 			--num_fds;
9007836SJohn.Forte@Sun.COM 			num_to_copy = num_fds - i;
9017836SJohn.Forte@Sun.COM 			(void) memcpy((void *)&poll_array[i],
9027836SJohn.Forte@Sun.COM 			    (void *)&poll_array[i+1],
9037836SJohn.Forte@Sun.COM 			    num_to_copy * sizeof (struct pollfd));
9047836SJohn.Forte@Sun.COM 			(void) memset((void *)&poll_array[num_fds], 0,
9057836SJohn.Forte@Sun.COM 			    sizeof (struct pollfd));
9067836SJohn.Forte@Sun.COM 			(void) memcpy((void *)&conn_polled[i],
9077836SJohn.Forte@Sun.COM 			    (void *)&conn_polled[i+1],
9087836SJohn.Forte@Sun.COM 			    num_to_copy * sizeof (struct conn_entry));
9097836SJohn.Forte@Sun.COM 			(void) memset((void *)&conn_polled[num_fds], 0,
9107836SJohn.Forte@Sun.COM 			    sizeof (struct conn_entry));
9117836SJohn.Forte@Sun.COM 			return;
9127836SJohn.Forte@Sun.COM 		}
9137836SJohn.Forte@Sun.COM 	}
9147836SJohn.Forte@Sun.COM 	syslog(LOG_ERR, "attempt to remove nonexistent fd from poll list");
9157836SJohn.Forte@Sun.COM 
9167836SJohn.Forte@Sun.COM }
9177836SJohn.Forte@Sun.COM 
9187836SJohn.Forte@Sun.COM static void
conn_close_oldest(void)9197836SJohn.Forte@Sun.COM conn_close_oldest(void)
9207836SJohn.Forte@Sun.COM {
9217836SJohn.Forte@Sun.COM 	int fd;
9227836SJohn.Forte@Sun.COM 	int i1;
9237836SJohn.Forte@Sun.COM 
9247836SJohn.Forte@Sun.COM 	/*
9257836SJohn.Forte@Sun.COM 	 * Find the oldest connection that is not already in the
9267836SJohn.Forte@Sun.COM 	 * process of shutting down.
9277836SJohn.Forte@Sun.COM 	 */
9287836SJohn.Forte@Sun.COM 	for (i1 = end_listen_fds; /* no conditional expression */; i1++) {
9297836SJohn.Forte@Sun.COM 		if (i1 >= num_fds)
9307836SJohn.Forte@Sun.COM 			return;
9317836SJohn.Forte@Sun.COM 		if (conn_polled[i1].closing == 0)
9327836SJohn.Forte@Sun.COM 			break;
9337836SJohn.Forte@Sun.COM 	}
9347836SJohn.Forte@Sun.COM #ifdef DEBUG
9357836SJohn.Forte@Sun.COM 	(void) printf("too many connections (%d), releasing oldest (%d)\n",
9367836SJohn.Forte@Sun.COM 	    num_conns, poll_array[i1].fd);
9377836SJohn.Forte@Sun.COM #else
9387836SJohn.Forte@Sun.COM 	syslog(LOG_WARNING, "too many connections (%d), releasing oldest (%d)",
9397836SJohn.Forte@Sun.COM 	    num_conns, poll_array[i1].fd);
9407836SJohn.Forte@Sun.COM #endif
9417836SJohn.Forte@Sun.COM 	fd = poll_array[i1].fd;
9427836SJohn.Forte@Sun.COM 	if (conn_polled[i1].nc.nc_semantics == NC_TPI_COTS) {
9437836SJohn.Forte@Sun.COM 		/*
9447836SJohn.Forte@Sun.COM 		 * For politeness, send a T_DISCON_REQ to the transport
9457836SJohn.Forte@Sun.COM 		 * provider.  We close the stream anyway.
9467836SJohn.Forte@Sun.COM 		 */
9477836SJohn.Forte@Sun.COM 		(void) t_snddis(fd, (struct t_call *)0);
9487836SJohn.Forte@Sun.COM 		num_conns--;
9497836SJohn.Forte@Sun.COM 		remove_from_poll_list(fd);
9507836SJohn.Forte@Sun.COM 		(void) t_close(fd);
9517836SJohn.Forte@Sun.COM 	} else {
9527836SJohn.Forte@Sun.COM 		/*
9537836SJohn.Forte@Sun.COM 		 * For orderly release, we do not close the stream
9547836SJohn.Forte@Sun.COM 		 * until the T_ORDREL_IND arrives to complete
9557836SJohn.Forte@Sun.COM 		 * the handshake.
9567836SJohn.Forte@Sun.COM 		 */
9577836SJohn.Forte@Sun.COM 		if (t_sndrel(fd) == 0)
9587836SJohn.Forte@Sun.COM 			conn_polled[i1].closing = 1;
9597836SJohn.Forte@Sun.COM 	}
9607836SJohn.Forte@Sun.COM }
9617836SJohn.Forte@Sun.COM 
9627836SJohn.Forte@Sun.COM static boolean_t
conn_get(int fd,struct netconfig * nconf,struct conn_ind ** connp)9637836SJohn.Forte@Sun.COM conn_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
9647836SJohn.Forte@Sun.COM {
9657836SJohn.Forte@Sun.COM 	struct conn_ind	*conn;
9667836SJohn.Forte@Sun.COM 	struct conn_ind	*next_conn;
9677836SJohn.Forte@Sun.COM 
9687836SJohn.Forte@Sun.COM 	conn = (struct conn_ind *)malloc(sizeof (*conn));
9697836SJohn.Forte@Sun.COM 	if (conn == NULL) {
9707836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "malloc for listen indication failed");
9717836SJohn.Forte@Sun.COM 		return (FALSE);
9727836SJohn.Forte@Sun.COM 	}
9737836SJohn.Forte@Sun.COM 
9747836SJohn.Forte@Sun.COM 	/* LINTED pointer alignment */
9757836SJohn.Forte@Sun.COM 	conn->conn_call = (struct t_call *)t_alloc(fd, T_CALL, T_ALL);
9767836SJohn.Forte@Sun.COM 	if (conn->conn_call == NULL) {
9777836SJohn.Forte@Sun.COM 		free((char *)conn);
9787836SJohn.Forte@Sun.COM 		rdcd_log_tli_error("t_alloc", fd, nconf);
9797836SJohn.Forte@Sun.COM 		return (FALSE);
9807836SJohn.Forte@Sun.COM 	}
9817836SJohn.Forte@Sun.COM 
9827836SJohn.Forte@Sun.COM 	if (t_listen(fd, conn->conn_call) == -1) {
9837836SJohn.Forte@Sun.COM 		rdcd_log_tli_error("t_listen", fd, nconf);
9847836SJohn.Forte@Sun.COM 		(void) t_free((char *)conn->conn_call, T_CALL);
9857836SJohn.Forte@Sun.COM 		free((char *)conn);
9867836SJohn.Forte@Sun.COM 		return (FALSE);
9877836SJohn.Forte@Sun.COM 	}
9887836SJohn.Forte@Sun.COM 
9897836SJohn.Forte@Sun.COM 	if (conn->conn_call->udata.len > 0) {
9907836SJohn.Forte@Sun.COM 		syslog(LOG_WARNING,
9917836SJohn.Forte@Sun.COM 		    "rejecting inbound connection(%s) with %d bytes "
9927836SJohn.Forte@Sun.COM 		    "of connect data",
9937836SJohn.Forte@Sun.COM 		    nconf->nc_proto, conn->conn_call->udata.len);
9947836SJohn.Forte@Sun.COM 
9957836SJohn.Forte@Sun.COM 		conn->conn_call->udata.len = 0;
9967836SJohn.Forte@Sun.COM 		(void) t_snddis(fd, conn->conn_call);
9977836SJohn.Forte@Sun.COM 		(void) t_free((char *)conn->conn_call, T_CALL);
9987836SJohn.Forte@Sun.COM 		free((char *)conn);
9997836SJohn.Forte@Sun.COM 		return (FALSE);
10007836SJohn.Forte@Sun.COM 	}
10017836SJohn.Forte@Sun.COM 
10027836SJohn.Forte@Sun.COM 	if ((next_conn = *connp) != NULL) {
10037836SJohn.Forte@Sun.COM 		next_conn->conn_prev->conn_next = conn;
10047836SJohn.Forte@Sun.COM 		conn->conn_next = next_conn;
10057836SJohn.Forte@Sun.COM 		conn->conn_prev = next_conn->conn_prev;
10067836SJohn.Forte@Sun.COM 		next_conn->conn_prev = conn;
10077836SJohn.Forte@Sun.COM 	} else {
10087836SJohn.Forte@Sun.COM 		conn->conn_next = conn;
10097836SJohn.Forte@Sun.COM 		conn->conn_prev = conn;
10107836SJohn.Forte@Sun.COM 		*connp = conn;
10117836SJohn.Forte@Sun.COM 	}
10127836SJohn.Forte@Sun.COM 	return (TRUE);
10137836SJohn.Forte@Sun.COM }
10147836SJohn.Forte@Sun.COM 
10157836SJohn.Forte@Sun.COM static int
discon_get(int fd,struct netconfig * nconf,struct conn_ind ** connp)10167836SJohn.Forte@Sun.COM discon_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
10177836SJohn.Forte@Sun.COM {
10187836SJohn.Forte@Sun.COM 	struct conn_ind	*conn;
10197836SJohn.Forte@Sun.COM 	struct t_discon	discon;
10207836SJohn.Forte@Sun.COM 
10217836SJohn.Forte@Sun.COM 	discon.udata.buf = (char *)0;
10227836SJohn.Forte@Sun.COM 	discon.udata.maxlen = 0;
10237836SJohn.Forte@Sun.COM 	if (t_rcvdis(fd, &discon) == -1) {
10247836SJohn.Forte@Sun.COM 		rdcd_log_tli_error("t_rcvdis", fd, nconf);
10257836SJohn.Forte@Sun.COM 		return (-1);
10267836SJohn.Forte@Sun.COM 	}
10277836SJohn.Forte@Sun.COM 
10287836SJohn.Forte@Sun.COM 	conn = *connp;
10297836SJohn.Forte@Sun.COM 	if (conn == NULL)
10307836SJohn.Forte@Sun.COM 		return (0);
10317836SJohn.Forte@Sun.COM 
10327836SJohn.Forte@Sun.COM 	do {
10337836SJohn.Forte@Sun.COM 		if (conn->conn_call->sequence == discon.sequence) {
10347836SJohn.Forte@Sun.COM 			if (conn->conn_next == conn)
10357836SJohn.Forte@Sun.COM 				*connp = (struct conn_ind *)0;
10367836SJohn.Forte@Sun.COM 			else {
10377836SJohn.Forte@Sun.COM 				if (conn == *connp) {
10387836SJohn.Forte@Sun.COM 					*connp = conn->conn_next;
10397836SJohn.Forte@Sun.COM 				}
10407836SJohn.Forte@Sun.COM 				conn->conn_next->conn_prev = conn->conn_prev;
10417836SJohn.Forte@Sun.COM 				conn->conn_prev->conn_next = conn->conn_next;
10427836SJohn.Forte@Sun.COM 			}
10437836SJohn.Forte@Sun.COM 			free((char *)conn);
10447836SJohn.Forte@Sun.COM 			break;
10457836SJohn.Forte@Sun.COM 		}
10467836SJohn.Forte@Sun.COM 		conn = conn->conn_next;
10477836SJohn.Forte@Sun.COM 	} while (conn != *connp);
10487836SJohn.Forte@Sun.COM 
10497836SJohn.Forte@Sun.COM 	return (0);
10507836SJohn.Forte@Sun.COM }
10517836SJohn.Forte@Sun.COM 
10527836SJohn.Forte@Sun.COM static void
cots_listen_event(int fd,int conn_index)10537836SJohn.Forte@Sun.COM cots_listen_event(int fd, int conn_index)
10547836SJohn.Forte@Sun.COM {
10557836SJohn.Forte@Sun.COM 	struct t_call *call;
10567836SJohn.Forte@Sun.COM 	struct conn_ind	*conn;
10577836SJohn.Forte@Sun.COM 	struct conn_ind	*conn_head;
10587836SJohn.Forte@Sun.COM 	int event;
10597836SJohn.Forte@Sun.COM 	struct netconfig *nconf = &conn_polled[conn_index].nc;
10607836SJohn.Forte@Sun.COM 	int new_fd;
10617836SJohn.Forte@Sun.COM 	struct netbuf addrmask;
10627836SJohn.Forte@Sun.COM 	int ret = 0;
10637836SJohn.Forte@Sun.COM 
10647836SJohn.Forte@Sun.COM 	conn_head = (struct conn_ind *)0;
10657836SJohn.Forte@Sun.COM 	(void) conn_get(fd, nconf, &conn_head);
10667836SJohn.Forte@Sun.COM 
10677836SJohn.Forte@Sun.COM 	while ((conn = conn_head) != NULL) {
10687836SJohn.Forte@Sun.COM 		conn_head = conn->conn_next;
10697836SJohn.Forte@Sun.COM 		if (conn_head == conn)
10707836SJohn.Forte@Sun.COM 			conn_head = (struct conn_ind *)0;
10717836SJohn.Forte@Sun.COM 		else {
10727836SJohn.Forte@Sun.COM 			conn_head->conn_prev = conn->conn_prev;
10737836SJohn.Forte@Sun.COM 			conn->conn_prev->conn_next = conn_head;
10747836SJohn.Forte@Sun.COM 		}
10757836SJohn.Forte@Sun.COM 		call = conn->conn_call;
10767836SJohn.Forte@Sun.COM 		free((char *)conn);
10777836SJohn.Forte@Sun.COM 
10787836SJohn.Forte@Sun.COM 		/*
10797836SJohn.Forte@Sun.COM 		 * If we have already accepted the maximum number of
10807836SJohn.Forte@Sun.COM 		 * connections allowed on the command line, then drop
10817836SJohn.Forte@Sun.COM 		 * the oldest connection (for any protocol) before
10827836SJohn.Forte@Sun.COM 		 * accepting the new connection.  Unless explicitly
10837836SJohn.Forte@Sun.COM 		 * set on the command line, max_conns_allowed is -1.
10847836SJohn.Forte@Sun.COM 		 */
10857836SJohn.Forte@Sun.COM 		if (max_conns_allowed != -1 && num_conns >= max_conns_allowed)
10867836SJohn.Forte@Sun.COM 			conn_close_oldest();
10877836SJohn.Forte@Sun.COM 
10887836SJohn.Forte@Sun.COM 		/*
10897836SJohn.Forte@Sun.COM 		 * Create a new transport endpoint for the same proto as
10907836SJohn.Forte@Sun.COM 		 * the listener.
10917836SJohn.Forte@Sun.COM 		 */
10927836SJohn.Forte@Sun.COM 		new_fd = rdc_transport_open(nconf);
10937836SJohn.Forte@Sun.COM 		if (new_fd == -1) {
10947836SJohn.Forte@Sun.COM 			call->udata.len = 0;
10957836SJohn.Forte@Sun.COM 			(void) t_snddis(fd, call);
10967836SJohn.Forte@Sun.COM 			(void) t_free((char *)call, T_CALL);
10977836SJohn.Forte@Sun.COM 			syslog(LOG_ERR, "Cannot establish transport over %s",
10987836SJohn.Forte@Sun.COM 			    nconf->nc_device);
10997836SJohn.Forte@Sun.COM 			continue;
11007836SJohn.Forte@Sun.COM 		}
11017836SJohn.Forte@Sun.COM 
11027836SJohn.Forte@Sun.COM 		/* Bind to a generic address/port for the accepting stream. */
11037836SJohn.Forte@Sun.COM 		if (t_bind(new_fd, (struct t_bind *)NULL,
11047836SJohn.Forte@Sun.COM 		    (struct t_bind *)NULL) == -1) {
11057836SJohn.Forte@Sun.COM 			rdcd_log_tli_error("t_bind", new_fd, nconf);
11067836SJohn.Forte@Sun.COM 			call->udata.len = 0;
11077836SJohn.Forte@Sun.COM 			(void) t_snddis(fd, call);
11087836SJohn.Forte@Sun.COM 			(void) t_free((char *)call, T_CALL);
11097836SJohn.Forte@Sun.COM 			(void) t_close(new_fd);
11107836SJohn.Forte@Sun.COM 			continue;
11117836SJohn.Forte@Sun.COM 		}
11127836SJohn.Forte@Sun.COM 
11137836SJohn.Forte@Sun.COM 		while (t_accept(fd, new_fd, call) == -1) {
11147836SJohn.Forte@Sun.COM 			if (t_errno != TLOOK) {
11157836SJohn.Forte@Sun.COM 				rdcd_log_tli_error("t_accept", fd, nconf);
11167836SJohn.Forte@Sun.COM 				call->udata.len = 0;
11177836SJohn.Forte@Sun.COM 				(void) t_snddis(fd, call);
11187836SJohn.Forte@Sun.COM 				(void) t_free((char *)call, T_CALL);
11197836SJohn.Forte@Sun.COM 				(void) t_close(new_fd);
11207836SJohn.Forte@Sun.COM 				goto do_next_conn;
11217836SJohn.Forte@Sun.COM 			}
11227836SJohn.Forte@Sun.COM 			while (event = t_look(fd)) {
11237836SJohn.Forte@Sun.COM 				switch (event) {
11247836SJohn.Forte@Sun.COM 				case T_LISTEN:
11257836SJohn.Forte@Sun.COM #ifdef DEBUG
11267836SJohn.Forte@Sun.COM 					(void) printf(
11277836SJohn.Forte@Sun.COM "cots_listen_event(%s): T_LISTEN during accept processing\n", nconf->nc_proto);
11287836SJohn.Forte@Sun.COM #endif
11297836SJohn.Forte@Sun.COM 					(void) conn_get(fd, nconf, &conn_head);
11307836SJohn.Forte@Sun.COM 					continue;
11317836SJohn.Forte@Sun.COM 
11327836SJohn.Forte@Sun.COM 				case T_DISCONNECT:
11337836SJohn.Forte@Sun.COM #ifdef DEBUG
11347836SJohn.Forte@Sun.COM 					(void) printf(
11357836SJohn.Forte@Sun.COM 	"cots_listen_event(%s): T_DISCONNECT during accept processing\n",
11367836SJohn.Forte@Sun.COM 						nconf->nc_proto);
11377836SJohn.Forte@Sun.COM #endif
11387836SJohn.Forte@Sun.COM 					(void) discon_get(fd, nconf,
11397836SJohn.Forte@Sun.COM 					    &conn_head);
11407836SJohn.Forte@Sun.COM 					continue;
11417836SJohn.Forte@Sun.COM 
11427836SJohn.Forte@Sun.COM 				default:
11437836SJohn.Forte@Sun.COM 					syslog(LOG_ERR,
11447836SJohn.Forte@Sun.COM 					    "unexpected event 0x%x during "
11457836SJohn.Forte@Sun.COM 					    "accept processing (%s)",
11467836SJohn.Forte@Sun.COM 					    event, nconf->nc_proto);
11477836SJohn.Forte@Sun.COM 					call->udata.len = 0;
11487836SJohn.Forte@Sun.COM 					(void) t_snddis(fd, call);
11497836SJohn.Forte@Sun.COM 					(void) t_free((char *)call, T_CALL);
11507836SJohn.Forte@Sun.COM 					(void) t_close(new_fd);
11517836SJohn.Forte@Sun.COM 					goto do_next_conn;
11527836SJohn.Forte@Sun.COM 				}
11537836SJohn.Forte@Sun.COM 			}
11547836SJohn.Forte@Sun.COM 		}
11557836SJohn.Forte@Sun.COM 
11567836SJohn.Forte@Sun.COM 		if (set_addrmask(new_fd, nconf, &addrmask) < 0) {
11577836SJohn.Forte@Sun.COM 			(void) syslog(LOG_ERR, "Cannot set address mask for %s",
11587836SJohn.Forte@Sun.COM 			    nconf->nc_netid);
11597836SJohn.Forte@Sun.COM 			return;
11607836SJohn.Forte@Sun.COM 		}
11617836SJohn.Forte@Sun.COM 
11627836SJohn.Forte@Sun.COM 		/* Tell KRPC about the new stream. */
11637836SJohn.Forte@Sun.COM 		ret = (*Mysvc)(new_fd, addrmask, nconf);
11647836SJohn.Forte@Sun.COM 		if (ret < 0) {
11657836SJohn.Forte@Sun.COM 			syslog(LOG_ERR,
11667836SJohn.Forte@Sun.COM 			    "unable to register with kernel rpc: %m");
11677836SJohn.Forte@Sun.COM 			free(addrmask.buf);
11687836SJohn.Forte@Sun.COM 			(void) t_snddis(new_fd, (struct t_call *)0);
11697836SJohn.Forte@Sun.COM 			(void) t_free((char *)call, T_CALL);
11707836SJohn.Forte@Sun.COM 			(void) t_close(new_fd);
11717836SJohn.Forte@Sun.COM 			goto do_next_conn;
11727836SJohn.Forte@Sun.COM 		}
11737836SJohn.Forte@Sun.COM 
11747836SJohn.Forte@Sun.COM 		free(addrmask.buf);
11757836SJohn.Forte@Sun.COM 		(void) t_free((char *)call, T_CALL);
11767836SJohn.Forte@Sun.COM 
11777836SJohn.Forte@Sun.COM 		/*
11787836SJohn.Forte@Sun.COM 		 * Poll on the new descriptor so that we get disconnect
11797836SJohn.Forte@Sun.COM 		 * and orderly release indications.
11807836SJohn.Forte@Sun.COM 		 */
11817836SJohn.Forte@Sun.COM 		num_conns++;
11827836SJohn.Forte@Sun.COM 		add_to_poll_list(new_fd, nconf);
11837836SJohn.Forte@Sun.COM 
11847836SJohn.Forte@Sun.COM 		/* Reset nconf in case it has been moved. */
11857836SJohn.Forte@Sun.COM 		nconf = &conn_polled[conn_index].nc;
11867836SJohn.Forte@Sun.COM do_next_conn:;
11877836SJohn.Forte@Sun.COM 	}
11887836SJohn.Forte@Sun.COM }
11897836SJohn.Forte@Sun.COM 
11907836SJohn.Forte@Sun.COM static int
do_poll_cots_action(int fd,int conn_index)11917836SJohn.Forte@Sun.COM do_poll_cots_action(int fd, int conn_index)
11927836SJohn.Forte@Sun.COM {
11937836SJohn.Forte@Sun.COM 	char buf[256];
11947836SJohn.Forte@Sun.COM 	int event;
11957836SJohn.Forte@Sun.COM 	int i1;
11967836SJohn.Forte@Sun.COM 	int flags;
11977836SJohn.Forte@Sun.COM 	struct conn_entry *connent = &conn_polled[conn_index];
11987836SJohn.Forte@Sun.COM 	struct netconfig *nconf = &(connent->nc);
11997836SJohn.Forte@Sun.COM 	const char *errorstr;
12007836SJohn.Forte@Sun.COM 
12017836SJohn.Forte@Sun.COM 	while (event = t_look(fd)) {
12027836SJohn.Forte@Sun.COM 		switch (event) {
12037836SJohn.Forte@Sun.COM 		case T_LISTEN:
12047836SJohn.Forte@Sun.COM #ifdef DEBUG
12057836SJohn.Forte@Sun.COM 	(void) printf("do_poll_cots_action(%s, %d): T_LISTEN event\n",
12067836SJohn.Forte@Sun.COM 	    nconf->nc_proto, fd);
12077836SJohn.Forte@Sun.COM #endif
12087836SJohn.Forte@Sun.COM 			cots_listen_event(fd, conn_index);
12097836SJohn.Forte@Sun.COM 			break;
12107836SJohn.Forte@Sun.COM 
12117836SJohn.Forte@Sun.COM 		case T_DATA:
12127836SJohn.Forte@Sun.COM #ifdef DEBUG
12137836SJohn.Forte@Sun.COM 	(void) printf("do_poll_cots_action(%d, %s): T_DATA event\n",
12147836SJohn.Forte@Sun.COM 		fd, nconf->nc_proto);
12157836SJohn.Forte@Sun.COM #endif
12167836SJohn.Forte@Sun.COM 			/*
12177836SJohn.Forte@Sun.COM 			 * Receive a private notification from CONS rpcmod.
12187836SJohn.Forte@Sun.COM 			 */
12197836SJohn.Forte@Sun.COM 			i1 = t_rcv(fd, buf, sizeof (buf), &flags);
12207836SJohn.Forte@Sun.COM 			if (i1 == -1) {
12217836SJohn.Forte@Sun.COM 				syslog(LOG_ERR, "t_rcv failed");
12227836SJohn.Forte@Sun.COM 				break;
12237836SJohn.Forte@Sun.COM 			}
12247836SJohn.Forte@Sun.COM 			if (i1 < sizeof (int))
12257836SJohn.Forte@Sun.COM 				break;
12267836SJohn.Forte@Sun.COM 			i1 = BE32_TO_U32(buf);
12277836SJohn.Forte@Sun.COM 			if (i1 == 1 || i1 == 2) {
12287836SJohn.Forte@Sun.COM 				/*
12297836SJohn.Forte@Sun.COM 				 * This connection has been idle for too long,
12307836SJohn.Forte@Sun.COM 				 * so release it as politely as we can.  If we
12317836SJohn.Forte@Sun.COM 				 * have already initiated an orderly release
12327836SJohn.Forte@Sun.COM 				 * and we get notified that the stream is
12337836SJohn.Forte@Sun.COM 				 * still idle, pull the plug.  This prevents
12347836SJohn.Forte@Sun.COM 				 * hung connections from continuing to consume
12357836SJohn.Forte@Sun.COM 				 * resources.
12367836SJohn.Forte@Sun.COM 				 */
12377836SJohn.Forte@Sun.COM #ifdef DEBUG
12387836SJohn.Forte@Sun.COM (void) printf("do_poll_cots_action(%s, %d): ", nconf->nc_proto, fd);
12397836SJohn.Forte@Sun.COM (void) printf("initiating orderly release of idle connection\n");
12407836SJohn.Forte@Sun.COM #endif
12417836SJohn.Forte@Sun.COM 				if (nconf->nc_semantics == NC_TPI_COTS ||
12427836SJohn.Forte@Sun.COM 				    connent->closing != 0) {
12437836SJohn.Forte@Sun.COM 					(void) t_snddis(fd, (struct t_call *)0);
12447836SJohn.Forte@Sun.COM 					goto fdclose;
12457836SJohn.Forte@Sun.COM 				}
12467836SJohn.Forte@Sun.COM 				/*
12477836SJohn.Forte@Sun.COM 				 * For NC_TPI_COTS_ORD, the stream is closed
12487836SJohn.Forte@Sun.COM 				 * and removed from the poll list when the
12497836SJohn.Forte@Sun.COM 				 * T_ORDREL is received from the provider.  We
12507836SJohn.Forte@Sun.COM 				 * don't wait for it here because it may take
12517836SJohn.Forte@Sun.COM 				 * a while for the transport to shut down.
12527836SJohn.Forte@Sun.COM 				 */
12537836SJohn.Forte@Sun.COM 				if (t_sndrel(fd) == -1) {
12547836SJohn.Forte@Sun.COM 					syslog(LOG_ERR,
12557836SJohn.Forte@Sun.COM 					"unable to send orderly release %m");
12567836SJohn.Forte@Sun.COM 				}
12577836SJohn.Forte@Sun.COM 				connent->closing = 1;
12587836SJohn.Forte@Sun.COM 			} else
12597836SJohn.Forte@Sun.COM 				syslog(LOG_ERR,
12607836SJohn.Forte@Sun.COM 				    "unexpected event from CONS rpcmod %d", i1);
12617836SJohn.Forte@Sun.COM 			break;
12627836SJohn.Forte@Sun.COM 
12637836SJohn.Forte@Sun.COM 		case T_ORDREL:
12647836SJohn.Forte@Sun.COM #ifdef DEBUG
12657836SJohn.Forte@Sun.COM 	(void) printf("do_poll_cots_action(%s, %d): T_ORDREL event\n",
12667836SJohn.Forte@Sun.COM 		nconf->nc_proto, fd);
12677836SJohn.Forte@Sun.COM #endif
12687836SJohn.Forte@Sun.COM 			/* Perform an orderly release. */
12697836SJohn.Forte@Sun.COM 			if (t_rcvrel(fd) == 0) {
12707836SJohn.Forte@Sun.COM 				/* T_ORDREL on listen fd's should be ignored */
12717836SJohn.Forte@Sun.COM 				if (!is_listen_fd_index(fd)) {
12727836SJohn.Forte@Sun.COM 					(void) t_sndrel(fd);
12737836SJohn.Forte@Sun.COM 					goto fdclose;
12747836SJohn.Forte@Sun.COM 				}
12757836SJohn.Forte@Sun.COM 				break;
12767836SJohn.Forte@Sun.COM 
12777836SJohn.Forte@Sun.COM 			} else if (t_errno == TLOOK) {
12787836SJohn.Forte@Sun.COM 				break;
12797836SJohn.Forte@Sun.COM 			} else {
12807836SJohn.Forte@Sun.COM 				rdcd_log_tli_error("t_rcvrel", fd, nconf);
12817836SJohn.Forte@Sun.COM 				/*
12827836SJohn.Forte@Sun.COM 				 * check to make sure we do not close
12837836SJohn.Forte@Sun.COM 				 * listen fd
12847836SJohn.Forte@Sun.COM 				 */
12857836SJohn.Forte@Sun.COM 				if (!is_listen_fd_index(fd))
12867836SJohn.Forte@Sun.COM 					break;
12877836SJohn.Forte@Sun.COM 				else
12887836SJohn.Forte@Sun.COM 					goto fdclose;
12897836SJohn.Forte@Sun.COM 			}
12907836SJohn.Forte@Sun.COM 
12917836SJohn.Forte@Sun.COM 		case T_DISCONNECT:
12927836SJohn.Forte@Sun.COM #ifdef DEBUG
12937836SJohn.Forte@Sun.COM (void) printf("do_poll_cots_action(%s, %d): T_DISCONNECT event\n",
12947836SJohn.Forte@Sun.COM nconf->nc_proto, fd);
12957836SJohn.Forte@Sun.COM #endif
12967836SJohn.Forte@Sun.COM 			if (t_rcvdis(fd, (struct t_discon *)NULL) == -1)
12977836SJohn.Forte@Sun.COM 				rdcd_log_tli_error("t_rcvdis", fd, nconf);
12987836SJohn.Forte@Sun.COM 
12997836SJohn.Forte@Sun.COM 			/*
13007836SJohn.Forte@Sun.COM 			 * T_DISCONNECT on listen fd's should be ignored.
13017836SJohn.Forte@Sun.COM 			 */
13027836SJohn.Forte@Sun.COM 			if (!is_listen_fd_index(fd))
13037836SJohn.Forte@Sun.COM 				break;
13047836SJohn.Forte@Sun.COM 			else
13057836SJohn.Forte@Sun.COM 				goto fdclose;
13067836SJohn.Forte@Sun.COM 
13077836SJohn.Forte@Sun.COM 		case T_ERROR:
13087836SJohn.Forte@Sun.COM 		default:
13097836SJohn.Forte@Sun.COM 			if (event == T_ERROR || t_errno == TSYSERR) {
13107836SJohn.Forte@Sun.COM 			    if ((errorstr = strerror(errno)) == NULL) {
13117836SJohn.Forte@Sun.COM 				(void) snprintf(buf, sizeof (buf),
13127836SJohn.Forte@Sun.COM 				    "Unknown error num %d", errno);
13137836SJohn.Forte@Sun.COM 				errorstr = (const char *)buf;
13147836SJohn.Forte@Sun.COM 			    }
13157836SJohn.Forte@Sun.COM 			} else if (event == -1)
13167836SJohn.Forte@Sun.COM 				errorstr = t_strerror(t_errno);
13177836SJohn.Forte@Sun.COM 			else
13187836SJohn.Forte@Sun.COM 				errorstr = "";
13197836SJohn.Forte@Sun.COM #ifdef DEBUG
13207836SJohn.Forte@Sun.COM 			syslog(LOG_ERR,
13217836SJohn.Forte@Sun.COM 			    "unexpected TLI event (0x%x) on "
13227836SJohn.Forte@Sun.COM 			    "connection-oriented transport(%s, %d):%s",
13237836SJohn.Forte@Sun.COM 			    event, nconf->nc_proto, fd, errorstr);
13247836SJohn.Forte@Sun.COM #endif
13257836SJohn.Forte@Sun.COM 
13267836SJohn.Forte@Sun.COM fdclose:
13277836SJohn.Forte@Sun.COM 			num_conns--;
13287836SJohn.Forte@Sun.COM 			remove_from_poll_list(fd);
13297836SJohn.Forte@Sun.COM 			(void) t_close(fd);
13307836SJohn.Forte@Sun.COM 			return (0);
13317836SJohn.Forte@Sun.COM 		}
13327836SJohn.Forte@Sun.COM 	}
13337836SJohn.Forte@Sun.COM 
13347836SJohn.Forte@Sun.COM 	return (0);
13357836SJohn.Forte@Sun.COM }
13367836SJohn.Forte@Sun.COM 
13377836SJohn.Forte@Sun.COM 
13387836SJohn.Forte@Sun.COM /*
13397836SJohn.Forte@Sun.COM  * Called to read and interpret the event on a connectionless descriptor.
13407836SJohn.Forte@Sun.COM  * Returns 0 if successful, or a UNIX error code if failure.
13417836SJohn.Forte@Sun.COM  */
13427836SJohn.Forte@Sun.COM static int
do_poll_clts_action(int fd,int conn_index)13437836SJohn.Forte@Sun.COM do_poll_clts_action(int fd, int conn_index)
13447836SJohn.Forte@Sun.COM {
13457836SJohn.Forte@Sun.COM 	int error;
13467836SJohn.Forte@Sun.COM 	int ret;
13477836SJohn.Forte@Sun.COM 	int flags;
13487836SJohn.Forte@Sun.COM 	struct netconfig *nconf = &conn_polled[conn_index].nc;
13497836SJohn.Forte@Sun.COM 	static struct t_unitdata *unitdata = NULL;
13507836SJohn.Forte@Sun.COM 	static struct t_uderr *uderr = NULL;
13517836SJohn.Forte@Sun.COM 	static int oldfd = -1;
13527836SJohn.Forte@Sun.COM 	struct nd_hostservlist *host = NULL;
13537836SJohn.Forte@Sun.COM 	struct strbuf ctl[1], data[1];
13547836SJohn.Forte@Sun.COM 	/*
13557836SJohn.Forte@Sun.COM 	 * We just need to have some space to consume the
13567836SJohn.Forte@Sun.COM 	 * message in the event we can't use the TLI interface to do the
13577836SJohn.Forte@Sun.COM 	 * job.
13587836SJohn.Forte@Sun.COM 	 *
13597836SJohn.Forte@Sun.COM 	 * We flush the message using getmsg(). For the control part
13607836SJohn.Forte@Sun.COM 	 * we allocate enough for any TPI header plus 32 bytes for address
13617836SJohn.Forte@Sun.COM 	 * and options. For the data part, there is nothing magic about
13627836SJohn.Forte@Sun.COM 	 * the size of the array, but 256 bytes is probably better than
13637836SJohn.Forte@Sun.COM 	 * 1 byte, and we don't expect any data portion anyway.
13647836SJohn.Forte@Sun.COM 	 *
13657836SJohn.Forte@Sun.COM 	 * If the array sizes are too small, we handle this because getmsg()
13667836SJohn.Forte@Sun.COM 	 * (called to consume the message) will return MOREDATA|MORECTL.
13677836SJohn.Forte@Sun.COM 	 * Thus we just call getmsg() until it's read the message.
13687836SJohn.Forte@Sun.COM 	 */
13697836SJohn.Forte@Sun.COM 	char ctlbuf[sizeof (union T_primitives) + 32];
13707836SJohn.Forte@Sun.COM 	char databuf[256];
13717836SJohn.Forte@Sun.COM 
13727836SJohn.Forte@Sun.COM 	/*
13737836SJohn.Forte@Sun.COM 	 * If this is the same descriptor as the last time
13747836SJohn.Forte@Sun.COM 	 * do_poll_clts_action was called, we can save some
13757836SJohn.Forte@Sun.COM 	 * de-allocation and allocation.
13767836SJohn.Forte@Sun.COM 	 */
13777836SJohn.Forte@Sun.COM 	if (oldfd != fd) {
13787836SJohn.Forte@Sun.COM 		oldfd = fd;
13797836SJohn.Forte@Sun.COM 
13807836SJohn.Forte@Sun.COM 		if (unitdata) {
13817836SJohn.Forte@Sun.COM 			(void) t_free((char *)unitdata, T_UNITDATA);
13827836SJohn.Forte@Sun.COM 			unitdata = NULL;
13837836SJohn.Forte@Sun.COM 		}
13847836SJohn.Forte@Sun.COM 		if (uderr) {
13857836SJohn.Forte@Sun.COM 			(void) t_free((char *)uderr, T_UDERROR);
13867836SJohn.Forte@Sun.COM 			uderr = NULL;
13877836SJohn.Forte@Sun.COM 		}
13887836SJohn.Forte@Sun.COM 	}
13897836SJohn.Forte@Sun.COM 
13907836SJohn.Forte@Sun.COM 	/*
13917836SJohn.Forte@Sun.COM 	 * Allocate a unitdata structure for receiving the event.
13927836SJohn.Forte@Sun.COM 	 */
13937836SJohn.Forte@Sun.COM 	if (unitdata == NULL) {
13947836SJohn.Forte@Sun.COM 		/* LINTED pointer alignment */
13957836SJohn.Forte@Sun.COM 		unitdata = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ALL);
13967836SJohn.Forte@Sun.COM 		if (unitdata == NULL) {
13977836SJohn.Forte@Sun.COM 			if (t_errno == TSYSERR) {
13987836SJohn.Forte@Sun.COM 				/*
13997836SJohn.Forte@Sun.COM 				 * Save the error code across
14007836SJohn.Forte@Sun.COM 				 * syslog(), just in case
14017836SJohn.Forte@Sun.COM 				 * syslog() gets its own error
14027836SJohn.Forte@Sun.COM 				 * and therefore overwrites errno.
14037836SJohn.Forte@Sun.COM 				 */
14047836SJohn.Forte@Sun.COM 				error = errno;
14057836SJohn.Forte@Sun.COM 				(void) syslog(LOG_ERR,
14067836SJohn.Forte@Sun.COM 	"t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed: %m",
14077836SJohn.Forte@Sun.COM 					fd, nconf->nc_proto);
14087836SJohn.Forte@Sun.COM 				return (error);
14097836SJohn.Forte@Sun.COM 			}
14107836SJohn.Forte@Sun.COM 			(void) syslog(LOG_ERR,
14117836SJohn.Forte@Sun.COM "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed TLI error %d",
14127836SJohn.Forte@Sun.COM 					fd, nconf->nc_proto, t_errno);
14137836SJohn.Forte@Sun.COM 			goto flush_it;
14147836SJohn.Forte@Sun.COM 		}
14157836SJohn.Forte@Sun.COM 	}
14167836SJohn.Forte@Sun.COM 
14177836SJohn.Forte@Sun.COM try_again:
14187836SJohn.Forte@Sun.COM 	flags = 0;
14197836SJohn.Forte@Sun.COM 
14207836SJohn.Forte@Sun.COM 	/*
14217836SJohn.Forte@Sun.COM 	 * The idea is we wait for T_UNITDATA_IND's. Of course,
14227836SJohn.Forte@Sun.COM 	 * we don't get any, because rpcmod filters them out.
14237836SJohn.Forte@Sun.COM 	 * However, we need to call t_rcvudata() to let TLI
14247836SJohn.Forte@Sun.COM 	 * tell us we have a T_UDERROR_IND.
14257836SJohn.Forte@Sun.COM 	 *
14267836SJohn.Forte@Sun.COM 	 * algorithm is:
14277836SJohn.Forte@Sun.COM 	 * 	t_rcvudata(), expecting TLOOK.
14287836SJohn.Forte@Sun.COM 	 * 	t_look(), expecting T_UDERR.
14297836SJohn.Forte@Sun.COM 	 * 	t_rcvuderr(), expecting success (0).
14307836SJohn.Forte@Sun.COM 	 * 	expand destination address into ASCII,
14317836SJohn.Forte@Sun.COM 	 *	and dump it.
14327836SJohn.Forte@Sun.COM 	 */
14337836SJohn.Forte@Sun.COM 
14347836SJohn.Forte@Sun.COM 	ret = t_rcvudata(fd, unitdata, &flags);
14357836SJohn.Forte@Sun.COM 	if (ret == 0 || t_errno == TBUFOVFLW) {
14367836SJohn.Forte@Sun.COM 		(void) syslog(LOG_WARNING,
14377836SJohn.Forte@Sun.COM "t_rcvudata(file descriptor %d/transport %s) got unexpected data, %d bytes",
14387836SJohn.Forte@Sun.COM 			fd, nconf->nc_proto, unitdata->udata.len);
14397836SJohn.Forte@Sun.COM 
14407836SJohn.Forte@Sun.COM 		/*
14417836SJohn.Forte@Sun.COM 		 * Even though we don't expect any data, in case we do,
14427836SJohn.Forte@Sun.COM 		 * keep reading until there is no more.
14437836SJohn.Forte@Sun.COM 		 */
14447836SJohn.Forte@Sun.COM 		if (flags & T_MORE)
14457836SJohn.Forte@Sun.COM 			goto try_again;
14467836SJohn.Forte@Sun.COM 
14477836SJohn.Forte@Sun.COM 		return (0);
14487836SJohn.Forte@Sun.COM 	}
14497836SJohn.Forte@Sun.COM 
14507836SJohn.Forte@Sun.COM 	switch (t_errno) {
14517836SJohn.Forte@Sun.COM 	case TNODATA:
14527836SJohn.Forte@Sun.COM 		return (0);
14537836SJohn.Forte@Sun.COM 	case TSYSERR:
14547836SJohn.Forte@Sun.COM 		/*
14557836SJohn.Forte@Sun.COM 		 * System errors are returned to caller.
14567836SJohn.Forte@Sun.COM 		 * Save the error code across
14577836SJohn.Forte@Sun.COM 		 * syslog(), just in case
14587836SJohn.Forte@Sun.COM 		 * syslog() gets its own error
14597836SJohn.Forte@Sun.COM 		 * and therefore overwrites errno.
14607836SJohn.Forte@Sun.COM 		 */
14617836SJohn.Forte@Sun.COM 		error = errno;
14627836SJohn.Forte@Sun.COM 		(void) syslog(LOG_ERR,
14637836SJohn.Forte@Sun.COM 			"t_rcvudata(file descriptor %d/transport %s) %m",
14647836SJohn.Forte@Sun.COM 			fd, nconf->nc_proto);
14657836SJohn.Forte@Sun.COM 		return (error);
14667836SJohn.Forte@Sun.COM 	case TLOOK:
14677836SJohn.Forte@Sun.COM 		break;
14687836SJohn.Forte@Sun.COM 	default:
14697836SJohn.Forte@Sun.COM 		(void) syslog(LOG_ERR,
14707836SJohn.Forte@Sun.COM 		"t_rcvudata(file descriptor %d/transport %s) TLI error %d",
14717836SJohn.Forte@Sun.COM 			fd, nconf->nc_proto, t_errno);
14727836SJohn.Forte@Sun.COM 		goto flush_it;
14737836SJohn.Forte@Sun.COM 	}
14747836SJohn.Forte@Sun.COM 
14757836SJohn.Forte@Sun.COM 	ret = t_look(fd);
14767836SJohn.Forte@Sun.COM 	switch (ret) {
14777836SJohn.Forte@Sun.COM 	case 0:
14787836SJohn.Forte@Sun.COM 		return (0);
14797836SJohn.Forte@Sun.COM 	case -1:
14807836SJohn.Forte@Sun.COM 		/*
14817836SJohn.Forte@Sun.COM 		 * System errors are returned to caller.
14827836SJohn.Forte@Sun.COM 		 */
14837836SJohn.Forte@Sun.COM 		if (t_errno == TSYSERR) {
14847836SJohn.Forte@Sun.COM 			/*
14857836SJohn.Forte@Sun.COM 			 * Save the error code across
14867836SJohn.Forte@Sun.COM 			 * syslog(), just in case
14877836SJohn.Forte@Sun.COM 			 * syslog() gets its own error
14887836SJohn.Forte@Sun.COM 			 * and therefore overwrites errno.
14897836SJohn.Forte@Sun.COM 			 */
14907836SJohn.Forte@Sun.COM 			error = errno;
14917836SJohn.Forte@Sun.COM 			(void) syslog(LOG_ERR,
14927836SJohn.Forte@Sun.COM 				"t_look(file descriptor %d/transport %s) %m",
14937836SJohn.Forte@Sun.COM 				fd, nconf->nc_proto);
14947836SJohn.Forte@Sun.COM 			return (error);
14957836SJohn.Forte@Sun.COM 		}
14967836SJohn.Forte@Sun.COM 		(void) syslog(LOG_ERR,
14977836SJohn.Forte@Sun.COM 			"t_look(file descriptor %d/transport %s) TLI error %d",
14987836SJohn.Forte@Sun.COM 			fd, nconf->nc_proto, t_errno);
14997836SJohn.Forte@Sun.COM 		goto flush_it;
15007836SJohn.Forte@Sun.COM 	case T_UDERR:
15017836SJohn.Forte@Sun.COM 		break;
15027836SJohn.Forte@Sun.COM 	default:
15037836SJohn.Forte@Sun.COM 		(void) syslog(LOG_WARNING,
15047836SJohn.Forte@Sun.COM 	"t_look(file descriptor %d/transport %s) returned %d not T_UDERR (%d)",
15057836SJohn.Forte@Sun.COM 			fd, nconf->nc_proto, ret, T_UDERR);
15067836SJohn.Forte@Sun.COM 	}
15077836SJohn.Forte@Sun.COM 
15087836SJohn.Forte@Sun.COM 	if (uderr == NULL) {
15097836SJohn.Forte@Sun.COM 		/* LINTED pointer alignment */
15107836SJohn.Forte@Sun.COM 		uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL);
15117836SJohn.Forte@Sun.COM 		if (uderr == NULL) {
15127836SJohn.Forte@Sun.COM 			if (t_errno == TSYSERR) {
15137836SJohn.Forte@Sun.COM 				/*
15147836SJohn.Forte@Sun.COM 				 * Save the error code across
15157836SJohn.Forte@Sun.COM 				 * syslog(), just in case
15167836SJohn.Forte@Sun.COM 				 * syslog() gets its own error
15177836SJohn.Forte@Sun.COM 				 * and therefore overwrites errno.
15187836SJohn.Forte@Sun.COM 				 */
15197836SJohn.Forte@Sun.COM 				error = errno;
15207836SJohn.Forte@Sun.COM 				(void) syslog(LOG_ERR,
15217836SJohn.Forte@Sun.COM 	"t_alloc(file descriptor %d/transport %s, T_UDERROR) failed: %m",
15227836SJohn.Forte@Sun.COM 					fd, nconf->nc_proto);
15237836SJohn.Forte@Sun.COM 				return (error);
15247836SJohn.Forte@Sun.COM 			}
15257836SJohn.Forte@Sun.COM 			(void) syslog(LOG_ERR,
15267836SJohn.Forte@Sun.COM "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed TLI error: %d",
15277836SJohn.Forte@Sun.COM 				fd, nconf->nc_proto, t_errno);
15287836SJohn.Forte@Sun.COM 			goto flush_it;
15297836SJohn.Forte@Sun.COM 		}
15307836SJohn.Forte@Sun.COM 	}
15317836SJohn.Forte@Sun.COM 
15327836SJohn.Forte@Sun.COM 	ret = t_rcvuderr(fd, uderr);
15337836SJohn.Forte@Sun.COM 	if (ret == 0) {
15347836SJohn.Forte@Sun.COM 
15357836SJohn.Forte@Sun.COM 		/*
15367836SJohn.Forte@Sun.COM 		 * Save the datagram error in errno, so that the
15377836SJohn.Forte@Sun.COM 		 * %m argument to syslog picks up the error string.
15387836SJohn.Forte@Sun.COM 		 */
15397836SJohn.Forte@Sun.COM 		errno = uderr->error;
15407836SJohn.Forte@Sun.COM 
15417836SJohn.Forte@Sun.COM 		/*
15427836SJohn.Forte@Sun.COM 		 * Log the datagram error, then log the host that
15437836SJohn.Forte@Sun.COM 		 * probably triggerred. Cannot log both in the
15447836SJohn.Forte@Sun.COM 		 * same transaction because of packet size limitations
15457836SJohn.Forte@Sun.COM 		 * in /dev/log.
15467836SJohn.Forte@Sun.COM 		 */
15477836SJohn.Forte@Sun.COM 		(void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
15487836SJohn.Forte@Sun.COM 		    "%s response over <file descriptor %d/transport %s> "
15497836SJohn.Forte@Sun.COM 		    "generated error: %m",
15507836SJohn.Forte@Sun.COM 		    progname, fd, nconf->nc_proto);
15517836SJohn.Forte@Sun.COM 
15527836SJohn.Forte@Sun.COM 		/*
15537836SJohn.Forte@Sun.COM 		 * Try to map the client's address back to a
15547836SJohn.Forte@Sun.COM 		 * name.
15557836SJohn.Forte@Sun.COM 		 */
15567836SJohn.Forte@Sun.COM 		ret = netdir_getbyaddr(nconf, &host, &uderr->addr);
15577836SJohn.Forte@Sun.COM 		if (ret != -1 && host && host->h_cnt > 0 &&
15587836SJohn.Forte@Sun.COM 		    host->h_hostservs) {
15597836SJohn.Forte@Sun.COM 		(void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
15607836SJohn.Forte@Sun.COM 		    "Bad %s response was sent to client with "
15617836SJohn.Forte@Sun.COM 		    "host name: %s; service port: %s",
15627836SJohn.Forte@Sun.COM 		    progname, host->h_hostservs->h_host,
15637836SJohn.Forte@Sun.COM 		    host->h_hostservs->h_serv);
15647836SJohn.Forte@Sun.COM 		} else {
15657836SJohn.Forte@Sun.COM 			int i, j;
15667836SJohn.Forte@Sun.COM 			char *buf;
15677836SJohn.Forte@Sun.COM 			char *hex = "0123456789abcdef";
15687836SJohn.Forte@Sun.COM 
15697836SJohn.Forte@Sun.COM 			/*
15707836SJohn.Forte@Sun.COM 			 * Mapping failed, print the whole thing
15717836SJohn.Forte@Sun.COM 			 * in ASCII hex.
15727836SJohn.Forte@Sun.COM 			 */
15737836SJohn.Forte@Sun.COM 			buf = (char *)malloc(uderr->addr.len * 2 + 1);
15747836SJohn.Forte@Sun.COM 			for (i = 0, j = 0; i < uderr->addr.len; i++, j += 2) {
15757836SJohn.Forte@Sun.COM 				buf[j] = hex[((uderr->addr.buf[i]) >> 4) & 0xf];
15767836SJohn.Forte@Sun.COM 				buf[j+1] = hex[uderr->addr.buf[i] & 0xf];
15777836SJohn.Forte@Sun.COM 			}
15787836SJohn.Forte@Sun.COM 			buf[j] = '\0';
15797836SJohn.Forte@Sun.COM 			(void) syslog((errno == ECONNREFUSED) ?
15807836SJohn.Forte@Sun.COM 			    LOG_DEBUG : LOG_WARNING,
15817836SJohn.Forte@Sun.COM 			    "Bad %s response was sent to client with "
15827836SJohn.Forte@Sun.COM 			    "transport address: 0x%s",
15837836SJohn.Forte@Sun.COM 			    progname, buf);
15847836SJohn.Forte@Sun.COM 			free((void *)buf);
15857836SJohn.Forte@Sun.COM 		}
15867836SJohn.Forte@Sun.COM 
15877836SJohn.Forte@Sun.COM 		if (ret == 0 && host != NULL)
15887836SJohn.Forte@Sun.COM 			netdir_free((void *)host, ND_HOSTSERVLIST);
15897836SJohn.Forte@Sun.COM 		return (0);
15907836SJohn.Forte@Sun.COM 	}
15917836SJohn.Forte@Sun.COM 
15927836SJohn.Forte@Sun.COM 	switch (t_errno) {
15937836SJohn.Forte@Sun.COM 	case TNOUDERR:
15947836SJohn.Forte@Sun.COM 		goto flush_it;
15957836SJohn.Forte@Sun.COM 	case TSYSERR:
15967836SJohn.Forte@Sun.COM 		/*
15977836SJohn.Forte@Sun.COM 		 * System errors are returned to caller.
15987836SJohn.Forte@Sun.COM 		 * Save the error code across
15997836SJohn.Forte@Sun.COM 		 * syslog(), just in case
16007836SJohn.Forte@Sun.COM 		 * syslog() gets its own error
16017836SJohn.Forte@Sun.COM 		 * and therefore overwrites errno.
16027836SJohn.Forte@Sun.COM 		 */
16037836SJohn.Forte@Sun.COM 		error = errno;
16047836SJohn.Forte@Sun.COM 		(void) syslog(LOG_ERR,
16057836SJohn.Forte@Sun.COM 			"t_rcvuderr(file descriptor %d/transport %s) %m",
16067836SJohn.Forte@Sun.COM 			fd, nconf->nc_proto);
16077836SJohn.Forte@Sun.COM 		return (error);
16087836SJohn.Forte@Sun.COM 	default:
16097836SJohn.Forte@Sun.COM 		(void) syslog(LOG_ERR,
16107836SJohn.Forte@Sun.COM 		"t_rcvuderr(file descriptor %d/transport %s) TLI error %d",
16117836SJohn.Forte@Sun.COM 			fd, nconf->nc_proto, t_errno);
16127836SJohn.Forte@Sun.COM 		goto flush_it;
16137836SJohn.Forte@Sun.COM 	}
16147836SJohn.Forte@Sun.COM 
16157836SJohn.Forte@Sun.COM flush_it:
16167836SJohn.Forte@Sun.COM 	/*
16177836SJohn.Forte@Sun.COM 	 * If we get here, then we could not cope with whatever message
16187836SJohn.Forte@Sun.COM 	 * we attempted to read, so flush it. If we did read a message,
16197836SJohn.Forte@Sun.COM 	 * and one isn't present, that is all right, because fd is in
16207836SJohn.Forte@Sun.COM 	 * nonblocking mode.
16217836SJohn.Forte@Sun.COM 	 */
16227836SJohn.Forte@Sun.COM 	(void) syslog(LOG_ERR,
16237836SJohn.Forte@Sun.COM 	"Flushing one input message from <file descriptor %d/transport %s>",
16247836SJohn.Forte@Sun.COM 		fd, nconf->nc_proto);
16257836SJohn.Forte@Sun.COM 
16267836SJohn.Forte@Sun.COM 	/*
16277836SJohn.Forte@Sun.COM 	 * Read and discard the message. Do this this until there is
16287836SJohn.Forte@Sun.COM 	 * no more control/data in the message or until we get an error.
16297836SJohn.Forte@Sun.COM 	 */
16307836SJohn.Forte@Sun.COM 	do {
16317836SJohn.Forte@Sun.COM 		ctl->maxlen = sizeof (ctlbuf);
16327836SJohn.Forte@Sun.COM 		ctl->buf = ctlbuf;
16337836SJohn.Forte@Sun.COM 		data->maxlen = sizeof (databuf);
16347836SJohn.Forte@Sun.COM 		data->buf = databuf;
16357836SJohn.Forte@Sun.COM 		flags = 0;
16367836SJohn.Forte@Sun.COM 		ret = getmsg(fd, ctl, data, &flags);
16377836SJohn.Forte@Sun.COM 		if (ret == -1)
16387836SJohn.Forte@Sun.COM 			return (errno);
16397836SJohn.Forte@Sun.COM 	} while (ret != 0);
16407836SJohn.Forte@Sun.COM 
16417836SJohn.Forte@Sun.COM 	return (0);
16427836SJohn.Forte@Sun.COM }
16437836SJohn.Forte@Sun.COM 
16447836SJohn.Forte@Sun.COM /*
16457836SJohn.Forte@Sun.COM  * Establish service thread.
16467836SJohn.Forte@Sun.COM  */
16477836SJohn.Forte@Sun.COM static int
rdcsvc(int fd,struct netbuf addrmask,struct netconfig * nconf)16487836SJohn.Forte@Sun.COM rdcsvc(int fd, struct netbuf addrmask, struct netconfig *nconf)
16497836SJohn.Forte@Sun.COM {
16507836SJohn.Forte@Sun.COM #ifdef	__NCALL__
16517836SJohn.Forte@Sun.COM 	struct ncall_svc_args nsa;
16527836SJohn.Forte@Sun.COM #else	/* !__NCALL__ */
16537836SJohn.Forte@Sun.COM 	struct rdc_svc_args nsa;
16547836SJohn.Forte@Sun.COM 	_rdc_ioctl_t rdc_args = { 0, };
16557836SJohn.Forte@Sun.COM #endif	/* __NCALL__ */
16567836SJohn.Forte@Sun.COM 
16577836SJohn.Forte@Sun.COM 	nsa.fd = fd;
16587836SJohn.Forte@Sun.COM 	nsa.nthr = (max_conns_allowed < 0 ? 16 : max_conns_allowed);
1659*11576SSurya.Prakki@Sun.COM 	(void) strncpy(nsa.netid, nconf->nc_netid, sizeof (nsa.netid));
16607836SJohn.Forte@Sun.COM 	nsa.addrmask.len = addrmask.len;
16617836SJohn.Forte@Sun.COM 	nsa.addrmask.maxlen = addrmask.maxlen;
16627836SJohn.Forte@Sun.COM 	nsa.addrmask.buf = addrmask.buf;
16637836SJohn.Forte@Sun.COM 
16647836SJohn.Forte@Sun.COM #ifdef	__NCALL__
16657836SJohn.Forte@Sun.COM 	return (sndrsys(NC_IOC_SERVER, &nsa));
16667836SJohn.Forte@Sun.COM #else	/* !__NCALL__ */
16677836SJohn.Forte@Sun.COM 	rdc_args.arg0 = (long)&nsa;
16687836SJohn.Forte@Sun.COM 	return (sndrsys(RDC_ENABLE_SVR, &rdc_args));
16697836SJohn.Forte@Sun.COM #endif	/* __NCALL__ */
16707836SJohn.Forte@Sun.COM }
16717836SJohn.Forte@Sun.COM 
16727836SJohn.Forte@Sun.COM 
16737836SJohn.Forte@Sun.COM 
16747836SJohn.Forte@Sun.COM static int
nofile_increase(int limit)16757836SJohn.Forte@Sun.COM nofile_increase(int limit)
16767836SJohn.Forte@Sun.COM {
16777836SJohn.Forte@Sun.COM 	struct rlimit rl;
16787836SJohn.Forte@Sun.COM 
16797836SJohn.Forte@Sun.COM 	if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
16807836SJohn.Forte@Sun.COM 		syslog(LOG_ERR,
16817836SJohn.Forte@Sun.COM 		    "nofile_increase() getrlimit of NOFILE failed: %m");
16827836SJohn.Forte@Sun.COM 		return (-1);
16837836SJohn.Forte@Sun.COM 	}
16847836SJohn.Forte@Sun.COM 
16857836SJohn.Forte@Sun.COM 	if (limit > 0)
16867836SJohn.Forte@Sun.COM 		rl.rlim_cur = limit;
16877836SJohn.Forte@Sun.COM 	else
16887836SJohn.Forte@Sun.COM 		rl.rlim_cur += NOFILE_INC_SIZE;
16897836SJohn.Forte@Sun.COM 
16907836SJohn.Forte@Sun.COM 	if (rl.rlim_cur > rl.rlim_max && rl.rlim_max != RLIM_INFINITY)
16917836SJohn.Forte@Sun.COM 		rl.rlim_max = rl.rlim_cur;
16927836SJohn.Forte@Sun.COM 
16937836SJohn.Forte@Sun.COM 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
16947836SJohn.Forte@Sun.COM 		syslog(LOG_ERR,
16957836SJohn.Forte@Sun.COM 		    "nofile_increase() setrlimit of NOFILE to %d failed: %m",
16967836SJohn.Forte@Sun.COM 		    rl.rlim_cur);
16977836SJohn.Forte@Sun.COM 		return (-1);
16987836SJohn.Forte@Sun.COM 	}
16997836SJohn.Forte@Sun.COM 
17007836SJohn.Forte@Sun.COM 	return (0);
17017836SJohn.Forte@Sun.COM }
17027836SJohn.Forte@Sun.COM 
17037836SJohn.Forte@Sun.COM int
rdcd_bindit(struct netconfig * nconf,struct netbuf ** addr,struct nd_hostserv * hs,int backlog)17047836SJohn.Forte@Sun.COM rdcd_bindit(struct netconfig *nconf, struct netbuf **addr,
17057836SJohn.Forte@Sun.COM     struct nd_hostserv *hs, int backlog)
17067836SJohn.Forte@Sun.COM {
17077836SJohn.Forte@Sun.COM 	int fd;
17087836SJohn.Forte@Sun.COM 	struct t_bind *ntb;
17097836SJohn.Forte@Sun.COM 	struct t_bind tb;
17107836SJohn.Forte@Sun.COM 	struct nd_addrlist *addrlist;
17117836SJohn.Forte@Sun.COM 	struct t_optmgmt req, resp;
17127836SJohn.Forte@Sun.COM 	struct opthdr *opt;
17137836SJohn.Forte@Sun.COM 	char reqbuf[128];
17147836SJohn.Forte@Sun.COM 
17157836SJohn.Forte@Sun.COM 	if ((fd = rdc_transport_open(nconf)) == -1) {
17167836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "cannot establish transport service over %s",
17177836SJohn.Forte@Sun.COM 		    nconf->nc_device);
17187836SJohn.Forte@Sun.COM 		return (-1);
17197836SJohn.Forte@Sun.COM 	}
17207836SJohn.Forte@Sun.COM 
17217836SJohn.Forte@Sun.COM 	addrlist = (struct nd_addrlist *)NULL;
17227836SJohn.Forte@Sun.COM 	if (netdir_getbyname(nconf, hs, &addrlist) != 0) {
17237836SJohn.Forte@Sun.COM 		if (strncmp(nconf->nc_netid, "udp", 3) != 0) {
17247836SJohn.Forte@Sun.COM 			syslog(LOG_ERR, "Cannot get address for transport "
17257836SJohn.Forte@Sun.COM 			    "%s host %s service %s",
17267836SJohn.Forte@Sun.COM 			    nconf->nc_netid, hs->h_host, hs->h_serv);
17277836SJohn.Forte@Sun.COM 		}
17287836SJohn.Forte@Sun.COM 		(void) t_close(fd);
17297836SJohn.Forte@Sun.COM 		return (-1);
17307836SJohn.Forte@Sun.COM 	}
17317836SJohn.Forte@Sun.COM 
17327836SJohn.Forte@Sun.COM 	if (strcmp(nconf->nc_proto, "tcp") == 0) {
17337836SJohn.Forte@Sun.COM 		/*
17347836SJohn.Forte@Sun.COM 		 * If we're running over TCP, then set the
17357836SJohn.Forte@Sun.COM 		 * SO_REUSEADDR option so that we can bind
17367836SJohn.Forte@Sun.COM 		 * to our preferred address even if previously
17377836SJohn.Forte@Sun.COM 		 * left connections exist in FIN_WAIT states.
17387836SJohn.Forte@Sun.COM 		 * This is somewhat bogus, but otherwise you have
17397836SJohn.Forte@Sun.COM 		 * to wait 2 minutes to restart after killing it.
17407836SJohn.Forte@Sun.COM 		 */
17417836SJohn.Forte@Sun.COM 		if (reuseaddr(fd) == -1) {
17427836SJohn.Forte@Sun.COM 			syslog(LOG_WARNING,
17437836SJohn.Forte@Sun.COM 			    "couldn't set SO_REUSEADDR option on transport");
17447836SJohn.Forte@Sun.COM 		}
17457836SJohn.Forte@Sun.COM 	}
17467836SJohn.Forte@Sun.COM 
17477836SJohn.Forte@Sun.COM 	if (nconf->nc_semantics == NC_TPI_CLTS)
17487836SJohn.Forte@Sun.COM 		tb.qlen = 0;
17497836SJohn.Forte@Sun.COM 	else
17507836SJohn.Forte@Sun.COM 		tb.qlen = backlog;
17517836SJohn.Forte@Sun.COM 
17527836SJohn.Forte@Sun.COM 	/* LINTED pointer alignment */
17537836SJohn.Forte@Sun.COM 	ntb = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL);
17547836SJohn.Forte@Sun.COM 	if (ntb == (struct t_bind *)NULL) {
17557836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "t_alloc failed:  t_errno %d, %m", t_errno);
17567836SJohn.Forte@Sun.COM 		(void) t_close(fd);
17577836SJohn.Forte@Sun.COM 		netdir_free((void *)addrlist, ND_ADDRLIST);
17587836SJohn.Forte@Sun.COM 		return (-1);
17597836SJohn.Forte@Sun.COM 	}
17607836SJohn.Forte@Sun.COM 
17617836SJohn.Forte@Sun.COM 	tb.addr = *(addrlist->n_addrs);		/* structure copy */
17627836SJohn.Forte@Sun.COM 
17637836SJohn.Forte@Sun.COM 	if (t_bind(fd, &tb, ntb) == -1) {
17647836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "t_bind failed:  t_errno %d, %m", t_errno);
17657836SJohn.Forte@Sun.COM 		(void) t_free((char *)ntb, T_BIND);
17667836SJohn.Forte@Sun.COM 		netdir_free((void *)addrlist, ND_ADDRLIST);
17677836SJohn.Forte@Sun.COM 		(void) t_close(fd);
17687836SJohn.Forte@Sun.COM 		return (-1);
17697836SJohn.Forte@Sun.COM 	}
17707836SJohn.Forte@Sun.COM 
17717836SJohn.Forte@Sun.COM 	/* make sure we bound to the right address */
17727836SJohn.Forte@Sun.COM 	if (tb.addr.len != ntb->addr.len ||
17737836SJohn.Forte@Sun.COM 	    memcmp(tb.addr.buf, ntb->addr.buf, tb.addr.len) != 0) {
17747836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "t_bind to wrong address");
17757836SJohn.Forte@Sun.COM 		(void) t_free((char *)ntb, T_BIND);
17767836SJohn.Forte@Sun.COM 		netdir_free((void *)addrlist, ND_ADDRLIST);
17777836SJohn.Forte@Sun.COM 		(void) t_close(fd);
17787836SJohn.Forte@Sun.COM 		return (-1);
17797836SJohn.Forte@Sun.COM 	}
17807836SJohn.Forte@Sun.COM 
17817836SJohn.Forte@Sun.COM 	*addr = &ntb->addr;
17827836SJohn.Forte@Sun.COM 	netdir_free((void *)addrlist, ND_ADDRLIST);
17837836SJohn.Forte@Sun.COM 
17847836SJohn.Forte@Sun.COM 	if (strcmp(nconf->nc_proto, "tcp") == 0 ||
17857836SJohn.Forte@Sun.COM 	    strcmp(nconf->nc_proto, "tcp6") == 0) {
17867836SJohn.Forte@Sun.COM 		/*
17877836SJohn.Forte@Sun.COM 		 * Disable the Nagle algorithm on TCP connections.
17887836SJohn.Forte@Sun.COM 		 * Connections accepted from this listener will
17897836SJohn.Forte@Sun.COM 		 * inherit the listener options.
17907836SJohn.Forte@Sun.COM 		 */
17917836SJohn.Forte@Sun.COM 
17927836SJohn.Forte@Sun.COM 		/* LINTED pointer alignment */
17937836SJohn.Forte@Sun.COM 		opt = (struct opthdr *)reqbuf;
17947836SJohn.Forte@Sun.COM 		opt->level = IPPROTO_TCP;
17957836SJohn.Forte@Sun.COM 		opt->name = TCP_NODELAY;
17967836SJohn.Forte@Sun.COM 		opt->len = sizeof (int);
17977836SJohn.Forte@Sun.COM 
17987836SJohn.Forte@Sun.COM 		/* LINTED pointer alignment */
17997836SJohn.Forte@Sun.COM 		*(int *)((char *)opt + sizeof (*opt)) = 1;
18007836SJohn.Forte@Sun.COM 
18017836SJohn.Forte@Sun.COM 		req.flags = T_NEGOTIATE;
18027836SJohn.Forte@Sun.COM 		req.opt.len = sizeof (*opt) + opt->len;
18037836SJohn.Forte@Sun.COM 		req.opt.buf = (char *)opt;
18047836SJohn.Forte@Sun.COM 		resp.flags = 0;
18057836SJohn.Forte@Sun.COM 		resp.opt.buf = reqbuf;
18067836SJohn.Forte@Sun.COM 		resp.opt.maxlen = sizeof (reqbuf);
18077836SJohn.Forte@Sun.COM 
18087836SJohn.Forte@Sun.COM 		if (t_optmgmt(fd, &req, &resp) < 0 ||
18097836SJohn.Forte@Sun.COM 		    resp.flags != T_SUCCESS) {
18107836SJohn.Forte@Sun.COM 			syslog(LOG_ERR,
18117836SJohn.Forte@Sun.COM 	"couldn't set NODELAY option for proto %s: t_errno = %d, %m",
18127836SJohn.Forte@Sun.COM 				nconf->nc_proto, t_errno);
18137836SJohn.Forte@Sun.COM 		}
18147836SJohn.Forte@Sun.COM 	}
18157836SJohn.Forte@Sun.COM 
18167836SJohn.Forte@Sun.COM 	return (fd);
18177836SJohn.Forte@Sun.COM }
18187836SJohn.Forte@Sun.COM 
18197836SJohn.Forte@Sun.COM 
18207836SJohn.Forte@Sun.COM /* ARGSUSED */
18217836SJohn.Forte@Sun.COM static int
bind_to_provider(char * provider,char * serv,struct netbuf ** addr,struct netconfig ** retnconf)18227836SJohn.Forte@Sun.COM bind_to_provider(char *provider, char *serv, struct netbuf **addr,
18237836SJohn.Forte@Sun.COM 		struct netconfig **retnconf)
18247836SJohn.Forte@Sun.COM {
18257836SJohn.Forte@Sun.COM 	struct netconfig *nconf;
18267836SJohn.Forte@Sun.COM 	NCONF_HANDLE *nc;
18277836SJohn.Forte@Sun.COM 	struct nd_hostserv hs;
18287836SJohn.Forte@Sun.COM 
18297836SJohn.Forte@Sun.COM 	hs.h_host = HOST_SELF;
18307836SJohn.Forte@Sun.COM 	hs.h_serv = RDC_SERVICE;	/* serv_name_to_port_name(serv); */
18317836SJohn.Forte@Sun.COM 
18327836SJohn.Forte@Sun.COM 	if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
18337836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "setnetconfig failed: %m");
18347836SJohn.Forte@Sun.COM 		return (-1);
18357836SJohn.Forte@Sun.COM 	}
18367836SJohn.Forte@Sun.COM 	while (nconf = getnetconfig(nc)) {
18377836SJohn.Forte@Sun.COM 		if (OK_TPI_TYPE(nconf) &&
18387836SJohn.Forte@Sun.COM 		    strcmp(nconf->nc_device, provider) == 0) {
18397836SJohn.Forte@Sun.COM 			*retnconf = nconf;
18407836SJohn.Forte@Sun.COM 			return (rdcd_bindit(nconf, addr, &hs, listen_backlog));
18417836SJohn.Forte@Sun.COM 		}
18427836SJohn.Forte@Sun.COM 	}
18437836SJohn.Forte@Sun.COM 	(void) endnetconfig(nc);
18447836SJohn.Forte@Sun.COM 	if ((Is_ipv6present() && (strcmp(provider, "/dev/tcp6") == 0)) ||
18457836SJohn.Forte@Sun.COM 	    (!Is_ipv6present() && (strcmp(provider, "/dev/tcp") == 0)))
18467836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "couldn't find netconfig entry for provider %s",
18477836SJohn.Forte@Sun.COM 		    provider);
18487836SJohn.Forte@Sun.COM 	return (-1);
18497836SJohn.Forte@Sun.COM }
18507836SJohn.Forte@Sun.COM 
18517836SJohn.Forte@Sun.COM 
18527836SJohn.Forte@Sun.COM /*
18537836SJohn.Forte@Sun.COM  * For listen fd's index is always less than end_listen_fds.
18547836SJohn.Forte@Sun.COM  * It's value is equal to the number of open file descriptors after the
18557836SJohn.Forte@Sun.COM  * last listen end point was opened but before any connection was accepted.
18567836SJohn.Forte@Sun.COM  */
18577836SJohn.Forte@Sun.COM static int
is_listen_fd_index(int index)18587836SJohn.Forte@Sun.COM is_listen_fd_index(int index)
18597836SJohn.Forte@Sun.COM {
18607836SJohn.Forte@Sun.COM 	return (index < end_listen_fds);
18617836SJohn.Forte@Sun.COM }
18627836SJohn.Forte@Sun.COM 
18637836SJohn.Forte@Sun.COM 
18647836SJohn.Forte@Sun.COM /*
18657836SJohn.Forte@Sun.COM  * Create an address mask appropriate for the transport.
18667836SJohn.Forte@Sun.COM  * The mask is used to obtain the host-specific part of
18677836SJohn.Forte@Sun.COM  * a network address when comparing addresses.
18687836SJohn.Forte@Sun.COM  * For an internet address the host-specific part is just
18697836SJohn.Forte@Sun.COM  * the 32 bit IP address and this part of the mask is set
18707836SJohn.Forte@Sun.COM  * to all-ones. The port number part of the mask is zeroes.
18717836SJohn.Forte@Sun.COM  */
18727836SJohn.Forte@Sun.COM static int
set_addrmask(int fd,struct netconfig * nconf,struct netbuf * mask)18737836SJohn.Forte@Sun.COM set_addrmask(int fd, struct netconfig *nconf, struct netbuf *mask)
18747836SJohn.Forte@Sun.COM {
18757836SJohn.Forte@Sun.COM 	struct t_info info;
18767836SJohn.Forte@Sun.COM 
18777836SJohn.Forte@Sun.COM 	/*
18787836SJohn.Forte@Sun.COM 	 * Find the size of the address we need to mask.
18797836SJohn.Forte@Sun.COM 	 */
18807836SJohn.Forte@Sun.COM 	if (t_getinfo(fd, &info) < 0) {
18817836SJohn.Forte@Sun.COM 		t_error("t_getinfo");
18827836SJohn.Forte@Sun.COM 		return (-1);
18837836SJohn.Forte@Sun.COM 	}
18847836SJohn.Forte@Sun.COM 	mask->len = mask->maxlen = info.addr;
18857836SJohn.Forte@Sun.COM 	if (info.addr <= 0) {
18867836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "set_addrmask: address size: %ld",
18877836SJohn.Forte@Sun.COM 			info.addr);
18887836SJohn.Forte@Sun.COM 		return (-1);
18897836SJohn.Forte@Sun.COM 	}
18907836SJohn.Forte@Sun.COM 
18917836SJohn.Forte@Sun.COM 	mask->buf = (char *)malloc(mask->len);
18927836SJohn.Forte@Sun.COM 	if (mask->buf == NULL) {
18937836SJohn.Forte@Sun.COM 		syslog(LOG_ERR, "set_addrmask: no memory");
18947836SJohn.Forte@Sun.COM 		return (-1);
18957836SJohn.Forte@Sun.COM 	}
18967836SJohn.Forte@Sun.COM 	(void) memset(mask->buf, 0, mask->len);	/* reset all mask bits */
18977836SJohn.Forte@Sun.COM 
18987836SJohn.Forte@Sun.COM 	if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
18997836SJohn.Forte@Sun.COM 		/*
19007836SJohn.Forte@Sun.COM 		 * Set the mask so that the port is ignored.
19017836SJohn.Forte@Sun.COM 		 */
19027836SJohn.Forte@Sun.COM 		/* LINTED pointer alignment */
19037836SJohn.Forte@Sun.COM 		((struct sockaddr_in *)mask->buf)->sin_addr.s_addr =
19047836SJohn.Forte@Sun.COM 		    (in_addr_t)~0;
19057836SJohn.Forte@Sun.COM 		/* LINTED pointer alignment */
19067836SJohn.Forte@Sun.COM 		((struct sockaddr_in *)mask->buf)->sin_family = (sa_family_t)~0;
19077836SJohn.Forte@Sun.COM 	}
19087836SJohn.Forte@Sun.COM #ifdef NC_INET6
19097836SJohn.Forte@Sun.COM 	else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
19107836SJohn.Forte@Sun.COM 		/* LINTED pointer alignment */
19117836SJohn.Forte@Sun.COM 		(void) memset(&((struct sockaddr_in6 *)mask->buf)->sin6_addr,
19127836SJohn.Forte@Sun.COM 		    (uchar_t)~0, sizeof (struct in6_addr));
19137836SJohn.Forte@Sun.COM 		/* LINTED pointer alignment */
19147836SJohn.Forte@Sun.COM 		((struct sockaddr_in6 *)mask->buf)->sin6_family =
19157836SJohn.Forte@Sun.COM 		    (sa_family_t)~0;
19167836SJohn.Forte@Sun.COM 	}
19177836SJohn.Forte@Sun.COM #endif
19187836SJohn.Forte@Sun.COM 	else {
19197836SJohn.Forte@Sun.COM 		/*
19207836SJohn.Forte@Sun.COM 		 * Set all mask bits.
19217836SJohn.Forte@Sun.COM 		 */
19227836SJohn.Forte@Sun.COM 		(void) memset(mask->buf, (uchar_t)~0, mask->len);
19237836SJohn.Forte@Sun.COM 	}
19247836SJohn.Forte@Sun.COM 	return (0);
19257836SJohn.Forte@Sun.COM }
19267836SJohn.Forte@Sun.COM 
19277836SJohn.Forte@Sun.COM #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
19287836SJohn.Forte@Sun.COM 
19297836SJohn.Forte@Sun.COM static int
sndrsvcpool(int maxservers)19307836SJohn.Forte@Sun.COM sndrsvcpool(int maxservers)
19317836SJohn.Forte@Sun.COM {
19327836SJohn.Forte@Sun.COM 	struct svcpool_args npa;
19337836SJohn.Forte@Sun.COM 
19347836SJohn.Forte@Sun.COM 	npa.id = RDC_SVCPOOL_ID;
19357836SJohn.Forte@Sun.COM 	npa.maxthreads = maxservers;
19367836SJohn.Forte@Sun.COM 	npa.redline = 0;
19377836SJohn.Forte@Sun.COM 	npa.qsize = 0;
19387836SJohn.Forte@Sun.COM 	npa.timeout = 0;
19397836SJohn.Forte@Sun.COM 	npa.stksize = 0;
19407836SJohn.Forte@Sun.COM 	npa.max_same_xprt = 0;
19417836SJohn.Forte@Sun.COM 	return (sndrsys(RDC_POOL_CREATE, &npa));
19427836SJohn.Forte@Sun.COM }
19437836SJohn.Forte@Sun.COM 
19447836SJohn.Forte@Sun.COM 
19457836SJohn.Forte@Sun.COM /*
19467836SJohn.Forte@Sun.COM  * The following stolen from cmd/fs.d/nfs/lib/thrpool.c
19477836SJohn.Forte@Sun.COM  */
19487836SJohn.Forte@Sun.COM 
19497836SJohn.Forte@Sun.COM #include <thread.h>
19507836SJohn.Forte@Sun.COM 
19517836SJohn.Forte@Sun.COM /*
19527836SJohn.Forte@Sun.COM  * Thread to call into the kernel and do work on behalf of SNDR/ncall-ip.
19537836SJohn.Forte@Sun.COM  */
19547836SJohn.Forte@Sun.COM static void *
svcstart(void * arg)19557836SJohn.Forte@Sun.COM svcstart(void *arg)
19567836SJohn.Forte@Sun.COM {
19577836SJohn.Forte@Sun.COM 	int id = (int)arg;
19587836SJohn.Forte@Sun.COM 	int err;
19597836SJohn.Forte@Sun.COM 
19607836SJohn.Forte@Sun.COM 	while ((err = sndrsys(RDC_POOL_RUN, &id)) != 0) {
19617836SJohn.Forte@Sun.COM 		/*
19627836SJohn.Forte@Sun.COM 		 * Interrupted by a signal while in the kernel.
19637836SJohn.Forte@Sun.COM 		 * this process is still alive, try again.
19647836SJohn.Forte@Sun.COM 		 */
19657836SJohn.Forte@Sun.COM 		if (err == EINTR)
19667836SJohn.Forte@Sun.COM 			continue;
19677836SJohn.Forte@Sun.COM 		else
19687836SJohn.Forte@Sun.COM 			break;
19697836SJohn.Forte@Sun.COM 	}
19707836SJohn.Forte@Sun.COM 
19717836SJohn.Forte@Sun.COM 	/*
19727836SJohn.Forte@Sun.COM 	 * If we weren't interrupted by a signal, but did
19737836SJohn.Forte@Sun.COM 	 * return from the kernel, this thread's work is done,
19747836SJohn.Forte@Sun.COM 	 * and it should exit.
19757836SJohn.Forte@Sun.COM 	 */
19767836SJohn.Forte@Sun.COM 	thr_exit(NULL);
19777836SJohn.Forte@Sun.COM 	return (NULL);
19787836SJohn.Forte@Sun.COM }
19797836SJohn.Forte@Sun.COM 
19807836SJohn.Forte@Sun.COM /*
19817836SJohn.Forte@Sun.COM  * User-space "creator" thread. This thread blocks in the kernel
19827836SJohn.Forte@Sun.COM  * until new worker threads need to be created for the service
19837836SJohn.Forte@Sun.COM  * pool. On return to userspace, if there is no error, create a
19847836SJohn.Forte@Sun.COM  * new thread for the service pool.
19857836SJohn.Forte@Sun.COM  */
19867836SJohn.Forte@Sun.COM static void *
svcblock(void * arg)19877836SJohn.Forte@Sun.COM svcblock(void *arg)
19887836SJohn.Forte@Sun.COM {
19897836SJohn.Forte@Sun.COM 	int id = (int)arg;
19907836SJohn.Forte@Sun.COM 
19917836SJohn.Forte@Sun.COM 	/* CONSTCOND */
19927836SJohn.Forte@Sun.COM 	while (1) {
19937836SJohn.Forte@Sun.COM 		thread_t tid;
19947836SJohn.Forte@Sun.COM 		int err;
19957836SJohn.Forte@Sun.COM 
19967836SJohn.Forte@Sun.COM 		/*
19977836SJohn.Forte@Sun.COM 		 * Call into the kernel, and hang out there
19987836SJohn.Forte@Sun.COM 		 * until a thread needs to be created.
19997836SJohn.Forte@Sun.COM 		 */
20007836SJohn.Forte@Sun.COM 		if (err = sndrsys(RDC_POOL_WAIT, &id)) {
20017836SJohn.Forte@Sun.COM 			if (err == ECANCELED || err == EBUSY)
20027836SJohn.Forte@Sun.COM 				/*
20037836SJohn.Forte@Sun.COM 				 * If we get back ECANCELED, the service
20047836SJohn.Forte@Sun.COM 				 * pool is exiting, and we may as well
20057836SJohn.Forte@Sun.COM 				 * clean up this thread. If EBUSY is
20067836SJohn.Forte@Sun.COM 				 * returned, there's already a thread
20077836SJohn.Forte@Sun.COM 				 * looping on this pool, so we should
20087836SJohn.Forte@Sun.COM 				 * give up.
20097836SJohn.Forte@Sun.COM 				 */
20107836SJohn.Forte@Sun.COM 				break;
20117836SJohn.Forte@Sun.COM 			else
20127836SJohn.Forte@Sun.COM 				continue;
20137836SJohn.Forte@Sun.COM 		}
20147836SJohn.Forte@Sun.COM 
20157836SJohn.Forte@Sun.COM 		(void) thr_create(NULL, NULL, svcstart, (void *)id,
20167836SJohn.Forte@Sun.COM 		    THR_BOUND | THR_DETACHED, &tid);
20177836SJohn.Forte@Sun.COM 	}
20187836SJohn.Forte@Sun.COM 
20197836SJohn.Forte@Sun.COM 	thr_exit(NULL);
20207836SJohn.Forte@Sun.COM 	return (NULL);
20217836SJohn.Forte@Sun.COM }
20227836SJohn.Forte@Sun.COM 
20237836SJohn.Forte@Sun.COM static int
svcwait(int id)20247836SJohn.Forte@Sun.COM svcwait(int id)
20257836SJohn.Forte@Sun.COM {
20267836SJohn.Forte@Sun.COM 	thread_t tid;
20277836SJohn.Forte@Sun.COM 
20287836SJohn.Forte@Sun.COM 	/*
20297836SJohn.Forte@Sun.COM 	 * Create a bound thread to wait for kernel LWPs that
20307836SJohn.Forte@Sun.COM 	 * need to be created.
20317836SJohn.Forte@Sun.COM 	 */
20327836SJohn.Forte@Sun.COM 	if (thr_create(NULL, NULL, svcblock, (void *)id,
20337836SJohn.Forte@Sun.COM 	    THR_BOUND | THR_DETACHED, &tid))
20347836SJohn.Forte@Sun.COM 		return (1);
20357836SJohn.Forte@Sun.COM 
20367836SJohn.Forte@Sun.COM 	return (0);
20377836SJohn.Forte@Sun.COM }
20387836SJohn.Forte@Sun.COM #endif /* Solaris 9+ */
2039