xref: /illumos-gate/usr/src/lib/libnsl/rpc/svc_vc.c (revision a69e76ca)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5004388ebScasper  * Common Development and Distribution License (the "License").
6004388ebScasper  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2161961e0fSrobinson 
227c478bd9Sstevel@tonic-gate /*
23d67944fbSScott Rotondo  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
2613147901SMarcel Telka /*
2713147901SMarcel Telka  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
2813147901SMarcel Telka  */
29e8031f0aSraf 
307c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
317c478bd9Sstevel@tonic-gate /* All Rights Reserved */
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley
347c478bd9Sstevel@tonic-gate  * 4.3 BSD under license from the Regents of the University of
357c478bd9Sstevel@tonic-gate  * California.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /*
39e8031f0aSraf  * Server side for Connection Oriented RPC.
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  * Actually implements two flavors of transporter -
427c478bd9Sstevel@tonic-gate  * a rendezvouser (a listener and connection establisher)
437c478bd9Sstevel@tonic-gate  * and a record stream.
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include "mt.h"
477c478bd9Sstevel@tonic-gate #include "rpc_mt.h"
487c478bd9Sstevel@tonic-gate #include <stdio.h>
497c478bd9Sstevel@tonic-gate #include <stdlib.h>
507c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
517c478bd9Sstevel@tonic-gate #include <sys/types.h>
527c478bd9Sstevel@tonic-gate #include <errno.h>
537c478bd9Sstevel@tonic-gate #include <sys/stat.h>
547c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
557c478bd9Sstevel@tonic-gate #include <sys/poll.h>
567c478bd9Sstevel@tonic-gate #include <syslog.h>
577c478bd9Sstevel@tonic-gate #include <rpc/nettype.h>
587c478bd9Sstevel@tonic-gate #include <tiuser.h>
597c478bd9Sstevel@tonic-gate #include <string.h>
607c478bd9Sstevel@tonic-gate #include <stropts.h>
617c478bd9Sstevel@tonic-gate #include <stdlib.h>
627c478bd9Sstevel@tonic-gate #include <unistd.h>
637c478bd9Sstevel@tonic-gate #include <sys/timod.h>
647c478bd9Sstevel@tonic-gate #include <limits.h>
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #ifndef MIN
677c478bd9Sstevel@tonic-gate #define	MIN(a, b)	(((a) < (b)) ? (a) : (b))
687c478bd9Sstevel@tonic-gate #endif
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #define	CLEANUP_SIZE	1024
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate extern int nsvc_xdrs;
737c478bd9Sstevel@tonic-gate extern int __rpc_connmaxrec;
747c478bd9Sstevel@tonic-gate extern int __rpc_irtimeout;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate extern SVCXPRT	**svc_xports;
777c478bd9Sstevel@tonic-gate extern int	__td_setnodelay(int);
787c478bd9Sstevel@tonic-gate extern bool_t	__xdrrec_getbytes_nonblock(XDR *, enum xprt_stat *);
797c478bd9Sstevel@tonic-gate extern bool_t	__xdrrec_set_conn_nonblock(XDR *, uint32_t);
807c478bd9Sstevel@tonic-gate extern int	__rpc_legal_connmaxrec(int);
817c478bd9Sstevel@tonic-gate /* Structure used to initialize SVC_XP_AUTH(xprt).svc_ah_ops. */
827c478bd9Sstevel@tonic-gate extern struct svc_auth_ops svc_auth_any_ops;
837c478bd9Sstevel@tonic-gate extern void	__xprt_unregister_private(const SVCXPRT *, bool_t);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate static struct xp_ops 	*svc_vc_ops(void);
867c478bd9Sstevel@tonic-gate static struct xp_ops 	*svc_vc_rendezvous_ops(void);
877c478bd9Sstevel@tonic-gate static void		svc_vc_destroy(SVCXPRT *);
887c478bd9Sstevel@tonic-gate static bool_t		svc_vc_nonblock(SVCXPRT *, SVCXPRT *);
897c478bd9Sstevel@tonic-gate static int		read_vc(SVCXPRT *, caddr_t, int);
907c478bd9Sstevel@tonic-gate static int		write_vc(SVCXPRT *, caddr_t, int);
917c478bd9Sstevel@tonic-gate static SVCXPRT		*makefd_xprt(int, uint_t, uint_t, t_scalar_t, char *);
927c478bd9Sstevel@tonic-gate static void		update_nonblock_timestamps(SVCXPRT *);
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */
957c478bd9Sstevel@tonic-gate 	uint_t sendsize;
967c478bd9Sstevel@tonic-gate 	uint_t recvsize;
977c478bd9Sstevel@tonic-gate 	struct t_call *t_call;
987c478bd9Sstevel@tonic-gate 	struct t_bind *t_bind;
997c478bd9Sstevel@tonic-gate 	t_scalar_t cf_tsdu;
1007c478bd9Sstevel@tonic-gate 	char *cf_cache;
1017c478bd9Sstevel@tonic-gate 	int tcp_flag;
1027c478bd9Sstevel@tonic-gate 	int tcp_keepalive;
1037c478bd9Sstevel@tonic-gate 	int cf_connmaxrec;
1047c478bd9Sstevel@tonic-gate };
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate struct cf_conn {	/* kept in xprt->xp_p1 for actual connection */
1077c478bd9Sstevel@tonic-gate 	uint_t sendsize;
1087c478bd9Sstevel@tonic-gate 	uint_t recvsize;
1097c478bd9Sstevel@tonic-gate 	enum xprt_stat strm_stat;
1107c478bd9Sstevel@tonic-gate 	uint32_t x_id;
1117c478bd9Sstevel@tonic-gate 	t_scalar_t cf_tsdu;
1127c478bd9Sstevel@tonic-gate 	XDR xdrs;
1137c478bd9Sstevel@tonic-gate 	char *cf_cache;
1147c478bd9Sstevel@tonic-gate 	char verf_body[MAX_AUTH_BYTES];
1157c478bd9Sstevel@tonic-gate 	bool_t cf_conn_nonblock;
1167c478bd9Sstevel@tonic-gate 	time_t cf_conn_nonblock_timestamp;
1177c478bd9Sstevel@tonic-gate };
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate static int t_rcvall(int, char *, int);
1207c478bd9Sstevel@tonic-gate static int t_rcvnonblock(SVCXPRT *, caddr_t, int);
1217c478bd9Sstevel@tonic-gate static void svc_timeout_nonblock_xprt_and_LRU(bool_t);
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate extern int __xdrrec_setfirst(XDR *);
1247c478bd9Sstevel@tonic-gate extern int __xdrrec_resetfirst(XDR *);
1257c478bd9Sstevel@tonic-gate extern int __is_xdrrec_first(XDR *);
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate  * This is intended as a performance improvement on the old string handling
1297c478bd9Sstevel@tonic-gate  * stuff by read only moving data into the  text segment.
1307c478bd9Sstevel@tonic-gate  * Format = <routine> : <error>
1317c478bd9Sstevel@tonic-gate  */
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate static const char errstring[] = " %s : %s";
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate /* Routine names */
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate static const char svc_vc_create_str[] = "svc_vc_create";
1387c478bd9Sstevel@tonic-gate static const char svc_fd_create_str[] = "svc_fd_create";
1397c478bd9Sstevel@tonic-gate static const char makefd_xprt_str[] = "svc_vc_create: makefd_xprt ";
1407c478bd9Sstevel@tonic-gate static const char rendezvous_request_str[] = "rendezvous_request";
1417c478bd9Sstevel@tonic-gate static const char svc_vc_fderr[] =
1427c478bd9Sstevel@tonic-gate 		"fd > FD_SETSIZE; Use rpc_control(RPC_SVC_USE_POLLFD,...);";
1437c478bd9Sstevel@tonic-gate static const char do_accept_str[] = "do_accept";
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate /* error messages */
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate static const char no_mem_str[] = "out of memory";
1487c478bd9Sstevel@tonic-gate static const char no_tinfo_str[] = "could not get transport information";
1497c478bd9Sstevel@tonic-gate static const char no_fcntl_getfl_str[] = "could not get status flags and modes";
1507c478bd9Sstevel@tonic-gate static const char no_nonblock_str[] = "could not set transport non-blocking";
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate /*
1537c478bd9Sstevel@tonic-gate  * Used to determine whether the time-out logic should be executed.
1547c478bd9Sstevel@tonic-gate  */
1557c478bd9Sstevel@tonic-gate static bool_t check_nonblock_timestamps = FALSE;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate void
svc_vc_xprtfree(SVCXPRT * xprt)1587c478bd9Sstevel@tonic-gate svc_vc_xprtfree(SVCXPRT *xprt)
1597c478bd9Sstevel@tonic-gate {
1607c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
1617c478bd9Sstevel@tonic-gate 	SVCXPRT_EXT		*xt = xprt ? SVCEXT(xprt) : NULL;
1627c478bd9Sstevel@tonic-gate 	struct cf_rendezvous	*r = xprt ?
1637c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
16413147901SMarcel Telka 	    (struct cf_rendezvous *)xprt->xp_p1 : NULL;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	if (!xprt)
1677c478bd9Sstevel@tonic-gate 		return;
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	if (xprt->xp_tp)
1707c478bd9Sstevel@tonic-gate 		free(xprt->xp_tp);
1717c478bd9Sstevel@tonic-gate 	if (xprt->xp_netid)
1727c478bd9Sstevel@tonic-gate 		free(xprt->xp_netid);
1737c478bd9Sstevel@tonic-gate 	if (xt && (xt->parent == NULL)) {
1747c478bd9Sstevel@tonic-gate 		if (xprt->xp_ltaddr.buf)
1757c478bd9Sstevel@tonic-gate 			free(xprt->xp_ltaddr.buf);
1767c478bd9Sstevel@tonic-gate 		if (xprt->xp_rtaddr.buf)
1777c478bd9Sstevel@tonic-gate 			free(xprt->xp_rtaddr.buf);
1787c478bd9Sstevel@tonic-gate 	}
1797c478bd9Sstevel@tonic-gate 	if (r) {
1807c478bd9Sstevel@tonic-gate 		if (r->t_call)
18161961e0fSrobinson 			(void) t_free((char *)r->t_call, T_CALL);
1827c478bd9Sstevel@tonic-gate 		if (r->t_bind)
18361961e0fSrobinson 			(void) t_free((char *)r->t_bind, T_BIND);
18461961e0fSrobinson 		free(r);
1857c478bd9Sstevel@tonic-gate 	}
1867c478bd9Sstevel@tonic-gate 	svc_xprt_free(xprt);
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate /*
1907c478bd9Sstevel@tonic-gate  * Usage:
1917c478bd9Sstevel@tonic-gate  *	xprt = svc_vc_create(fd, sendsize, recvsize);
1927c478bd9Sstevel@tonic-gate  * Since connection streams do buffered io similar to stdio, the caller
1937c478bd9Sstevel@tonic-gate  * can specify how big the send and receive buffers are. If recvsize
1947c478bd9Sstevel@tonic-gate  * or sendsize are 0, defaults will be chosen.
1957c478bd9Sstevel@tonic-gate  * fd should be open and bound.
1967c478bd9Sstevel@tonic-gate  */
1977c478bd9Sstevel@tonic-gate SVCXPRT *
svc_vc_create_private(int fd,uint_t sendsize,uint_t recvsize)1987c478bd9Sstevel@tonic-gate svc_vc_create_private(int fd, uint_t sendsize, uint_t recvsize)
1997c478bd9Sstevel@tonic-gate {
2007c478bd9Sstevel@tonic-gate 	struct cf_rendezvous *r;
2017c478bd9Sstevel@tonic-gate 	SVCXPRT *xprt;
2027c478bd9Sstevel@tonic-gate 	struct t_info tinfo;
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	if (RPC_FD_NOTIN_FDSET(fd)) {
2057c478bd9Sstevel@tonic-gate 		errno = EBADF;
2067c478bd9Sstevel@tonic-gate 		t_errno = TBADF;
2077c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, errstring, svc_vc_create_str,
2087c478bd9Sstevel@tonic-gate 		    svc_vc_fderr);
20961961e0fSrobinson 		return (NULL);
2107c478bd9Sstevel@tonic-gate 	}
21161961e0fSrobinson 	if ((xprt = svc_xprt_alloc()) == NULL) {
2127c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, errstring,
2137c478bd9Sstevel@tonic-gate 		    svc_vc_create_str, no_mem_str);
21461961e0fSrobinson 		return (NULL);
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
2177c478bd9Sstevel@tonic-gate 	svc_flags(xprt) |= SVC_RENDEZVOUS;
2187c478bd9Sstevel@tonic-gate 
21961961e0fSrobinson 	r = calloc(1, sizeof (*r));
22061961e0fSrobinson 	if (r == NULL) {
2217c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, errstring,
22213147901SMarcel Telka 		    svc_vc_create_str, no_mem_str);
2237c478bd9Sstevel@tonic-gate 		svc_vc_xprtfree(xprt);
22461961e0fSrobinson 		return (NULL);
2257c478bd9Sstevel@tonic-gate 	}
2267c478bd9Sstevel@tonic-gate 	if (t_getinfo(fd, &tinfo) == -1) {
2277c478bd9Sstevel@tonic-gate 		char errorstr[100];
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 		__tli_sys_strerror(errorstr, sizeof (errorstr),
23013147901SMarcel Telka 		    t_errno, errno);
2317c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "%s : %s : %s",
23213147901SMarcel Telka 		    svc_vc_create_str, no_tinfo_str, errorstr);
23361961e0fSrobinson 		free(r);
2347c478bd9Sstevel@tonic-gate 		svc_vc_xprtfree(xprt);
23561961e0fSrobinson 		return (NULL);
2367c478bd9Sstevel@tonic-gate 	}
2377c478bd9Sstevel@tonic-gate 	/*
2387c478bd9Sstevel@tonic-gate 	 * Find the receive and the send size
2397c478bd9Sstevel@tonic-gate 	 */
2407c478bd9Sstevel@tonic-gate 	r->sendsize = __rpc_get_t_size((int)sendsize, tinfo.tsdu);
2417c478bd9Sstevel@tonic-gate 	r->recvsize = __rpc_get_t_size((int)recvsize, tinfo.tsdu);
2427c478bd9Sstevel@tonic-gate 	if ((r->sendsize == 0) || (r->recvsize == 0)) {
2437c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR,
2447c478bd9Sstevel@tonic-gate 		    "svc_vc_create:  transport does not support "
2457c478bd9Sstevel@tonic-gate 		    "data transfer");
24661961e0fSrobinson 		free(r);
2477c478bd9Sstevel@tonic-gate 		svc_vc_xprtfree(xprt);
24861961e0fSrobinson 		return (NULL);
2497c478bd9Sstevel@tonic-gate 	}
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
2527c478bd9Sstevel@tonic-gate 	r->t_call = (struct t_call *)t_alloc(fd, T_CALL, T_ADDR | T_OPT);
2537c478bd9Sstevel@tonic-gate 	if (r->t_call == NULL) {
2547c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, errstring,
25513147901SMarcel Telka 		    svc_vc_create_str, no_mem_str);
25661961e0fSrobinson 		free(r);
2577c478bd9Sstevel@tonic-gate 		svc_vc_xprtfree(xprt);
25861961e0fSrobinson 		return (NULL);
2597c478bd9Sstevel@tonic-gate 	}
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
2627c478bd9Sstevel@tonic-gate 	r->t_bind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
26361961e0fSrobinson 	if (r->t_bind == NULL) {
2647c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, errstring,
26513147901SMarcel Telka 		    svc_vc_create_str, no_mem_str);
26661961e0fSrobinson 		(void) t_free((char *)r->t_call, T_CALL);
26761961e0fSrobinson 		free(r);
2687c478bd9Sstevel@tonic-gate 		svc_vc_xprtfree(xprt);
26961961e0fSrobinson 		return (NULL);
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	r->cf_tsdu = tinfo.tsdu;
2737c478bd9Sstevel@tonic-gate 	r->tcp_flag = FALSE;
2747c478bd9Sstevel@tonic-gate 	r->tcp_keepalive = FALSE;
2757c478bd9Sstevel@tonic-gate 	r->cf_connmaxrec = __rpc_connmaxrec;
2767c478bd9Sstevel@tonic-gate 	xprt->xp_fd = fd;
2777c478bd9Sstevel@tonic-gate 	xprt->xp_p1 = (caddr_t)r;
2787c478bd9Sstevel@tonic-gate 	xprt->xp_p2 = NULL;
2797c478bd9Sstevel@tonic-gate 	xprt->xp_verf = _null_auth;
2807c478bd9Sstevel@tonic-gate 	xprt->xp_ops = svc_vc_rendezvous_ops();
2817c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
2827c478bd9Sstevel@tonic-gate 	SVC_XP_AUTH(xprt).svc_ah_ops = svc_auth_any_ops;
2837c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
2847c478bd9Sstevel@tonic-gate 	SVC_XP_AUTH(xprt).svc_ah_private = NULL;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	return (xprt);
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate SVCXPRT *
svc_vc_create(const int fd,const uint_t sendsize,const uint_t recvsize)29061961e0fSrobinson svc_vc_create(const int fd, const uint_t sendsize, const uint_t recvsize)
2917c478bd9Sstevel@tonic-gate {
2927c478bd9Sstevel@tonic-gate 	SVCXPRT *xprt;
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	if ((xprt = svc_vc_create_private(fd, sendsize, recvsize)) != NULL)
2957c478bd9Sstevel@tonic-gate 		xprt_register(xprt);
2967c478bd9Sstevel@tonic-gate 	return (xprt);
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate SVCXPRT *
svc_vc_xprtcopy(SVCXPRT * parent)3007c478bd9Sstevel@tonic-gate svc_vc_xprtcopy(SVCXPRT *parent)
3017c478bd9Sstevel@tonic-gate {
3027c478bd9Sstevel@tonic-gate 	SVCXPRT			*xprt;
3037c478bd9Sstevel@tonic-gate 	struct cf_rendezvous	*r, *pr;
3047c478bd9Sstevel@tonic-gate 	int			fd = parent->xp_fd;
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	if ((xprt = svc_xprt_alloc()) == NULL)
3077c478bd9Sstevel@tonic-gate 		return (NULL);
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
3107c478bd9Sstevel@tonic-gate 	SVCEXT(xprt)->parent = parent;
3117c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
3127c478bd9Sstevel@tonic-gate 	SVCEXT(xprt)->flags = SVCEXT(parent)->flags;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	xprt->xp_fd = fd;
3157c478bd9Sstevel@tonic-gate 	xprt->xp_ops = svc_vc_rendezvous_ops();
3167c478bd9Sstevel@tonic-gate 	if (parent->xp_tp) {
3177c478bd9Sstevel@tonic-gate 		xprt->xp_tp = (char *)strdup(parent->xp_tp);
3187c478bd9Sstevel@tonic-gate 		if (xprt->xp_tp == NULL) {
3197c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "svc_vc_xprtcopy: strdup failed");
3207c478bd9Sstevel@tonic-gate 			svc_vc_xprtfree(xprt);
3217c478bd9Sstevel@tonic-gate 			return (NULL);
3227c478bd9Sstevel@tonic-gate 		}
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate 	if (parent->xp_netid) {
3257c478bd9Sstevel@tonic-gate 		xprt->xp_netid = (char *)strdup(parent->xp_netid);
3267c478bd9Sstevel@tonic-gate 		if (xprt->xp_netid == NULL) {
3277c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "svc_vc_xprtcopy: strdup failed");
3287c478bd9Sstevel@tonic-gate 			if (xprt->xp_tp)
32961961e0fSrobinson 				free(xprt->xp_tp);
3307c478bd9Sstevel@tonic-gate 			svc_vc_xprtfree(xprt);
3317c478bd9Sstevel@tonic-gate 			return (NULL);
3327c478bd9Sstevel@tonic-gate 		}
3337c478bd9Sstevel@tonic-gate 	}
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	/*
3367c478bd9Sstevel@tonic-gate 	 * can share both local and remote address
3377c478bd9Sstevel@tonic-gate 	 */
3387c478bd9Sstevel@tonic-gate 	xprt->xp_ltaddr = parent->xp_ltaddr;
3397c478bd9Sstevel@tonic-gate 	xprt->xp_rtaddr = parent->xp_rtaddr; /* XXX - not used for rendezvous */
3407c478bd9Sstevel@tonic-gate 	xprt->xp_type = parent->xp_type;
3417c478bd9Sstevel@tonic-gate 	xprt->xp_verf = parent->xp_verf;
3427c478bd9Sstevel@tonic-gate 
34361961e0fSrobinson 	if ((r = calloc(1, sizeof (*r))) == NULL) {
3447c478bd9Sstevel@tonic-gate 		svc_vc_xprtfree(xprt);
3457c478bd9Sstevel@tonic-gate 		return (NULL);
3467c478bd9Sstevel@tonic-gate 	}
3477c478bd9Sstevel@tonic-gate 	xprt->xp_p1 = (caddr_t)r;
3487c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
3497c478bd9Sstevel@tonic-gate 	pr = (struct cf_rendezvous *)parent->xp_p1;
3507c478bd9Sstevel@tonic-gate 	r->sendsize = pr->sendsize;
3517c478bd9Sstevel@tonic-gate 	r->recvsize = pr->recvsize;
3527c478bd9Sstevel@tonic-gate 	r->cf_tsdu = pr->cf_tsdu;
3537c478bd9Sstevel@tonic-gate 	r->cf_cache = pr->cf_cache;
3547c478bd9Sstevel@tonic-gate 	r->tcp_flag = pr->tcp_flag;
3557c478bd9Sstevel@tonic-gate 	r->tcp_keepalive = pr->tcp_keepalive;
3567c478bd9Sstevel@tonic-gate 	r->cf_connmaxrec = pr->cf_connmaxrec;
3577c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
3587c478bd9Sstevel@tonic-gate 	r->t_call = (struct t_call *)t_alloc(fd, T_CALL, T_ADDR | T_OPT);
3597c478bd9Sstevel@tonic-gate 	if (r->t_call == NULL) {
3607c478bd9Sstevel@tonic-gate 		svc_vc_xprtfree(xprt);
3617c478bd9Sstevel@tonic-gate 		return (NULL);
3627c478bd9Sstevel@tonic-gate 	}
3637c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
3647c478bd9Sstevel@tonic-gate 	r->t_bind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
3657c478bd9Sstevel@tonic-gate 	if (r->t_bind == NULL) {
3667c478bd9Sstevel@tonic-gate 		svc_vc_xprtfree(xprt);
3677c478bd9Sstevel@tonic-gate 		return (NULL);
3687c478bd9Sstevel@tonic-gate 	}
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	return (xprt);
3717c478bd9Sstevel@tonic-gate }
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate /*
3747c478bd9Sstevel@tonic-gate  * XXX : Used for setting flag to indicate that this is TCP
3757c478bd9Sstevel@tonic-gate  */
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3787c478bd9Sstevel@tonic-gate int
__svc_vc_setflag(SVCXPRT * xprt,int flag)3797c478bd9Sstevel@tonic-gate __svc_vc_setflag(SVCXPRT *xprt, int flag)
3807c478bd9Sstevel@tonic-gate {
3817c478bd9Sstevel@tonic-gate 	struct cf_rendezvous *r;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
3847c478bd9Sstevel@tonic-gate 	r = (struct cf_rendezvous *)xprt->xp_p1;
3857c478bd9Sstevel@tonic-gate 	r->tcp_flag = TRUE;
3867c478bd9Sstevel@tonic-gate 	return (1);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate  * used for the actual connection.
3917c478bd9Sstevel@tonic-gate  */
3927c478bd9Sstevel@tonic-gate SVCXPRT *
svc_fd_create_private(int fd,uint_t sendsize,uint_t recvsize)3937c478bd9Sstevel@tonic-gate svc_fd_create_private(int fd, uint_t sendsize, uint_t recvsize)
3947c478bd9Sstevel@tonic-gate {
3957c478bd9Sstevel@tonic-gate 	struct t_info tinfo;
3967c478bd9Sstevel@tonic-gate 	SVCXPRT *dummy;
3977c478bd9Sstevel@tonic-gate 	struct netbuf tres = {0};
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	if (RPC_FD_NOTIN_FDSET(fd)) {
4007c478bd9Sstevel@tonic-gate 		errno = EBADF;
4017c478bd9Sstevel@tonic-gate 		t_errno = TBADF;
4027c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, errstring,
4037c478bd9Sstevel@tonic-gate 		    svc_fd_create_str, svc_vc_fderr);
40461961e0fSrobinson 		return (NULL);
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 	if (t_getinfo(fd, &tinfo) == -1) {
4077c478bd9Sstevel@tonic-gate 		char errorstr[100];
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 		__tli_sys_strerror(errorstr, sizeof (errorstr),
41013147901SMarcel Telka 		    t_errno, errno);
4117c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "%s : %s : %s",
41213147901SMarcel Telka 		    svc_fd_create_str, no_tinfo_str, errorstr);
41361961e0fSrobinson 		return (NULL);
4147c478bd9Sstevel@tonic-gate 	}
4157c478bd9Sstevel@tonic-gate 	/*
4167c478bd9Sstevel@tonic-gate 	 * Find the receive and the send size
4177c478bd9Sstevel@tonic-gate 	 */
4187c478bd9Sstevel@tonic-gate 	sendsize = __rpc_get_t_size((int)sendsize, tinfo.tsdu);
4197c478bd9Sstevel@tonic-gate 	recvsize = __rpc_get_t_size((int)recvsize, tinfo.tsdu);
4207c478bd9Sstevel@tonic-gate 	if ((sendsize == 0) || (recvsize == 0)) {
4217c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, errstring, svc_fd_create_str,
42213147901SMarcel Telka 		    "transport does not support data transfer");
42361961e0fSrobinson 		return (NULL);
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate 	dummy = makefd_xprt(fd, sendsize, recvsize, tinfo.tsdu, NULL);
4267c478bd9Sstevel@tonic-gate 				/* NULL signifies no dup cache */
4277c478bd9Sstevel@tonic-gate 	/* Assign the local bind address */
4287c478bd9Sstevel@tonic-gate 	if (t_getname(fd, &tres, LOCALNAME) == -1)
4297c478bd9Sstevel@tonic-gate 		tres.len = 0;
4307c478bd9Sstevel@tonic-gate 	dummy->xp_ltaddr = tres;
4317c478bd9Sstevel@tonic-gate 	/* Fill in type of service */
4327c478bd9Sstevel@tonic-gate 	dummy->xp_type = tinfo.servtype;
4337c478bd9Sstevel@tonic-gate 	return (dummy);
4347c478bd9Sstevel@tonic-gate }
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate SVCXPRT *
svc_fd_create(const int fd,const uint_t sendsize,const uint_t recvsize)43761961e0fSrobinson svc_fd_create(const int fd, const uint_t sendsize, const uint_t recvsize)
4387c478bd9Sstevel@tonic-gate {
4397c478bd9Sstevel@tonic-gate 	SVCXPRT *xprt;
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	if ((xprt = svc_fd_create_private(fd, sendsize, recvsize)) != NULL)
4427c478bd9Sstevel@tonic-gate 		xprt_register(xprt);
4437c478bd9Sstevel@tonic-gate 	return (xprt);
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate void
svc_fd_xprtfree(SVCXPRT * xprt)4477c478bd9Sstevel@tonic-gate svc_fd_xprtfree(SVCXPRT *xprt)
4487c478bd9Sstevel@tonic-gate {
4497c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
4507c478bd9Sstevel@tonic-gate 	SVCXPRT_EXT	*xt = xprt ? SVCEXT(xprt) : NULL;
4517c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
4527c478bd9Sstevel@tonic-gate 	struct cf_conn	*cd = xprt ? (struct cf_conn *)xprt->xp_p1 : NULL;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	if (!xprt)
4557c478bd9Sstevel@tonic-gate 		return;
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	if (xprt->xp_tp)
4587c478bd9Sstevel@tonic-gate 		free(xprt->xp_tp);
4597c478bd9Sstevel@tonic-gate 	if (xprt->xp_netid)
4607c478bd9Sstevel@tonic-gate 		free(xprt->xp_netid);
4617c478bd9Sstevel@tonic-gate 	if (xt && (xt->parent == NULL)) {
4627c478bd9Sstevel@tonic-gate 		if (xprt->xp_ltaddr.buf)
4637c478bd9Sstevel@tonic-gate 			free(xprt->xp_ltaddr.buf);
4647c478bd9Sstevel@tonic-gate 		if (xprt->xp_rtaddr.buf)
4657c478bd9Sstevel@tonic-gate 			free(xprt->xp_rtaddr.buf);
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate 	if (cd) {
4687c478bd9Sstevel@tonic-gate 		XDR_DESTROY(&(cd->xdrs));
46961961e0fSrobinson 		free(cd);
4707c478bd9Sstevel@tonic-gate 	}
4717c478bd9Sstevel@tonic-gate 	if (xt && (xt->parent == NULL) && xprt->xp_p2) {
4727c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
47361961e0fSrobinson 		free(((struct netbuf *)xprt->xp_p2)->buf);
47461961e0fSrobinson 		free(xprt->xp_p2);
4757c478bd9Sstevel@tonic-gate 	}
4767c478bd9Sstevel@tonic-gate 	svc_xprt_free(xprt);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate static SVCXPRT *
makefd_xprt(int fd,uint_t sendsize,uint_t recvsize,t_scalar_t tsdu,char * cache)4807c478bd9Sstevel@tonic-gate makefd_xprt(int fd, uint_t sendsize, uint_t recvsize, t_scalar_t tsdu,
4817c478bd9Sstevel@tonic-gate     char *cache)
4827c478bd9Sstevel@tonic-gate {
4837c478bd9Sstevel@tonic-gate 	SVCXPRT *xprt;
4847c478bd9Sstevel@tonic-gate 	struct cf_conn *cd;
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	xprt = svc_xprt_alloc();
48761961e0fSrobinson 	if (xprt == NULL) {
4887c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, errstring, makefd_xprt_str, no_mem_str);
48961961e0fSrobinson 		return (NULL);
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
4927c478bd9Sstevel@tonic-gate 	svc_flags(xprt) |= SVC_CONNECTION;
4937c478bd9Sstevel@tonic-gate 
49461961e0fSrobinson 	cd = malloc(sizeof (struct cf_conn));
49561961e0fSrobinson 	if (cd == NULL) {
4967c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, errstring, makefd_xprt_str, no_mem_str);
4977c478bd9Sstevel@tonic-gate 		svc_fd_xprtfree(xprt);
49861961e0fSrobinson 		return (NULL);
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 	cd->sendsize = sendsize;
5017c478bd9Sstevel@tonic-gate 	cd->recvsize = recvsize;
5027c478bd9Sstevel@tonic-gate 	cd->strm_stat = XPRT_IDLE;
5037c478bd9Sstevel@tonic-gate 	cd->cf_tsdu = tsdu;
5047c478bd9Sstevel@tonic-gate 	cd->cf_cache = cache;
5057c478bd9Sstevel@tonic-gate 	cd->cf_conn_nonblock = FALSE;
5067c478bd9Sstevel@tonic-gate 	cd->cf_conn_nonblock_timestamp = 0;
5077c478bd9Sstevel@tonic-gate 	cd->xdrs.x_ops = NULL;
5087c478bd9Sstevel@tonic-gate 	xdrrec_create(&(cd->xdrs), sendsize, 0, (caddr_t)xprt,
50913147901SMarcel Telka 	    (int(*)())NULL, (int(*)(void *, char *, int))write_vc);
5107c478bd9Sstevel@tonic-gate 	if (cd->xdrs.x_ops == NULL) {
5117c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, errstring, makefd_xprt_str, no_mem_str);
51261961e0fSrobinson 		free(cd);
5137c478bd9Sstevel@tonic-gate 		svc_fd_xprtfree(xprt);
51461961e0fSrobinson 		return (NULL);
5157c478bd9Sstevel@tonic-gate 	}
5167c478bd9Sstevel@tonic-gate 
51761961e0fSrobinson 	(void) rw_wrlock(&svc_fd_lock);
5187c478bd9Sstevel@tonic-gate 	if (svc_xdrs == NULL) {
51961961e0fSrobinson 		svc_xdrs = calloc(FD_INCREMENT,  sizeof (XDR *));
5207c478bd9Sstevel@tonic-gate 		if (svc_xdrs == NULL) {
5217c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR, errstring, makefd_xprt_str,
52213147901SMarcel Telka 			    no_mem_str);
5237c478bd9Sstevel@tonic-gate 			XDR_DESTROY(&(cd->xdrs));
52461961e0fSrobinson 			free(cd);
5257c478bd9Sstevel@tonic-gate 			svc_fd_xprtfree(xprt);
52661961e0fSrobinson 			(void) rw_unlock(&svc_fd_lock);
52761961e0fSrobinson 			return (NULL);
5287c478bd9Sstevel@tonic-gate 		}
5297c478bd9Sstevel@tonic-gate 		nsvc_xdrs = FD_INCREMENT;
5307c478bd9Sstevel@tonic-gate 	}
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	while (fd >= nsvc_xdrs) {
53313147901SMarcel Telka 		XDR **tmp_xdrs = realloc(svc_xdrs,
53413147901SMarcel Telka 		    sizeof (XDR *) * (nsvc_xdrs + FD_INCREMENT));
5357c478bd9Sstevel@tonic-gate 		if (tmp_xdrs == NULL) {
5367c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR, errstring, makefd_xprt_str,
53713147901SMarcel Telka 			    no_mem_str);
5387c478bd9Sstevel@tonic-gate 			XDR_DESTROY(&(cd->xdrs));
53961961e0fSrobinson 			free(cd);
5407c478bd9Sstevel@tonic-gate 			svc_fd_xprtfree(xprt);
54161961e0fSrobinson 			(void) rw_unlock(&svc_fd_lock);
54261961e0fSrobinson 			return (NULL);
5437c478bd9Sstevel@tonic-gate 		}
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 		svc_xdrs = tmp_xdrs;
5467c478bd9Sstevel@tonic-gate 		/* initial the new array to 0 from the last allocated array */
5477c478bd9Sstevel@tonic-gate 		(void) memset(&svc_xdrs[nsvc_xdrs], 0,
54813147901SMarcel Telka 		    sizeof (XDR *) * FD_INCREMENT);
5497c478bd9Sstevel@tonic-gate 		nsvc_xdrs += FD_INCREMENT;
5507c478bd9Sstevel@tonic-gate 	}
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	if (svc_xdrs[fd] != NULL) {
5537c478bd9Sstevel@tonic-gate 		XDR_DESTROY(svc_xdrs[fd]);
5547c478bd9Sstevel@tonic-gate 	} else if ((svc_xdrs[fd] = malloc(sizeof (XDR))) == NULL) {
5557c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, errstring, makefd_xprt_str, no_mem_str);
5567c478bd9Sstevel@tonic-gate 		XDR_DESTROY(&(cd->xdrs));
55761961e0fSrobinson 		free(cd);
5587c478bd9Sstevel@tonic-gate 		svc_fd_xprtfree(xprt);
55961961e0fSrobinson 		(void) rw_unlock(&svc_fd_lock);
56061961e0fSrobinson 		return (NULL);
5617c478bd9Sstevel@tonic-gate 	}
5627c478bd9Sstevel@tonic-gate 	(void) memset(svc_xdrs[fd], 0, sizeof (XDR));
5637c478bd9Sstevel@tonic-gate 	xdrrec_create(svc_xdrs[fd], 0, recvsize, (caddr_t)xprt,
56413147901SMarcel Telka 	    (int(*)(void *, char *, int))read_vc, (int(*)())NULL);
5657c478bd9Sstevel@tonic-gate 	if (svc_xdrs[fd]->x_ops == NULL) {
5667c478bd9Sstevel@tonic-gate 		free(svc_xdrs[fd]);
5677c478bd9Sstevel@tonic-gate 		svc_xdrs[fd] = NULL;
5687c478bd9Sstevel@tonic-gate 		XDR_DESTROY(&(cd->xdrs));
56961961e0fSrobinson 		free(cd);
5707c478bd9Sstevel@tonic-gate 		svc_fd_xprtfree(xprt);
57161961e0fSrobinson 		(void) rw_unlock(&svc_fd_lock);
57261961e0fSrobinson 		return (NULL);
5737c478bd9Sstevel@tonic-gate 	}
57461961e0fSrobinson 	(void) rw_unlock(&svc_fd_lock);
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	xprt->xp_p1 = (caddr_t)cd;
5777c478bd9Sstevel@tonic-gate 	xprt->xp_p2 = NULL;
5787c478bd9Sstevel@tonic-gate 	xprt->xp_verf.oa_base = cd->verf_body;
5797c478bd9Sstevel@tonic-gate 	xprt->xp_ops = svc_vc_ops();	/* truely deals with calls */
5807c478bd9Sstevel@tonic-gate 	xprt->xp_fd = fd;
5817c478bd9Sstevel@tonic-gate 	return (xprt);
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate SVCXPRT *
svc_fd_xprtcopy(SVCXPRT * parent)5857c478bd9Sstevel@tonic-gate svc_fd_xprtcopy(SVCXPRT *parent)
5867c478bd9Sstevel@tonic-gate {
5877c478bd9Sstevel@tonic-gate 	SVCXPRT			*xprt;
5887c478bd9Sstevel@tonic-gate 	struct cf_conn		*cd, *pcd;
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	if ((xprt = svc_xprt_alloc()) == NULL)
5917c478bd9Sstevel@tonic-gate 		return (NULL);
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
5947c478bd9Sstevel@tonic-gate 	SVCEXT(xprt)->parent = parent;
5957c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
5967c478bd9Sstevel@tonic-gate 	SVCEXT(xprt)->flags = SVCEXT(parent)->flags;
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	xprt->xp_fd = parent->xp_fd;
5997c478bd9Sstevel@tonic-gate 	xprt->xp_ops = svc_vc_ops();
6007c478bd9Sstevel@tonic-gate 	if (parent->xp_tp) {
6017c478bd9Sstevel@tonic-gate 		xprt->xp_tp = (char *)strdup(parent->xp_tp);
6027c478bd9Sstevel@tonic-gate 		if (xprt->xp_tp == NULL) {
6037c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "svc_fd_xprtcopy: strdup failed");
6047c478bd9Sstevel@tonic-gate 			svc_fd_xprtfree(xprt);
6057c478bd9Sstevel@tonic-gate 			return (NULL);
6067c478bd9Sstevel@tonic-gate 		}
6077c478bd9Sstevel@tonic-gate 	}
6087c478bd9Sstevel@tonic-gate 	if (parent->xp_netid) {
6097c478bd9Sstevel@tonic-gate 		xprt->xp_netid = (char *)strdup(parent->xp_netid);
6107c478bd9Sstevel@tonic-gate 		if (xprt->xp_netid == NULL) {
6117c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "svc_fd_xprtcopy: strdup failed");
6127c478bd9Sstevel@tonic-gate 			if (xprt->xp_tp)
61361961e0fSrobinson 				free(xprt->xp_tp);
6147c478bd9Sstevel@tonic-gate 			svc_fd_xprtfree(xprt);
6157c478bd9Sstevel@tonic-gate 			return (NULL);
6167c478bd9Sstevel@tonic-gate 		}
6177c478bd9Sstevel@tonic-gate 	}
6187c478bd9Sstevel@tonic-gate 	/*
6197c478bd9Sstevel@tonic-gate 	 * share local and remote addresses with parent
6207c478bd9Sstevel@tonic-gate 	 */
6217c478bd9Sstevel@tonic-gate 	xprt->xp_ltaddr = parent->xp_ltaddr;
6227c478bd9Sstevel@tonic-gate 	xprt->xp_rtaddr = parent->xp_rtaddr;
6237c478bd9Sstevel@tonic-gate 	xprt->xp_type = parent->xp_type;
6247c478bd9Sstevel@tonic-gate 
62561961e0fSrobinson 	if ((cd = malloc(sizeof (struct cf_conn))) == NULL) {
6267c478bd9Sstevel@tonic-gate 		svc_fd_xprtfree(xprt);
6277c478bd9Sstevel@tonic-gate 		return (NULL);
6287c478bd9Sstevel@tonic-gate 	}
6297c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
6307c478bd9Sstevel@tonic-gate 	pcd = (struct cf_conn *)parent->xp_p1;
6317c478bd9Sstevel@tonic-gate 	cd->sendsize = pcd->sendsize;
6327c478bd9Sstevel@tonic-gate 	cd->recvsize = pcd->recvsize;
6337c478bd9Sstevel@tonic-gate 	cd->strm_stat = pcd->strm_stat;
6347c478bd9Sstevel@tonic-gate 	cd->x_id = pcd->x_id;
6357c478bd9Sstevel@tonic-gate 	cd->cf_tsdu = pcd->cf_tsdu;
6367c478bd9Sstevel@tonic-gate 	cd->cf_cache = pcd->cf_cache;
6377c478bd9Sstevel@tonic-gate 	cd->cf_conn_nonblock = pcd->cf_conn_nonblock;
6387c478bd9Sstevel@tonic-gate 	cd->cf_conn_nonblock_timestamp = pcd->cf_conn_nonblock_timestamp;
6397c478bd9Sstevel@tonic-gate 	cd->xdrs.x_ops = NULL;
6407c478bd9Sstevel@tonic-gate 	xdrrec_create(&(cd->xdrs), cd->sendsize, 0, (caddr_t)xprt,
64113147901SMarcel Telka 	    (int(*)())NULL, (int(*)(void *, char *, int))write_vc);
6427c478bd9Sstevel@tonic-gate 	if (cd->xdrs.x_ops == NULL) {
6437c478bd9Sstevel@tonic-gate 		free(cd);
6447c478bd9Sstevel@tonic-gate 		svc_fd_xprtfree(xprt);
6457c478bd9Sstevel@tonic-gate 		return (NULL);
6467c478bd9Sstevel@tonic-gate 	}
6477c478bd9Sstevel@tonic-gate 	xprt->xp_verf.oa_base = cd->verf_body;
6487c478bd9Sstevel@tonic-gate 	xprt->xp_p1 = (char *)cd;
6497c478bd9Sstevel@tonic-gate 	xprt->xp_p2 = parent->xp_p2;	/* shared */
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	return (xprt);
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate 
654d67944fbSScott Rotondo static void do_accept();
655d67944fbSScott Rotondo 
6567c478bd9Sstevel@tonic-gate /*
6577c478bd9Sstevel@tonic-gate  * This routine is called by svc_getreqset(), when a packet is recd.
6587c478bd9Sstevel@tonic-gate  * The listener process creates another end point on which the actual
6597c478bd9Sstevel@tonic-gate  * connection is carried. It returns FALSE to indicate that it was
6607c478bd9Sstevel@tonic-gate  * not a rpc packet (falsely though), but as a side effect creates
6617c478bd9Sstevel@tonic-gate  * another endpoint which is also registered, which then always
6627c478bd9Sstevel@tonic-gate  * has a request ready to be served.
6637c478bd9Sstevel@tonic-gate  */
6647c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
6657c478bd9Sstevel@tonic-gate static bool_t
rendezvous_request(SVCXPRT * xprt,struct rpc_msg * msg)6667c478bd9Sstevel@tonic-gate rendezvous_request(SVCXPRT *xprt, struct rpc_msg *msg)
6677c478bd9Sstevel@tonic-gate {
6687c478bd9Sstevel@tonic-gate 	struct cf_rendezvous *r;
6697c478bd9Sstevel@tonic-gate 	char *tpname = NULL;
6707c478bd9Sstevel@tonic-gate 	char devbuf[256];
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
6737c478bd9Sstevel@tonic-gate 	r = (struct cf_rendezvous *)xprt->xp_p1;
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate again:
6767c478bd9Sstevel@tonic-gate 	switch (t_look(xprt->xp_fd)) {
6777c478bd9Sstevel@tonic-gate 	case T_DISCONNECT:
6787c478bd9Sstevel@tonic-gate 		(void) t_rcvdis(xprt->xp_fd, NULL);
6797c478bd9Sstevel@tonic-gate 		return (FALSE);
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	case T_LISTEN:
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 		if (t_listen(xprt->xp_fd, r->t_call) == -1) {
6847c478bd9Sstevel@tonic-gate 			if ((t_errno == TSYSERR) && (errno == EINTR))
6857c478bd9Sstevel@tonic-gate 				goto again;
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 			if (t_errno == TLOOK) {
6887c478bd9Sstevel@tonic-gate 				if (t_look(xprt->xp_fd) == T_DISCONNECT)
68913147901SMarcel Telka 					(void) t_rcvdis(xprt->xp_fd, NULL);
6907c478bd9Sstevel@tonic-gate 			}
6917c478bd9Sstevel@tonic-gate 			return (FALSE);
6927c478bd9Sstevel@tonic-gate 		}
6937c478bd9Sstevel@tonic-gate 		break;
6947c478bd9Sstevel@tonic-gate 	default:
6957c478bd9Sstevel@tonic-gate 		return (FALSE);
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate 	/*
6987c478bd9Sstevel@tonic-gate 	 * Now create another endpoint, and accept the connection
6997c478bd9Sstevel@tonic-gate 	 * on it.
7007c478bd9Sstevel@tonic-gate 	 */
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	if (xprt->xp_tp) {
7037c478bd9Sstevel@tonic-gate 		tpname = xprt->xp_tp;
7047c478bd9Sstevel@tonic-gate 	} else {
7057c478bd9Sstevel@tonic-gate 		/*
7067c478bd9Sstevel@tonic-gate 		 * If xprt->xp_tp is NULL, then try to extract the
7077c478bd9Sstevel@tonic-gate 		 * transport protocol information from the transport
7087c478bd9Sstevel@tonic-gate 		 * protcol corresponding to xprt->xp_fd
7097c478bd9Sstevel@tonic-gate 		 */
7107c478bd9Sstevel@tonic-gate 		struct netconfig *nconf;
7117c478bd9Sstevel@tonic-gate 		tpname = devbuf;
7127c478bd9Sstevel@tonic-gate 		if ((nconf = __rpcfd_to_nconf(xprt->xp_fd, xprt->xp_type))
71313147901SMarcel Telka 		    == NULL) {
7147c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR, errstring,
71513147901SMarcel Telka 			    rendezvous_request_str, "no suitable transport");
7167c478bd9Sstevel@tonic-gate 			goto err;
7177c478bd9Sstevel@tonic-gate 		}
71861961e0fSrobinson 		(void) strcpy(tpname, nconf->nc_device);
7197c478bd9Sstevel@tonic-gate 		freenetconfigent(nconf);
7207c478bd9Sstevel@tonic-gate 	}
7217c478bd9Sstevel@tonic-gate 
72213147901SMarcel Telka 	do_accept(xprt->xp_fd, tpname, xprt->xp_netid, r);
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate err:
7257c478bd9Sstevel@tonic-gate 	return (FALSE); /* there is never an rpc msg to be processed */
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate 
72813147901SMarcel Telka struct entry {
72913147901SMarcel Telka 	struct t_call *t_call;
73013147901SMarcel Telka 	struct entry *next;
73113147901SMarcel Telka };
73213147901SMarcel Telka 
7337c478bd9Sstevel@tonic-gate static void
do_accept(int srcfd,char * tpname,char * netid,struct cf_rendezvous * r)73413147901SMarcel Telka do_accept(int srcfd, char *tpname, char *netid, struct cf_rendezvous *r)
7357c478bd9Sstevel@tonic-gate {
7367c478bd9Sstevel@tonic-gate 	int	destfd;
7377c478bd9Sstevel@tonic-gate 	struct t_call	t_call;
73861961e0fSrobinson 	struct t_call	*tcp2 = NULL;
7397c478bd9Sstevel@tonic-gate 	struct t_info	tinfo;
74013147901SMarcel Telka 	SVCXPRT	*xprt;
74113147901SMarcel Telka 	SVCXPRT	*xprt_srcfd;
74213147901SMarcel Telka 	struct entry *head = NULL;
74313147901SMarcel Telka 	struct entry *tail = NULL;
74413147901SMarcel Telka 	struct entry *e;
74513147901SMarcel Telka 	struct t_call *tcp;
74613147901SMarcel Telka 
74713147901SMarcel Telka restart:
74813147901SMarcel Telka 	tcp = r->t_call;
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	destfd = t_open(tpname, O_RDWR, &tinfo);
7517c478bd9Sstevel@tonic-gate 	if (check_nonblock_timestamps) {
7527c478bd9Sstevel@tonic-gate 		if (destfd == -1 && t_errno == TSYSERR && errno == EMFILE) {
7537c478bd9Sstevel@tonic-gate 			/*
7547c478bd9Sstevel@tonic-gate 			 * Since there are nonblocking connection xprts and
7557c478bd9Sstevel@tonic-gate 			 * too many open files, the LRU connection xprt should
7567c478bd9Sstevel@tonic-gate 			 * get destroyed in case an attacker has been creating
7577c478bd9Sstevel@tonic-gate 			 * many connections.
7587c478bd9Sstevel@tonic-gate 			 */
75961961e0fSrobinson 			(void) mutex_lock(&svc_mutex);
7607c478bd9Sstevel@tonic-gate 			svc_timeout_nonblock_xprt_and_LRU(TRUE);
76161961e0fSrobinson 			(void) mutex_unlock(&svc_mutex);
7627c478bd9Sstevel@tonic-gate 			destfd = t_open(tpname, O_RDWR, &tinfo);
7637c478bd9Sstevel@tonic-gate 		} else {
7647c478bd9Sstevel@tonic-gate 			/*
7657c478bd9Sstevel@tonic-gate 			 * Destroy/timeout all nonblock connection xprts
7667c478bd9Sstevel@tonic-gate 			 * that have not had recent activity.
7677c478bd9Sstevel@tonic-gate 			 * Do not destroy LRU xprt unless there are
7687c478bd9Sstevel@tonic-gate 			 * too many open files.
7697c478bd9Sstevel@tonic-gate 			 */
77061961e0fSrobinson 			(void) mutex_lock(&svc_mutex);
7717c478bd9Sstevel@tonic-gate 			svc_timeout_nonblock_xprt_and_LRU(FALSE);
77261961e0fSrobinson 			(void) mutex_unlock(&svc_mutex);
7737c478bd9Sstevel@tonic-gate 		}
7747c478bd9Sstevel@tonic-gate 	}
7757c478bd9Sstevel@tonic-gate 	if (destfd == -1) {
7767c478bd9Sstevel@tonic-gate 		char errorstr[100];
7777c478bd9Sstevel@tonic-gate 
77813147901SMarcel Telka 		__tli_sys_strerror(errorstr, sizeof (errorstr), t_errno, errno);
7797c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "%s : %s : %s", do_accept_str,
78013147901SMarcel Telka 		    "can't open connection", errorstr);
7817c478bd9Sstevel@tonic-gate 		(void) t_snddis(srcfd, tcp);
78213147901SMarcel Telka 
78313147901SMarcel Telka 		goto end;
78461961e0fSrobinson 	}
7857c478bd9Sstevel@tonic-gate 	if (RPC_FD_NOTIN_FDSET(destfd)) {
78613147901SMarcel Telka 		(void) syslog(LOG_ERR, errstring, do_accept_str, svc_vc_fderr);
7877c478bd9Sstevel@tonic-gate 		(void) t_close(destfd);
7887c478bd9Sstevel@tonic-gate 		(void) t_snddis(srcfd, tcp);
78913147901SMarcel Telka 
79013147901SMarcel Telka 		goto end;
7917c478bd9Sstevel@tonic-gate 	}
79213147901SMarcel Telka 	(void) fcntl(destfd, F_SETFD, FD_CLOEXEC);
7937c478bd9Sstevel@tonic-gate 	if ((tinfo.servtype != T_COTS) && (tinfo.servtype != T_COTS_ORD)) {
7947c478bd9Sstevel@tonic-gate 		/* Not a connection oriented mode */
7957c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, errstring, do_accept_str,
79613147901SMarcel Telka 		    "do_accept:  illegal transport");
7977c478bd9Sstevel@tonic-gate 		(void) t_close(destfd);
7987c478bd9Sstevel@tonic-gate 		(void) t_snddis(srcfd, tcp);
79913147901SMarcel Telka 
80013147901SMarcel Telka 		goto end;
8017c478bd9Sstevel@tonic-gate 	}
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 
80461961e0fSrobinson 	if (t_bind(destfd, NULL, r->t_bind) == -1) {
8057c478bd9Sstevel@tonic-gate 		char errorstr[100];
8067c478bd9Sstevel@tonic-gate 
80713147901SMarcel Telka 		__tli_sys_strerror(errorstr, sizeof (errorstr), t_errno, errno);
8087c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, " %s : %s : %s", do_accept_str,
80913147901SMarcel Telka 		    "t_bind failed", errorstr);
8107c478bd9Sstevel@tonic-gate 		(void) t_close(destfd);
8117c478bd9Sstevel@tonic-gate 		(void) t_snddis(srcfd, tcp);
81213147901SMarcel Telka 
81313147901SMarcel Telka 		goto end;
8147c478bd9Sstevel@tonic-gate 	}
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	if (r->tcp_flag)	/* if TCP, set NODELAY flag */
81761961e0fSrobinson 		(void) __td_setnodelay(destfd);
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	/*
8207c478bd9Sstevel@tonic-gate 	 * This connection is not listening, hence no need to set
8217c478bd9Sstevel@tonic-gate 	 * the qlen.
8227c478bd9Sstevel@tonic-gate 	 */
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	/*
8257c478bd9Sstevel@tonic-gate 	 * XXX: The local transport chokes on its own listen
8267c478bd9Sstevel@tonic-gate 	 * options so we zero them for now
8277c478bd9Sstevel@tonic-gate 	 */
8287c478bd9Sstevel@tonic-gate 	t_call = *tcp;
8297c478bd9Sstevel@tonic-gate 	t_call.opt.len = 0;
8307c478bd9Sstevel@tonic-gate 	t_call.opt.maxlen = 0;
83161961e0fSrobinson 	t_call.opt.buf = NULL;
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 	while (t_accept(srcfd, destfd, &t_call) == -1) {
8347c478bd9Sstevel@tonic-gate 		char errorstr[100];
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 		switch (t_errno) {
8377c478bd9Sstevel@tonic-gate 		case TLOOK:
8387c478bd9Sstevel@tonic-gate again:
8397c478bd9Sstevel@tonic-gate 			switch (t_look(srcfd)) {
8407c478bd9Sstevel@tonic-gate 			case T_CONNECT:
8417c478bd9Sstevel@tonic-gate 			case T_DATA:
8427c478bd9Sstevel@tonic-gate 			case T_EXDATA:
8437c478bd9Sstevel@tonic-gate 				/* this should not happen */
8447c478bd9Sstevel@tonic-gate 				break;
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 			case T_DISCONNECT:
84761961e0fSrobinson 				(void) t_rcvdis(srcfd, NULL);
8487c478bd9Sstevel@tonic-gate 				break;
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 			case T_LISTEN:
85161961e0fSrobinson 				if (tcp2 == NULL)
8527c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
8537c478bd9Sstevel@tonic-gate 					tcp2 = (struct t_call *)t_alloc(srcfd,
8547c478bd9Sstevel@tonic-gate 					    T_CALL, T_ADDR | T_OPT);
85561961e0fSrobinson 				if (tcp2 == NULL) {
8567c478bd9Sstevel@tonic-gate 					(void) t_close(destfd);
8577c478bd9Sstevel@tonic-gate 					(void) t_snddis(srcfd, tcp);
8587c478bd9Sstevel@tonic-gate 					syslog(LOG_ERR, errstring,
85913147901SMarcel Telka 					    do_accept_str, no_mem_str);
86013147901SMarcel Telka 
86113147901SMarcel Telka 					goto end;
8627c478bd9Sstevel@tonic-gate 				}
8637c478bd9Sstevel@tonic-gate 				if (t_listen(srcfd, tcp2) == -1) {
8647c478bd9Sstevel@tonic-gate 					switch (t_errno) {
8657c478bd9Sstevel@tonic-gate 					case TSYSERR:
8667c478bd9Sstevel@tonic-gate 						if (errno == EINTR)
8677c478bd9Sstevel@tonic-gate 							goto again;
8687c478bd9Sstevel@tonic-gate 						break;
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 					case TLOOK:
8717c478bd9Sstevel@tonic-gate 						goto again;
8727c478bd9Sstevel@tonic-gate 					}
8737c478bd9Sstevel@tonic-gate 					(void) t_close(destfd);
8747c478bd9Sstevel@tonic-gate 					(void) t_snddis(srcfd, tcp);
87513147901SMarcel Telka 
87613147901SMarcel Telka 					goto end;
8777c478bd9Sstevel@tonic-gate 				}
87813147901SMarcel Telka 
87913147901SMarcel Telka 				e = malloc(sizeof (struct entry));
88013147901SMarcel Telka 				if (e == NULL) {
88113147901SMarcel Telka 					(void) t_snddis(srcfd, tcp2);
88213147901SMarcel Telka 					(void) t_free((char *)tcp2, T_CALL);
88313147901SMarcel Telka 					tcp2 = NULL;
88413147901SMarcel Telka 
88513147901SMarcel Telka 					break;
88613147901SMarcel Telka 				}
88713147901SMarcel Telka 
88813147901SMarcel Telka 				e->t_call = tcp2;
88913147901SMarcel Telka 				tcp2 = NULL;
89013147901SMarcel Telka 				e->next = NULL;
89113147901SMarcel Telka 
89213147901SMarcel Telka 				if (head == NULL)
89313147901SMarcel Telka 					head = e;
89413147901SMarcel Telka 				else
89513147901SMarcel Telka 					tail->next = e;
89613147901SMarcel Telka 				tail = e;
89713147901SMarcel Telka 
8987c478bd9Sstevel@tonic-gate 				break;
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 			case T_ORDREL:
9017c478bd9Sstevel@tonic-gate 				(void) t_rcvrel(srcfd);
9027c478bd9Sstevel@tonic-gate 				(void) t_sndrel(srcfd);
9037c478bd9Sstevel@tonic-gate 				break;
9047c478bd9Sstevel@tonic-gate 			}
9057c478bd9Sstevel@tonic-gate 			break;
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 		case TBADSEQ:
9087c478bd9Sstevel@tonic-gate 			/*
9097c478bd9Sstevel@tonic-gate 			 * This can happen if the remote side has
9107c478bd9Sstevel@tonic-gate 			 * disconnected before the connection is
9117c478bd9Sstevel@tonic-gate 			 * accepted.  In this case, a disconnect
9127c478bd9Sstevel@tonic-gate 			 * should not be sent on srcfd (important!
9137c478bd9Sstevel@tonic-gate 			 * the listening fd will be hosed otherwise!).
9147c478bd9Sstevel@tonic-gate 			 * This error is not logged since this is an
9157c478bd9Sstevel@tonic-gate 			 * operational situation that is recoverable.
9167c478bd9Sstevel@tonic-gate 			 */
9177c478bd9Sstevel@tonic-gate 			(void) t_close(destfd);
91813147901SMarcel Telka 
91913147901SMarcel Telka 			goto end;
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 		case TOUTSTATE:
9227c478bd9Sstevel@tonic-gate 			/*
9237c478bd9Sstevel@tonic-gate 			 * This can happen if the t_rcvdis() or t_rcvrel()/
9247c478bd9Sstevel@tonic-gate 			 * t_sndrel() put srcfd into the T_IDLE state.
9257c478bd9Sstevel@tonic-gate 			 */
9267c478bd9Sstevel@tonic-gate 			if (t_getstate(srcfd) == T_IDLE) {
9277c478bd9Sstevel@tonic-gate 				(void) t_close(destfd);
9287c478bd9Sstevel@tonic-gate 				(void) t_snddis(srcfd, tcp);
92913147901SMarcel Telka 
93013147901SMarcel Telka 				goto end;
9317c478bd9Sstevel@tonic-gate 			}
932*a69e76caSToomas Soome 			/* FALLTHROUGH */
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 		default:
9357c478bd9Sstevel@tonic-gate 			__tli_sys_strerror(errorstr, sizeof (errorstr),
93613147901SMarcel Telka 			    t_errno, errno);
9377c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
9387c478bd9Sstevel@tonic-gate 			    "cannot accept connection:  %s (current state %d)",
9397c478bd9Sstevel@tonic-gate 			    errorstr, t_getstate(srcfd));
9407c478bd9Sstevel@tonic-gate 			(void) t_close(destfd);
9417c478bd9Sstevel@tonic-gate 			(void) t_snddis(srcfd, tcp);
94213147901SMarcel Telka 
94313147901SMarcel Telka 			goto end;
9447c478bd9Sstevel@tonic-gate 		}
9457c478bd9Sstevel@tonic-gate 	}
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 	if (r->tcp_flag && r->tcp_keepalive) {
94813147901SMarcel Telka 		char *option;
94913147901SMarcel Telka 		char *option_ret;
95013147901SMarcel Telka 
95161961e0fSrobinson 		option = malloc(sizeof (struct opthdr) + sizeof (int));
95261961e0fSrobinson 		option_ret = malloc(sizeof (struct opthdr) + sizeof (int));
95313147901SMarcel Telka 		if (option != NULL && option_ret != NULL) {
95413147901SMarcel Telka 			struct opthdr *opt;
95513147901SMarcel Telka 			struct t_optmgmt optreq, optret;
95613147901SMarcel Telka 			int *p_optval;
95713147901SMarcel Telka 
95861961e0fSrobinson 			/* LINTED pointer cast */
9597c478bd9Sstevel@tonic-gate 			opt = (struct opthdr *)option;
9607c478bd9Sstevel@tonic-gate 			opt->level = SOL_SOCKET;
9617c478bd9Sstevel@tonic-gate 			opt->name  = SO_KEEPALIVE;
9627c478bd9Sstevel@tonic-gate 			opt->len  = sizeof (int);
9637c478bd9Sstevel@tonic-gate 			p_optval = (int *)(opt + 1);
9647c478bd9Sstevel@tonic-gate 			*p_optval = SO_KEEPALIVE;
9657c478bd9Sstevel@tonic-gate 			optreq.opt.maxlen = optreq.opt.len =
96613147901SMarcel Telka 			    sizeof (struct opthdr) + sizeof (int);
9677c478bd9Sstevel@tonic-gate 			optreq.opt.buf = (char *)option;
9687c478bd9Sstevel@tonic-gate 			optreq.flags = T_NEGOTIATE;
9697c478bd9Sstevel@tonic-gate 			optret.opt.maxlen = sizeof (struct opthdr)
97013147901SMarcel Telka 			    + sizeof (int);
9717c478bd9Sstevel@tonic-gate 			optret.opt.buf = (char *)option_ret;
97261961e0fSrobinson 			(void) t_optmgmt(destfd, &optreq, &optret);
9737c478bd9Sstevel@tonic-gate 		}
97413147901SMarcel Telka 		free(option);
97513147901SMarcel Telka 		free(option_ret);
9767c478bd9Sstevel@tonic-gate 	}
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	/*
9807c478bd9Sstevel@tonic-gate 	 * make a new transporter
9817c478bd9Sstevel@tonic-gate 	 */
9827c478bd9Sstevel@tonic-gate 	xprt = makefd_xprt(destfd, r->sendsize, r->recvsize, r->cf_tsdu,
98313147901SMarcel Telka 	    r->cf_cache);
98461961e0fSrobinson 	if (xprt == NULL) {
9857c478bd9Sstevel@tonic-gate 		/*
9867c478bd9Sstevel@tonic-gate 		 * makefd_xprt() returns a NULL xprt only when
9877c478bd9Sstevel@tonic-gate 		 * it's out of memory.
9887c478bd9Sstevel@tonic-gate 		 */
9897c478bd9Sstevel@tonic-gate 		goto memerr;
9907c478bd9Sstevel@tonic-gate 	}
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	/*
9937c478bd9Sstevel@tonic-gate 	 * Copy the new local and remote bind information
9947c478bd9Sstevel@tonic-gate 	 */
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	xprt->xp_rtaddr.len = tcp->addr.len;
9977c478bd9Sstevel@tonic-gate 	xprt->xp_rtaddr.maxlen = tcp->addr.len;
9987c478bd9Sstevel@tonic-gate 	if ((xprt->xp_rtaddr.buf = malloc(tcp->addr.len)) == NULL)
9997c478bd9Sstevel@tonic-gate 		goto memerr;
100061961e0fSrobinson 	(void) memcpy(xprt->xp_rtaddr.buf, tcp->addr.buf, tcp->addr.len);
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	if (strcmp(netid, "tcp") == 0) {
10037c478bd9Sstevel@tonic-gate 		xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_in);
10047c478bd9Sstevel@tonic-gate 		if ((xprt->xp_ltaddr.buf =
100513147901SMarcel Telka 		    malloc(xprt->xp_ltaddr.maxlen)) == NULL)
10067c478bd9Sstevel@tonic-gate 			goto memerr;
10077c478bd9Sstevel@tonic-gate 		if (t_getname(destfd, &xprt->xp_ltaddr, LOCALNAME) < 0) {
100813147901SMarcel Telka 			(void) syslog(LOG_ERR,
100913147901SMarcel Telka 			    "do_accept: t_getname for tcp failed!");
10107c478bd9Sstevel@tonic-gate 			goto xprt_err;
10117c478bd9Sstevel@tonic-gate 		}
10127c478bd9Sstevel@tonic-gate 	} else if (strcmp(netid, "tcp6") == 0) {
10137c478bd9Sstevel@tonic-gate 		xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_in6);
10147c478bd9Sstevel@tonic-gate 		if ((xprt->xp_ltaddr.buf =
101513147901SMarcel Telka 		    malloc(xprt->xp_ltaddr.maxlen)) == NULL)
10167c478bd9Sstevel@tonic-gate 			goto memerr;
10177c478bd9Sstevel@tonic-gate 		if (t_getname(destfd, &xprt->xp_ltaddr, LOCALNAME) < 0) {
10187c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
101913147901SMarcel Telka 			    "do_accept: t_getname for tcp6 failed!");
10207c478bd9Sstevel@tonic-gate 			goto xprt_err;
10217c478bd9Sstevel@tonic-gate 		}
10227c478bd9Sstevel@tonic-gate 	}
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	xprt->xp_tp = strdup(tpname);
10257c478bd9Sstevel@tonic-gate 	xprt->xp_netid = strdup(netid);
102661961e0fSrobinson 	if ((xprt->xp_tp == NULL) ||
102761961e0fSrobinson 	    (xprt->xp_netid == NULL)) {
10287c478bd9Sstevel@tonic-gate 		goto memerr;
10297c478bd9Sstevel@tonic-gate 	}
10307c478bd9Sstevel@tonic-gate 	if (tcp->opt.len > 0) {
10317c478bd9Sstevel@tonic-gate 		xprt->xp_p2 = malloc(sizeof (struct netbuf));
10327c478bd9Sstevel@tonic-gate 
103361961e0fSrobinson 		if (xprt->xp_p2 != NULL) {
10347c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
103513147901SMarcel Telka 			struct netbuf *netptr = (struct netbuf *)xprt->xp_p2;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 			netptr->len = tcp->opt.len;
10387c478bd9Sstevel@tonic-gate 			netptr->maxlen = tcp->opt.len;
10397c478bd9Sstevel@tonic-gate 			if ((netptr->buf = malloc(tcp->opt.len)) == NULL)
10407c478bd9Sstevel@tonic-gate 				goto memerr;
104161961e0fSrobinson 			(void) memcpy(netptr->buf, tcp->opt.buf, tcp->opt.len);
10427c478bd9Sstevel@tonic-gate 		} else
10437c478bd9Sstevel@tonic-gate 			goto memerr;
10447c478bd9Sstevel@tonic-gate 	}
104561961e0fSrobinson /*	(void) ioctl(destfd, I_POP, NULL);    */
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 	/*
10487c478bd9Sstevel@tonic-gate 	 * If a nonblocked connection fd has been requested,
10497c478bd9Sstevel@tonic-gate 	 * perform the necessary operations.
10507c478bd9Sstevel@tonic-gate 	 */
10517c478bd9Sstevel@tonic-gate 	xprt_srcfd = svc_xports[srcfd];
105261961e0fSrobinson 	/* LINTED pointer cast */
10537c478bd9Sstevel@tonic-gate 	if (((struct cf_rendezvous *)(xprt_srcfd->xp_p1))->cf_connmaxrec) {
10547c478bd9Sstevel@tonic-gate 		if (!svc_vc_nonblock(xprt_srcfd, xprt))
10557c478bd9Sstevel@tonic-gate 			goto xprt_err;
10567c478bd9Sstevel@tonic-gate 	}
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 	/*
10597c478bd9Sstevel@tonic-gate 	 * Copy the call back declared for the service to the current
10607c478bd9Sstevel@tonic-gate 	 * connection
10617c478bd9Sstevel@tonic-gate 	 */
10627c478bd9Sstevel@tonic-gate 	xprt->xp_closeclnt = xprt_srcfd->xp_closeclnt;
10637c478bd9Sstevel@tonic-gate 	xprt_register(xprt);
10647c478bd9Sstevel@tonic-gate 
106513147901SMarcel Telka end:
106613147901SMarcel Telka 	if (head != NULL) {
106713147901SMarcel Telka 		(void) t_free((char *)r->t_call, T_CALL);
106813147901SMarcel Telka 		r->t_call = head->t_call;
106913147901SMarcel Telka 		e = head;
107013147901SMarcel Telka 		head = head->next;
107113147901SMarcel Telka 		free(e);
107213147901SMarcel Telka 		goto restart;
107313147901SMarcel Telka 	}
107413147901SMarcel Telka 
107513147901SMarcel Telka 	if (tcp2)
107613147901SMarcel Telka 		(void) t_free((char *)tcp2, T_CALL);
107713147901SMarcel Telka 
10787c478bd9Sstevel@tonic-gate 	return;
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate memerr:
10817c478bd9Sstevel@tonic-gate 	(void) syslog(LOG_ERR, errstring, do_accept_str, no_mem_str);
10827c478bd9Sstevel@tonic-gate xprt_err:
10837c478bd9Sstevel@tonic-gate 	if (xprt)
10847c478bd9Sstevel@tonic-gate 		svc_vc_destroy(xprt);
10857c478bd9Sstevel@tonic-gate 	(void) t_close(destfd);
108613147901SMarcel Telka 
108713147901SMarcel Telka 	goto end;
10887c478bd9Sstevel@tonic-gate }
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate /*
10917c478bd9Sstevel@tonic-gate  * This routine performs the necessary fcntl() operations to create
10927c478bd9Sstevel@tonic-gate  * a nonblocked connection fd.
10937c478bd9Sstevel@tonic-gate  * It also adjusts the sizes and allocates the buffer
10947c478bd9Sstevel@tonic-gate  * for the nonblocked operations, and updates the associated
10957c478bd9Sstevel@tonic-gate  * timestamp field in struct cf_conn for timeout bookkeeping.
10967c478bd9Sstevel@tonic-gate  */
10977c478bd9Sstevel@tonic-gate static bool_t
svc_vc_nonblock(SVCXPRT * xprt_rendezvous,SVCXPRT * xprt_conn)10987c478bd9Sstevel@tonic-gate svc_vc_nonblock(SVCXPRT *xprt_rendezvous, SVCXPRT *xprt_conn)
10997c478bd9Sstevel@tonic-gate {
11007c478bd9Sstevel@tonic-gate 	int nn;
11017c478bd9Sstevel@tonic-gate 	int fdconn = xprt_conn->xp_fd;
11027c478bd9Sstevel@tonic-gate 	struct cf_rendezvous *r =
110313147901SMarcel Telka 	    /* LINTED pointer cast */
110413147901SMarcel Telka 	    (struct cf_rendezvous *)xprt_rendezvous->xp_p1;
110561961e0fSrobinson 	/* LINTED pointer cast */
11067c478bd9Sstevel@tonic-gate 	struct cf_conn *cd = (struct cf_conn *)xprt_conn->xp_p1;
11077c478bd9Sstevel@tonic-gate 	uint32_t maxrecsz;
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	if ((nn = fcntl(fdconn, F_GETFL, 0)) < 0) {
11107c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "%s : %s : %m", do_accept_str,
111113147901SMarcel Telka 		    no_fcntl_getfl_str);
11127c478bd9Sstevel@tonic-gate 		return (FALSE);
11137c478bd9Sstevel@tonic-gate 	}
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	if (fcntl(fdconn, F_SETFL, nn|O_NONBLOCK) != 0) {
11167c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "%s : %s : %m", do_accept_str,
111713147901SMarcel Telka 		    no_nonblock_str);
11187c478bd9Sstevel@tonic-gate 		return (FALSE);
11197c478bd9Sstevel@tonic-gate 	}
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 	cd->cf_conn_nonblock = TRUE;
11227c478bd9Sstevel@tonic-gate 	/*
11237c478bd9Sstevel@tonic-gate 	 * If the max fragment size has not been set via
11247c478bd9Sstevel@tonic-gate 	 * rpc_control(), use the default.
11257c478bd9Sstevel@tonic-gate 	 */
11267c478bd9Sstevel@tonic-gate 	if ((maxrecsz = r->cf_connmaxrec) == 0)
11277c478bd9Sstevel@tonic-gate 		maxrecsz = r->recvsize;
11287c478bd9Sstevel@tonic-gate 	/* Set XDR stream to use non-blocking semantics. */
11297c478bd9Sstevel@tonic-gate 	if (__xdrrec_set_conn_nonblock(svc_xdrs[fdconn], maxrecsz)) {
11307c478bd9Sstevel@tonic-gate 		check_nonblock_timestamps = TRUE;
11317c478bd9Sstevel@tonic-gate 		update_nonblock_timestamps(xprt_conn);
11327c478bd9Sstevel@tonic-gate 		return (TRUE);
11337c478bd9Sstevel@tonic-gate 	}
11347c478bd9Sstevel@tonic-gate 	return (FALSE);
11357c478bd9Sstevel@tonic-gate }
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate /* ARGSUSED */
11387c478bd9Sstevel@tonic-gate static enum xprt_stat
rendezvous_stat(SVCXPRT * xprt)11397c478bd9Sstevel@tonic-gate rendezvous_stat(SVCXPRT *xprt)
11407c478bd9Sstevel@tonic-gate {
11417c478bd9Sstevel@tonic-gate 	return (XPRT_IDLE);
11427c478bd9Sstevel@tonic-gate }
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate static void
svc_vc_destroy(SVCXPRT * xprt)11457c478bd9Sstevel@tonic-gate svc_vc_destroy(SVCXPRT *xprt)
11467c478bd9Sstevel@tonic-gate {
114761961e0fSrobinson 	(void) mutex_lock(&svc_mutex);
11487c478bd9Sstevel@tonic-gate 	_svc_vc_destroy_private(xprt, TRUE);
11497c478bd9Sstevel@tonic-gate 	(void) svc_timeout_nonblock_xprt_and_LRU(FALSE);
115061961e0fSrobinson 	(void) mutex_unlock(&svc_mutex);
11517c478bd9Sstevel@tonic-gate }
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate void
_svc_vc_destroy_private(SVCXPRT * xprt,bool_t lock_not_held)11547c478bd9Sstevel@tonic-gate _svc_vc_destroy_private(SVCXPRT *xprt, bool_t lock_not_held)
11557c478bd9Sstevel@tonic-gate {
11567c478bd9Sstevel@tonic-gate 	if (svc_mt_mode != RPC_SVC_MT_NONE) {
11577c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
11587c478bd9Sstevel@tonic-gate 		if (SVCEXT(xprt)->parent)
11597c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
11607c478bd9Sstevel@tonic-gate 			xprt = SVCEXT(xprt)->parent;
11617c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
11627c478bd9Sstevel@tonic-gate 		svc_flags(xprt) |= SVC_DEFUNCT;
11637c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
11647c478bd9Sstevel@tonic-gate 		if (SVCEXT(xprt)->refcnt > 0)
11657c478bd9Sstevel@tonic-gate 			return;
11667c478bd9Sstevel@tonic-gate 	}
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 	if (xprt->xp_closeclnt != NULL) {
11697c478bd9Sstevel@tonic-gate 		svc_errorhandler_t cb = xprt->xp_closeclnt;
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 		/*
11727c478bd9Sstevel@tonic-gate 		 * Reset the pointer here to avoid reentrance on the same
11737c478bd9Sstevel@tonic-gate 		 * SVCXPRT handle.
11747c478bd9Sstevel@tonic-gate 		 */
11757c478bd9Sstevel@tonic-gate 		xprt->xp_closeclnt = NULL;
11767c478bd9Sstevel@tonic-gate 		cb(xprt, (xprt->xp_rtaddr.len != 0));
11777c478bd9Sstevel@tonic-gate 	}
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 	__xprt_unregister_private(xprt, lock_not_held);
118061961e0fSrobinson 	(void) t_close(xprt->xp_fd);
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	if (svc_mt_mode != RPC_SVC_MT_NONE) {
11837c478bd9Sstevel@tonic-gate 		svc_xprt_destroy(xprt);
11847c478bd9Sstevel@tonic-gate 	} else {
11857c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
11867c478bd9Sstevel@tonic-gate 		if (svc_type(xprt) == SVC_RENDEZVOUS)
11877c478bd9Sstevel@tonic-gate 			svc_vc_xprtfree(xprt);
11887c478bd9Sstevel@tonic-gate 		else
11897c478bd9Sstevel@tonic-gate 			svc_fd_xprtfree(xprt);
11907c478bd9Sstevel@tonic-gate 	}
11917c478bd9Sstevel@tonic-gate }
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11947c478bd9Sstevel@tonic-gate static bool_t
svc_vc_control(SVCXPRT * xprt,const uint_t rq,void * in)11957c478bd9Sstevel@tonic-gate svc_vc_control(SVCXPRT *xprt, const uint_t rq, void *in)
11967c478bd9Sstevel@tonic-gate {
11977c478bd9Sstevel@tonic-gate 	switch (rq) {
11987c478bd9Sstevel@tonic-gate 	case SVCSET_RECVERRHANDLER:
11997c478bd9Sstevel@tonic-gate 		xprt->xp_closeclnt = (svc_errorhandler_t)in;
12007c478bd9Sstevel@tonic-gate 		return (TRUE);
12017c478bd9Sstevel@tonic-gate 	case SVCGET_RECVERRHANDLER:
12027c478bd9Sstevel@tonic-gate 		*(svc_errorhandler_t *)in = xprt->xp_closeclnt;
12037c478bd9Sstevel@tonic-gate 		return (TRUE);
12047c478bd9Sstevel@tonic-gate 	case SVCGET_XID:
120561961e0fSrobinson 		if (xprt->xp_p1 == NULL)
12067c478bd9Sstevel@tonic-gate 			return (FALSE);
120761961e0fSrobinson 		/* LINTED pointer alignment */
120861961e0fSrobinson 		*(uint32_t *)in = ((struct cf_conn *)(xprt->xp_p1))->x_id;
120961961e0fSrobinson 		return (TRUE);
12107c478bd9Sstevel@tonic-gate 	default:
12117c478bd9Sstevel@tonic-gate 		return (FALSE);
12127c478bd9Sstevel@tonic-gate 	}
12137c478bd9Sstevel@tonic-gate }
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate static bool_t
rendezvous_control(SVCXPRT * xprt,const uint_t rq,void * in)12167c478bd9Sstevel@tonic-gate rendezvous_control(SVCXPRT *xprt, const uint_t rq, void *in)
12177c478bd9Sstevel@tonic-gate {
12187c478bd9Sstevel@tonic-gate 	struct cf_rendezvous *r;
12197c478bd9Sstevel@tonic-gate 	int tmp;
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 	switch (rq) {
12227c478bd9Sstevel@tonic-gate 	case SVCSET_RECVERRHANDLER:
12237c478bd9Sstevel@tonic-gate 		xprt->xp_closeclnt = (svc_errorhandler_t)in;
12247c478bd9Sstevel@tonic-gate 		return (TRUE);
12257c478bd9Sstevel@tonic-gate 	case SVCGET_RECVERRHANDLER:
12267c478bd9Sstevel@tonic-gate 		*(svc_errorhandler_t *)in = xprt->xp_closeclnt;
12277c478bd9Sstevel@tonic-gate 		return (TRUE);
12287c478bd9Sstevel@tonic-gate 	case SVCSET_KEEPALIVE:
122961961e0fSrobinson 		/* LINTED pointer cast */
12307c478bd9Sstevel@tonic-gate 		r = (struct cf_rendezvous *)xprt->xp_p1;
12317c478bd9Sstevel@tonic-gate 		if (r->tcp_flag) {
12327c478bd9Sstevel@tonic-gate 			r->tcp_keepalive = (int)(intptr_t)in;
12337c478bd9Sstevel@tonic-gate 			return (TRUE);
12347c478bd9Sstevel@tonic-gate 		}
123561961e0fSrobinson 		return (FALSE);
12367c478bd9Sstevel@tonic-gate 	case SVCSET_CONNMAXREC:
12377c478bd9Sstevel@tonic-gate 		/*
12387c478bd9Sstevel@tonic-gate 		 * Override the default maximum record size, set via
12397c478bd9Sstevel@tonic-gate 		 * rpc_control(), for this connection. Only appropriate
12407c478bd9Sstevel@tonic-gate 		 * for connection oriented transports, but is ignored for
12417c478bd9Sstevel@tonic-gate 		 * the connectionless case, so no need to check the
12427c478bd9Sstevel@tonic-gate 		 * connection type here.
12437c478bd9Sstevel@tonic-gate 		 */
124461961e0fSrobinson 		/* LINTED pointer cast */
12457c478bd9Sstevel@tonic-gate 		r = (struct cf_rendezvous *)xprt->xp_p1;
12467c478bd9Sstevel@tonic-gate 		tmp = __rpc_legal_connmaxrec(*(int *)in);
12477c478bd9Sstevel@tonic-gate 		if (r != 0 && tmp >= 0) {
12487c478bd9Sstevel@tonic-gate 			r->cf_connmaxrec = tmp;
12497c478bd9Sstevel@tonic-gate 			return (TRUE);
12507c478bd9Sstevel@tonic-gate 		}
125161961e0fSrobinson 		return (FALSE);
12527c478bd9Sstevel@tonic-gate 	case SVCGET_CONNMAXREC:
125361961e0fSrobinson 		/* LINTED pointer cast */
12547c478bd9Sstevel@tonic-gate 		r = (struct cf_rendezvous *)xprt->xp_p1;
12557c478bd9Sstevel@tonic-gate 		if (r != 0) {
12567c478bd9Sstevel@tonic-gate 			*(int *)in = r->cf_connmaxrec;
12577c478bd9Sstevel@tonic-gate 			return (TRUE);
12587c478bd9Sstevel@tonic-gate 		}
125961961e0fSrobinson 		return (FALSE);
12607c478bd9Sstevel@tonic-gate 	case SVCGET_XID:	/* fall through for now */
12617c478bd9Sstevel@tonic-gate 	default:
12627c478bd9Sstevel@tonic-gate 		return (FALSE);
12637c478bd9Sstevel@tonic-gate 	}
12647c478bd9Sstevel@tonic-gate }
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate /*
12677c478bd9Sstevel@tonic-gate  * All read operations timeout after 35 seconds.
12687c478bd9Sstevel@tonic-gate  * A timeout is fatal for the connection.
12697c478bd9Sstevel@tonic-gate  * update_nonblock_timestamps() is used for nonblocked
12707c478bd9Sstevel@tonic-gate  * connection fds.
12717c478bd9Sstevel@tonic-gate  */
12727c478bd9Sstevel@tonic-gate #define	WAIT_PER_TRY	35000	/* milliseconds */
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate static  void
update_nonblock_timestamps(SVCXPRT * xprt_conn)12757c478bd9Sstevel@tonic-gate update_nonblock_timestamps(SVCXPRT *xprt_conn)
12767c478bd9Sstevel@tonic-gate {
12777c478bd9Sstevel@tonic-gate 	struct timeval tv;
127861961e0fSrobinson 	/* LINTED pointer cast */
12797c478bd9Sstevel@tonic-gate 	struct cf_conn *cd = (struct cf_conn *)xprt_conn->xp_p1;
12807c478bd9Sstevel@tonic-gate 
128161961e0fSrobinson 	(void) gettimeofday(&tv, NULL);
12827c478bd9Sstevel@tonic-gate 	cd->cf_conn_nonblock_timestamp = tv.tv_sec;
12837c478bd9Sstevel@tonic-gate }
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate /*
12867c478bd9Sstevel@tonic-gate  * reads data from the vc conection.
12877c478bd9Sstevel@tonic-gate  * any error is fatal and the connection is closed.
12887c478bd9Sstevel@tonic-gate  * (And a read of zero bytes is a half closed stream => error.)
12897c478bd9Sstevel@tonic-gate  */
12907c478bd9Sstevel@tonic-gate static int
read_vc(SVCXPRT * xprt,caddr_t buf,int len)12917c478bd9Sstevel@tonic-gate read_vc(SVCXPRT *xprt, caddr_t buf, int len)
12927c478bd9Sstevel@tonic-gate {
12937c478bd9Sstevel@tonic-gate 	int fd = xprt->xp_fd;
12947c478bd9Sstevel@tonic-gate 	XDR *xdrs = svc_xdrs[fd];
12957c478bd9Sstevel@tonic-gate 	struct pollfd pfd;
12967c478bd9Sstevel@tonic-gate 	int ret;
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 	/*
12997c478bd9Sstevel@tonic-gate 	 * Make sure the connection is not already dead.
13007c478bd9Sstevel@tonic-gate 	 */
13017c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
130261961e0fSrobinson 	if (svc_failed(xprt))
13037c478bd9Sstevel@tonic-gate 		return (-1);
13047c478bd9Sstevel@tonic-gate 
130561961e0fSrobinson 	/* LINTED pointer cast */
13067c478bd9Sstevel@tonic-gate 	if (((struct cf_conn *)(xprt->xp_p1))->cf_conn_nonblock) {
13077c478bd9Sstevel@tonic-gate 		/*
13087c478bd9Sstevel@tonic-gate 		 * For nonblocked reads, only update the
13097c478bd9Sstevel@tonic-gate 		 * timestamps to record the activity so the
13107c478bd9Sstevel@tonic-gate 		 * connection will not be timedout.
13117c478bd9Sstevel@tonic-gate 		 * Up to "len" bytes are requested.
13127c478bd9Sstevel@tonic-gate 		 * If fewer than "len" bytes are received, the
13137c478bd9Sstevel@tonic-gate 		 * connection is poll()ed again.
13147c478bd9Sstevel@tonic-gate 		 * The poll() for the connection fd is performed
13157c478bd9Sstevel@tonic-gate 		 * in the main poll() so that all outstanding fds
13167c478bd9Sstevel@tonic-gate 		 * are polled rather than just the vc connection.
13177c478bd9Sstevel@tonic-gate 		 * Polling on only the vc connection until the entire
13187c478bd9Sstevel@tonic-gate 		 * fragment has been read can be exploited in
13197c478bd9Sstevel@tonic-gate 		 * a Denial of Service Attack such as telnet <host> 111.
13207c478bd9Sstevel@tonic-gate 		 */
13217c478bd9Sstevel@tonic-gate 		if ((len = t_rcvnonblock(xprt, buf, len)) >= 0) {
13227c478bd9Sstevel@tonic-gate 			if (len > 0) {
13237c478bd9Sstevel@tonic-gate 				update_nonblock_timestamps(xprt);
13247c478bd9Sstevel@tonic-gate 			}
13257c478bd9Sstevel@tonic-gate 			return (len);
13267c478bd9Sstevel@tonic-gate 		}
132761961e0fSrobinson 		goto fatal_err;
13287c478bd9Sstevel@tonic-gate 	}
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 	if (!__is_xdrrec_first(xdrs)) {
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 		pfd.fd = fd;
13337c478bd9Sstevel@tonic-gate 		pfd.events = MASKVAL;
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 		do {
13367c478bd9Sstevel@tonic-gate 			if ((ret = poll(&pfd, 1, WAIT_PER_TRY)) <= 0) {
13377c478bd9Sstevel@tonic-gate 				/*
13387c478bd9Sstevel@tonic-gate 				 * If errno is EINTR, ERESTART, or EAGAIN
13397c478bd9Sstevel@tonic-gate 				 * ignore error and repeat poll
13407c478bd9Sstevel@tonic-gate 				 */
13417c478bd9Sstevel@tonic-gate 				if (ret < 0 && (errno == EINTR ||
13427c478bd9Sstevel@tonic-gate 				    errno == ERESTART || errno == EAGAIN))
13437c478bd9Sstevel@tonic-gate 					continue;
13447c478bd9Sstevel@tonic-gate 				goto fatal_err;
13457c478bd9Sstevel@tonic-gate 			}
13467c478bd9Sstevel@tonic-gate 		} while (pfd.revents == 0);
13477c478bd9Sstevel@tonic-gate 		if (pfd.revents & POLLNVAL)
13487c478bd9Sstevel@tonic-gate 			goto fatal_err;
13497c478bd9Sstevel@tonic-gate 	}
135061961e0fSrobinson 	(void) __xdrrec_resetfirst(xdrs);
13517c478bd9Sstevel@tonic-gate 	if ((len = t_rcvall(fd, buf, len)) > 0) {
13527c478bd9Sstevel@tonic-gate 		return (len);
13537c478bd9Sstevel@tonic-gate 	}
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate fatal_err:
13567c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
13577c478bd9Sstevel@tonic-gate 	((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
13587c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
13597c478bd9Sstevel@tonic-gate 	svc_flags(xprt) |= SVC_FAILED;
13607c478bd9Sstevel@tonic-gate 	return (-1);
13617c478bd9Sstevel@tonic-gate }
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate /*
13647c478bd9Sstevel@tonic-gate  * Requests up to "len" bytes of data.
13657c478bd9Sstevel@tonic-gate  * Returns number of bytes actually received, or error indication.
13667c478bd9Sstevel@tonic-gate  */
13677c478bd9Sstevel@tonic-gate static int
t_rcvnonblock(SVCXPRT * xprt,caddr_t buf,int len)13687c478bd9Sstevel@tonic-gate t_rcvnonblock(SVCXPRT *xprt, caddr_t buf, int len)
13697c478bd9Sstevel@tonic-gate {
13707c478bd9Sstevel@tonic-gate 	int fd = xprt->xp_fd;
13717c478bd9Sstevel@tonic-gate 	int flag;
13727c478bd9Sstevel@tonic-gate 	int res;
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 	res = t_rcv(fd, buf, (unsigned)len, &flag);
13757c478bd9Sstevel@tonic-gate 	if (res == -1) {
13767c478bd9Sstevel@tonic-gate 		switch (t_errno) {
13777c478bd9Sstevel@tonic-gate 		case TLOOK:
13787c478bd9Sstevel@tonic-gate 			switch (t_look(fd)) {
13797c478bd9Sstevel@tonic-gate 			case T_DISCONNECT:
138061961e0fSrobinson 				(void) t_rcvdis(fd, NULL);
13817c478bd9Sstevel@tonic-gate 				break;
13827c478bd9Sstevel@tonic-gate 			case T_ORDREL:
138361961e0fSrobinson 				(void) t_rcvrel(fd);
13847c478bd9Sstevel@tonic-gate 				(void) t_sndrel(fd);
13857c478bd9Sstevel@tonic-gate 				break;
13867c478bd9Sstevel@tonic-gate 			default:
13877c478bd9Sstevel@tonic-gate 				break;
13887c478bd9Sstevel@tonic-gate 			}
13897c478bd9Sstevel@tonic-gate 			break;
13907c478bd9Sstevel@tonic-gate 		case TNODATA:
13917c478bd9Sstevel@tonic-gate 			/*
13927c478bd9Sstevel@tonic-gate 			 * Either poll() lied, or the xprt/fd was closed and
13937c478bd9Sstevel@tonic-gate 			 * re-opened under our feet. Return 0, so that we go
13947c478bd9Sstevel@tonic-gate 			 * back to waiting for data.
13957c478bd9Sstevel@tonic-gate 			 */
13967c478bd9Sstevel@tonic-gate 			res = 0;
13977c478bd9Sstevel@tonic-gate 			break;
13987c478bd9Sstevel@tonic-gate 		/* Should handle TBUFOVFLW TSYSERR ? */
13997c478bd9Sstevel@tonic-gate 		default:
14007c478bd9Sstevel@tonic-gate 			break;
14017c478bd9Sstevel@tonic-gate 		}
14027c478bd9Sstevel@tonic-gate 	}
14037c478bd9Sstevel@tonic-gate 	return (res);
14047c478bd9Sstevel@tonic-gate }
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate /*
14077c478bd9Sstevel@tonic-gate  * Timeout out nonblocked connection fds
14087c478bd9Sstevel@tonic-gate  * If there has been no activity on the fd for __rpc_irtimeout
14097c478bd9Sstevel@tonic-gate  * seconds, timeout the fd  by destroying its xprt.
14107c478bd9Sstevel@tonic-gate  * If the caller gets an EMFILE error, the caller may also request
14117c478bd9Sstevel@tonic-gate  * that the least busy xprt gets destroyed as well.
14127c478bd9Sstevel@tonic-gate  * svc_thr_mutex is held when this is called.
14137c478bd9Sstevel@tonic-gate  * svc_mutex is held when this is called.
14147c478bd9Sstevel@tonic-gate  */
14157c478bd9Sstevel@tonic-gate static void
svc_timeout_nonblock_xprt_and_LRU(bool_t destroy_lru)14167c478bd9Sstevel@tonic-gate svc_timeout_nonblock_xprt_and_LRU(bool_t destroy_lru)
14177c478bd9Sstevel@tonic-gate {
14187c478bd9Sstevel@tonic-gate 	SVCXPRT *xprt;
14197c478bd9Sstevel@tonic-gate 	SVCXPRT *dead_xprt[CLEANUP_SIZE];
14207c478bd9Sstevel@tonic-gate 	SVCXPRT *candidate_xprt = NULL;
14217c478bd9Sstevel@tonic-gate 	struct cf_conn *cd;
14227c478bd9Sstevel@tonic-gate 	int i, fd_idx = 0, dead_idx = 0;
14237c478bd9Sstevel@tonic-gate 	struct timeval now;
14247c478bd9Sstevel@tonic-gate 	time_t lasttime, maxctime = 0;
14257c478bd9Sstevel@tonic-gate 	extern rwlock_t svc_fd_lock;
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate 	if (!check_nonblock_timestamps)
14287c478bd9Sstevel@tonic-gate 		return;
14297c478bd9Sstevel@tonic-gate 
143061961e0fSrobinson 	(void) gettimeofday(&now, NULL);
14317c478bd9Sstevel@tonic-gate 	if (svc_xports == NULL)
14327c478bd9Sstevel@tonic-gate 		return;
14337c478bd9Sstevel@tonic-gate 	/*
14347c478bd9Sstevel@tonic-gate 	 * Hold svc_fd_lock to protect
14357c478bd9Sstevel@tonic-gate 	 * svc_xports, svc_maxpollfd, svc_max_pollfd
14367c478bd9Sstevel@tonic-gate 	 */
143761961e0fSrobinson 	(void) rw_wrlock(&svc_fd_lock);
143861961e0fSrobinson 	for (;;) {
14397c478bd9Sstevel@tonic-gate 		/*
14407c478bd9Sstevel@tonic-gate 		 * Timeout upto CLEANUP_SIZE connection fds per
14417c478bd9Sstevel@tonic-gate 		 * iteration for the while(1) loop
14427c478bd9Sstevel@tonic-gate 		 */
14437c478bd9Sstevel@tonic-gate 		for (dead_idx = 0; fd_idx < svc_max_pollfd; fd_idx++) {
14447c478bd9Sstevel@tonic-gate 			if ((xprt = svc_xports[fd_idx]) == NULL) {
14457c478bd9Sstevel@tonic-gate 				continue;
14467c478bd9Sstevel@tonic-gate 			}
14477c478bd9Sstevel@tonic-gate 			/* Only look at connection fds */
144861961e0fSrobinson 			/* LINTED pointer cast */
14497c478bd9Sstevel@tonic-gate 			if (svc_type(xprt) != SVC_CONNECTION) {
14507c478bd9Sstevel@tonic-gate 				continue;
14517c478bd9Sstevel@tonic-gate 			}
145261961e0fSrobinson 			/* LINTED pointer cast */
14537c478bd9Sstevel@tonic-gate 			cd = (struct cf_conn *)xprt->xp_p1;
14547c478bd9Sstevel@tonic-gate 			if (!cd->cf_conn_nonblock)
14557c478bd9Sstevel@tonic-gate 				continue;
14567c478bd9Sstevel@tonic-gate 			lasttime = now.tv_sec - cd->cf_conn_nonblock_timestamp;
14577c478bd9Sstevel@tonic-gate 			if (lasttime >= __rpc_irtimeout &&
14587c478bd9Sstevel@tonic-gate 			    __rpc_irtimeout != 0) {
14597c478bd9Sstevel@tonic-gate 				/* Enter in timedout/dead array */
14607c478bd9Sstevel@tonic-gate 				dead_xprt[dead_idx++] = xprt;
14617c478bd9Sstevel@tonic-gate 				if (dead_idx >= CLEANUP_SIZE)
14627c478bd9Sstevel@tonic-gate 					break;
14637c478bd9Sstevel@tonic-gate 			} else
14647c478bd9Sstevel@tonic-gate 			if (lasttime > maxctime) {
14657c478bd9Sstevel@tonic-gate 				/* Possible LRU xprt */
14667c478bd9Sstevel@tonic-gate 				candidate_xprt = xprt;
14677c478bd9Sstevel@tonic-gate 				maxctime = lasttime;
14687c478bd9Sstevel@tonic-gate 			}
14697c478bd9Sstevel@tonic-gate 		}
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate 		for (i = 0; i < dead_idx; i++) {
14727c478bd9Sstevel@tonic-gate 			/* Still holding svc_fd_lock */
14737c478bd9Sstevel@tonic-gate 			_svc_vc_destroy_private(dead_xprt[i], FALSE);
14747c478bd9Sstevel@tonic-gate 		}
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 		/*
14777c478bd9Sstevel@tonic-gate 		 * If all the nonblocked fds have been checked, we're done.
14787c478bd9Sstevel@tonic-gate 		 */
14797c478bd9Sstevel@tonic-gate 		if (fd_idx++ >= svc_max_pollfd)
14807c478bd9Sstevel@tonic-gate 			break;
14817c478bd9Sstevel@tonic-gate 	}
148261961e0fSrobinson 	if ((destroy_lru) && (candidate_xprt != NULL)) {
14837c478bd9Sstevel@tonic-gate 		_svc_vc_destroy_private(candidate_xprt, FALSE);
14847c478bd9Sstevel@tonic-gate 	}
148561961e0fSrobinson 	(void) rw_unlock(&svc_fd_lock);
14867c478bd9Sstevel@tonic-gate }
14877c478bd9Sstevel@tonic-gate /*
14887c478bd9Sstevel@tonic-gate  * Receive the required bytes of data, even if it is fragmented.
14897c478bd9Sstevel@tonic-gate  */
14907c478bd9Sstevel@tonic-gate static int
t_rcvall(int fd,char * buf,int len)14917c478bd9Sstevel@tonic-gate t_rcvall(int fd, char *buf, int len)
14927c478bd9Sstevel@tonic-gate {
14937c478bd9Sstevel@tonic-gate 	int flag;
14947c478bd9Sstevel@tonic-gate 	int final = 0;
14957c478bd9Sstevel@tonic-gate 	int res;
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate 	do {
14987c478bd9Sstevel@tonic-gate 		res = t_rcv(fd, buf, (unsigned)len, &flag);
14997c478bd9Sstevel@tonic-gate 		if (res == -1) {
15007c478bd9Sstevel@tonic-gate 			if (t_errno == TLOOK) {
15017c478bd9Sstevel@tonic-gate 				switch (t_look(fd)) {
15027c478bd9Sstevel@tonic-gate 				case T_DISCONNECT:
150361961e0fSrobinson 					(void) t_rcvdis(fd, NULL);
15047c478bd9Sstevel@tonic-gate 					break;
15057c478bd9Sstevel@tonic-gate 				case T_ORDREL:
150661961e0fSrobinson 					(void) t_rcvrel(fd);
15077c478bd9Sstevel@tonic-gate 					(void) t_sndrel(fd);
15087c478bd9Sstevel@tonic-gate 					break;
15097c478bd9Sstevel@tonic-gate 				default:
15107c478bd9Sstevel@tonic-gate 					break;
15117c478bd9Sstevel@tonic-gate 				}
15127c478bd9Sstevel@tonic-gate 			}
15137c478bd9Sstevel@tonic-gate 			break;
15147c478bd9Sstevel@tonic-gate 		}
15157c478bd9Sstevel@tonic-gate 		final += res;
15167c478bd9Sstevel@tonic-gate 		buf += res;
15177c478bd9Sstevel@tonic-gate 		len -= res;
15187c478bd9Sstevel@tonic-gate 	} while (len && (flag & T_MORE));
15197c478bd9Sstevel@tonic-gate 	return (res == -1 ? -1 : final);
15207c478bd9Sstevel@tonic-gate }
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate /*
15237c478bd9Sstevel@tonic-gate  * writes data to the vc connection.
15247c478bd9Sstevel@tonic-gate  * Any error is fatal and the connection is closed.
15257c478bd9Sstevel@tonic-gate  */
15267c478bd9Sstevel@tonic-gate static int
write_vc(SVCXPRT * xprt,caddr_t buf,int len)15277c478bd9Sstevel@tonic-gate write_vc(SVCXPRT *xprt, caddr_t buf, int len)
15287c478bd9Sstevel@tonic-gate {
15297c478bd9Sstevel@tonic-gate 	int i, cnt;
15307c478bd9Sstevel@tonic-gate 	int flag;
15317c478bd9Sstevel@tonic-gate 	int maxsz;
15327c478bd9Sstevel@tonic-gate 	int nonblock;
15337c478bd9Sstevel@tonic-gate 	struct pollfd pfd;
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
15367c478bd9Sstevel@tonic-gate 	maxsz = ((struct cf_conn *)(xprt->xp_p1))->cf_tsdu;
153761961e0fSrobinson 	/* LINTED pointer cast */
15387c478bd9Sstevel@tonic-gate 	nonblock = ((struct cf_conn *)(xprt->xp_p1))->cf_conn_nonblock;
15397c478bd9Sstevel@tonic-gate 	if (nonblock && maxsz <= 0)
15407c478bd9Sstevel@tonic-gate 		maxsz = len;
15417c478bd9Sstevel@tonic-gate 	if ((maxsz == 0) || (maxsz == -1)) {
15427c478bd9Sstevel@tonic-gate 		if ((len = t_snd(xprt->xp_fd, buf, (unsigned)len,
154313147901SMarcel Telka 		    (int)0)) == -1) {
15447c478bd9Sstevel@tonic-gate 			if (t_errno == TLOOK) {
15457c478bd9Sstevel@tonic-gate 				switch (t_look(xprt->xp_fd)) {
15467c478bd9Sstevel@tonic-gate 				case T_DISCONNECT:
154761961e0fSrobinson 					(void) t_rcvdis(xprt->xp_fd, NULL);
15487c478bd9Sstevel@tonic-gate 					break;
15497c478bd9Sstevel@tonic-gate 				case T_ORDREL:
155061961e0fSrobinson 					(void) t_rcvrel(xprt->xp_fd);
15517c478bd9Sstevel@tonic-gate 					(void) t_sndrel(xprt->xp_fd);
15527c478bd9Sstevel@tonic-gate 					break;
15537c478bd9Sstevel@tonic-gate 				default:
15547c478bd9Sstevel@tonic-gate 					break;
15557c478bd9Sstevel@tonic-gate 				}
15567c478bd9Sstevel@tonic-gate 			}
15577c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
155813147901SMarcel Telka 			((struct cf_conn *)(xprt->xp_p1))->strm_stat =
155913147901SMarcel Telka 			    XPRT_DIED;
15607c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
15617c478bd9Sstevel@tonic-gate 			svc_flags(xprt) |= SVC_FAILED;
15627c478bd9Sstevel@tonic-gate 		}
15637c478bd9Sstevel@tonic-gate 		return (len);
15647c478bd9Sstevel@tonic-gate 	}
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate 	/*
15677c478bd9Sstevel@tonic-gate 	 * Setup for polling. We want to be able to write normal
15687c478bd9Sstevel@tonic-gate 	 * data to the transport
15697c478bd9Sstevel@tonic-gate 	 */
15707c478bd9Sstevel@tonic-gate 	pfd.fd = xprt->xp_fd;
15717c478bd9Sstevel@tonic-gate 	pfd.events = POLLWRNORM;
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 	/*
15747c478bd9Sstevel@tonic-gate 	 * This for those transports which have a max size for data,
15757c478bd9Sstevel@tonic-gate 	 * and for the non-blocking case, where t_snd() may send less
15767c478bd9Sstevel@tonic-gate 	 * than requested.
15777c478bd9Sstevel@tonic-gate 	 */
15787c478bd9Sstevel@tonic-gate 	for (cnt = len, i = 0; cnt > 0; cnt -= i, buf += i) {
15797c478bd9Sstevel@tonic-gate 		flag = cnt > maxsz ? T_MORE : 0;
15807c478bd9Sstevel@tonic-gate 		if ((i = t_snd(xprt->xp_fd, buf,
158113147901SMarcel Telka 		    (unsigned)MIN(cnt, maxsz), flag)) == -1) {
15827c478bd9Sstevel@tonic-gate 			if (t_errno == TLOOK) {
15837c478bd9Sstevel@tonic-gate 				switch (t_look(xprt->xp_fd)) {
15847c478bd9Sstevel@tonic-gate 				case T_DISCONNECT:
158561961e0fSrobinson 					(void) t_rcvdis(xprt->xp_fd, NULL);
15867c478bd9Sstevel@tonic-gate 					break;
15877c478bd9Sstevel@tonic-gate 				case T_ORDREL:
158861961e0fSrobinson 					(void) t_rcvrel(xprt->xp_fd);
15897c478bd9Sstevel@tonic-gate 					break;
15907c478bd9Sstevel@tonic-gate 				default:
15917c478bd9Sstevel@tonic-gate 					break;
15927c478bd9Sstevel@tonic-gate 				}
15937c478bd9Sstevel@tonic-gate 			} else if (t_errno == TFLOW) {
15947c478bd9Sstevel@tonic-gate 				/* Try again */
15957c478bd9Sstevel@tonic-gate 				i = 0;
15967c478bd9Sstevel@tonic-gate 				/* Wait till we can write to the transport */
15977c478bd9Sstevel@tonic-gate 				do {
159813147901SMarcel Telka 					if (poll(&pfd, 1, WAIT_PER_TRY) < 0) {
159913147901SMarcel Telka 						/*
160013147901SMarcel Telka 						 * If errno is ERESTART, or
160113147901SMarcel Telka 						 * EAGAIN ignore error and
160213147901SMarcel Telka 						 * repeat poll
160313147901SMarcel Telka 						 */
160413147901SMarcel Telka 						if (errno == ERESTART ||
160513147901SMarcel Telka 						    errno == EAGAIN)
160613147901SMarcel Telka 							continue;
160713147901SMarcel Telka 						else
160813147901SMarcel Telka 							goto fatal_err;
160913147901SMarcel Telka 					}
16107c478bd9Sstevel@tonic-gate 				} while (pfd.revents == 0);
16117c478bd9Sstevel@tonic-gate 				if (pfd.revents & (POLLNVAL | POLLERR |
161213147901SMarcel Telka 				    POLLHUP))
16137c478bd9Sstevel@tonic-gate 					goto fatal_err;
16147c478bd9Sstevel@tonic-gate 				continue;
16157c478bd9Sstevel@tonic-gate 			}
16167c478bd9Sstevel@tonic-gate fatal_err:
16177c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
161813147901SMarcel Telka 			((struct cf_conn *)(xprt->xp_p1))->strm_stat =
161913147901SMarcel Telka 			    XPRT_DIED;
16207c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
16217c478bd9Sstevel@tonic-gate 			svc_flags(xprt) |= SVC_FAILED;
16227c478bd9Sstevel@tonic-gate 			return (-1);
16237c478bd9Sstevel@tonic-gate 		}
16247c478bd9Sstevel@tonic-gate 	}
16257c478bd9Sstevel@tonic-gate 	return (len);
16267c478bd9Sstevel@tonic-gate }
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate static enum xprt_stat
svc_vc_stat(SVCXPRT * xprt)16297c478bd9Sstevel@tonic-gate svc_vc_stat(SVCXPRT *xprt)
16307c478bd9Sstevel@tonic-gate {
16317c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
16327c478bd9Sstevel@tonic-gate 	SVCXPRT *parent = SVCEXT(xprt)->parent ? SVCEXT(xprt)->parent : xprt;
16337c478bd9Sstevel@tonic-gate 
16347c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
163561961e0fSrobinson 	if (svc_failed(parent) || svc_failed(xprt))
16367c478bd9Sstevel@tonic-gate 		return (XPRT_DIED);
163761961e0fSrobinson 	if (!xdrrec_eof(svc_xdrs[xprt->xp_fd]))
16387c478bd9Sstevel@tonic-gate 		return (XPRT_MOREREQS);
16397c478bd9Sstevel@tonic-gate 	/*
16407c478bd9Sstevel@tonic-gate 	 * xdrrec_eof could have noticed that the connection is dead, so
16417c478bd9Sstevel@tonic-gate 	 * check status again.
16427c478bd9Sstevel@tonic-gate 	 */
16437c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
164461961e0fSrobinson 	if (svc_failed(parent) || svc_failed(xprt))
16457c478bd9Sstevel@tonic-gate 		return (XPRT_DIED);
16467c478bd9Sstevel@tonic-gate 	return (XPRT_IDLE);
16477c478bd9Sstevel@tonic-gate }
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate 
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate static bool_t
svc_vc_recv(SVCXPRT * xprt,struct rpc_msg * msg)16527c478bd9Sstevel@tonic-gate svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg)
16537c478bd9Sstevel@tonic-gate {
16547c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
16557c478bd9Sstevel@tonic-gate 	struct cf_conn *cd = (struct cf_conn *)(xprt->xp_p1);
16567c478bd9Sstevel@tonic-gate 	XDR *xdrs = svc_xdrs[xprt->xp_fd];
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 	xdrs->x_op = XDR_DECODE;
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 	if (cd->cf_conn_nonblock) {
16617c478bd9Sstevel@tonic-gate 		/* Get the next input */
16627c478bd9Sstevel@tonic-gate 		if (!__xdrrec_getbytes_nonblock(xdrs, &cd->strm_stat)) {
16637c478bd9Sstevel@tonic-gate 			/*
16647c478bd9Sstevel@tonic-gate 			 * The entire record has not been received.
16657c478bd9Sstevel@tonic-gate 			 * If the xprt has died, pass it along in svc_flags.
16667c478bd9Sstevel@tonic-gate 			 * Return FALSE; For nonblocked vc connection,
16677c478bd9Sstevel@tonic-gate 			 * xdr_callmsg() is called only after the entire
16687c478bd9Sstevel@tonic-gate 			 * record has been received.  For blocked vc
16697c478bd9Sstevel@tonic-gate 			 * connection, the data is received on the fly as it
16707c478bd9Sstevel@tonic-gate 			 * is being processed through the xdr routines.
16717c478bd9Sstevel@tonic-gate 			 */
16727c478bd9Sstevel@tonic-gate 			if (cd->strm_stat == XPRT_DIED)
167361961e0fSrobinson 				/* LINTED pointer cast */
16747c478bd9Sstevel@tonic-gate 				svc_flags(xprt) |= SVC_FAILED;
16757c478bd9Sstevel@tonic-gate 			return (FALSE);
16767c478bd9Sstevel@tonic-gate 		}
16777c478bd9Sstevel@tonic-gate 	} else {
167861961e0fSrobinson 		if (!xdrrec_skiprecord(xdrs))
16797c478bd9Sstevel@tonic-gate 			return (FALSE);
168061961e0fSrobinson 		(void) __xdrrec_setfirst(xdrs);
16817c478bd9Sstevel@tonic-gate 	}
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate 	if (xdr_callmsg(xdrs, msg)) {
16847c478bd9Sstevel@tonic-gate 		cd->x_id = msg->rm_xid;
16857c478bd9Sstevel@tonic-gate 		return (TRUE);
16867c478bd9Sstevel@tonic-gate 	}
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 	/*
16897c478bd9Sstevel@tonic-gate 	 * If a non-blocking connection, drop it when message decode fails.
16907c478bd9Sstevel@tonic-gate 	 * We are either under attack, or we're talking to a broken client.
16917c478bd9Sstevel@tonic-gate 	 */
16927c478bd9Sstevel@tonic-gate 	if (cd->cf_conn_nonblock) {
169361961e0fSrobinson 		/* LINTED pointer cast */
16947c478bd9Sstevel@tonic-gate 		svc_flags(xprt) |= SVC_FAILED;
16957c478bd9Sstevel@tonic-gate 	}
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 	return (FALSE);
16987c478bd9Sstevel@tonic-gate }
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate static bool_t
svc_vc_getargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)17017c478bd9Sstevel@tonic-gate svc_vc_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
17027c478bd9Sstevel@tonic-gate {
170361961e0fSrobinson 	bool_t dummy;
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
170661961e0fSrobinson 	dummy = SVCAUTH_UNWRAP(&SVC_XP_AUTH(xprt), svc_xdrs[xprt->xp_fd],
170713147901SMarcel Telka 	    xdr_args, args_ptr);
17087c478bd9Sstevel@tonic-gate 	if (svc_mt_mode != RPC_SVC_MT_NONE)
17097c478bd9Sstevel@tonic-gate 		svc_args_done(xprt);
171061961e0fSrobinson 	return (dummy);
17117c478bd9Sstevel@tonic-gate }
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate static bool_t
svc_vc_freeargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)17147c478bd9Sstevel@tonic-gate svc_vc_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
17157c478bd9Sstevel@tonic-gate {
17167c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
17177c478bd9Sstevel@tonic-gate 	XDR *xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs);
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate 	xdrs->x_op = XDR_FREE;
172061961e0fSrobinson 	return ((*xdr_args)(xdrs, args_ptr));
17217c478bd9Sstevel@tonic-gate }
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate static bool_t
svc_vc_reply(SVCXPRT * xprt,struct rpc_msg * msg)17247c478bd9Sstevel@tonic-gate svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg)
17257c478bd9Sstevel@tonic-gate {
17267c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
17277c478bd9Sstevel@tonic-gate 	struct cf_conn *cd = (struct cf_conn *)(xprt->xp_p1);
17287c478bd9Sstevel@tonic-gate 	XDR *xdrs = &(cd->xdrs);
17297c478bd9Sstevel@tonic-gate 	bool_t stat = FALSE;
17307c478bd9Sstevel@tonic-gate 	xdrproc_t xdr_results;
17317c478bd9Sstevel@tonic-gate 	caddr_t xdr_location;
17327c478bd9Sstevel@tonic-gate 	bool_t has_args;
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate 	if (svc_mt_mode != RPC_SVC_MT_NONE)
17357c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
173661961e0fSrobinson 		(void) mutex_lock(&svc_send_mutex(SVCEXT(xprt)->parent));
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
173913147901SMarcel Telka 	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
17407c478bd9Sstevel@tonic-gate 		has_args = TRUE;
17417c478bd9Sstevel@tonic-gate 		xdr_results = msg->acpted_rply.ar_results.proc;
17427c478bd9Sstevel@tonic-gate 		xdr_location = msg->acpted_rply.ar_results.where;
17437c478bd9Sstevel@tonic-gate 		msg->acpted_rply.ar_results.proc = xdr_void;
17447c478bd9Sstevel@tonic-gate 		msg->acpted_rply.ar_results.where = NULL;
17457c478bd9Sstevel@tonic-gate 	} else
17467c478bd9Sstevel@tonic-gate 		has_args = FALSE;
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate 	xdrs->x_op = XDR_ENCODE;
17497c478bd9Sstevel@tonic-gate 	msg->rm_xid = cd->x_id;
17507c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
17517c478bd9Sstevel@tonic-gate 	if (xdr_replymsg(xdrs, msg) && (!has_args || SVCAUTH_WRAP(
175213147901SMarcel Telka 	    &SVC_XP_AUTH(xprt), xdrs, xdr_results, xdr_location))) {
17537c478bd9Sstevel@tonic-gate 		stat = TRUE;
17547c478bd9Sstevel@tonic-gate 	}
17557c478bd9Sstevel@tonic-gate 	(void) xdrrec_endofrecord(xdrs, TRUE);
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate 	if (svc_mt_mode != RPC_SVC_MT_NONE)
17587c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
175961961e0fSrobinson 		(void) mutex_unlock(&svc_send_mutex(SVCEXT(xprt)->parent));
17607c478bd9Sstevel@tonic-gate 
17617c478bd9Sstevel@tonic-gate 	return (stat);
17627c478bd9Sstevel@tonic-gate }
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate static struct xp_ops *
svc_vc_ops(void)176561961e0fSrobinson svc_vc_ops(void)
17667c478bd9Sstevel@tonic-gate {
17677c478bd9Sstevel@tonic-gate 	static struct xp_ops ops;
17687c478bd9Sstevel@tonic-gate 	extern mutex_t ops_lock;
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate /* VARIABLES PROTECTED BY ops_lock: ops */
17717c478bd9Sstevel@tonic-gate 
177261961e0fSrobinson 	(void) mutex_lock(&ops_lock);
17737c478bd9Sstevel@tonic-gate 	if (ops.xp_recv == NULL) {
17747c478bd9Sstevel@tonic-gate 		ops.xp_recv = svc_vc_recv;
17757c478bd9Sstevel@tonic-gate 		ops.xp_stat = svc_vc_stat;
17767c478bd9Sstevel@tonic-gate 		ops.xp_getargs = svc_vc_getargs;
17777c478bd9Sstevel@tonic-gate 		ops.xp_reply = svc_vc_reply;
17787c478bd9Sstevel@tonic-gate 		ops.xp_freeargs = svc_vc_freeargs;
17797c478bd9Sstevel@tonic-gate 		ops.xp_destroy = svc_vc_destroy;
17807c478bd9Sstevel@tonic-gate 		ops.xp_control = svc_vc_control;
17817c478bd9Sstevel@tonic-gate 	}
178261961e0fSrobinson 	(void) mutex_unlock(&ops_lock);
17837c478bd9Sstevel@tonic-gate 	return (&ops);
17847c478bd9Sstevel@tonic-gate }
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate static struct xp_ops *
svc_vc_rendezvous_ops(void)178761961e0fSrobinson svc_vc_rendezvous_ops(void)
17887c478bd9Sstevel@tonic-gate {
17897c478bd9Sstevel@tonic-gate 	static struct xp_ops ops;
17907c478bd9Sstevel@tonic-gate 	extern mutex_t ops_lock;
17917c478bd9Sstevel@tonic-gate 
179261961e0fSrobinson 	(void) mutex_lock(&ops_lock);
17937c478bd9Sstevel@tonic-gate 	if (ops.xp_recv == NULL) {
17947c478bd9Sstevel@tonic-gate 		ops.xp_recv = rendezvous_request;
17957c478bd9Sstevel@tonic-gate 		ops.xp_stat = rendezvous_stat;
17967c478bd9Sstevel@tonic-gate 		ops.xp_getargs = (bool_t (*)())abort;
17977c478bd9Sstevel@tonic-gate 		ops.xp_reply = (bool_t (*)())abort;
179813147901SMarcel Telka 		ops.xp_freeargs = (bool_t (*)())abort;
17997c478bd9Sstevel@tonic-gate 		ops.xp_destroy = svc_vc_destroy;
18007c478bd9Sstevel@tonic-gate 		ops.xp_control = rendezvous_control;
18017c478bd9Sstevel@tonic-gate 	}
180261961e0fSrobinson 	(void) mutex_unlock(&ops_lock);
18037c478bd9Sstevel@tonic-gate 	return (&ops);
18047c478bd9Sstevel@tonic-gate }
18057c478bd9Sstevel@tonic-gate 
18067c478bd9Sstevel@tonic-gate /*
18077c478bd9Sstevel@tonic-gate  * dup cache wrapper functions for vc requests. The set of dup
18087c478bd9Sstevel@tonic-gate  * functions were written with the view that they may be expanded
18097c478bd9Sstevel@tonic-gate  * during creation of a generic svc_vc_enablecache routine
18107c478bd9Sstevel@tonic-gate  * which would have a size based cache, rather than a time based cache.
18117c478bd9Sstevel@tonic-gate  * The real work is done in generic svc.c
18127c478bd9Sstevel@tonic-gate  */
18137c478bd9Sstevel@tonic-gate bool_t
__svc_vc_dupcache_init(SVCXPRT * xprt,void * condition,int basis)18147c478bd9Sstevel@tonic-gate __svc_vc_dupcache_init(SVCXPRT *xprt, void *condition, int basis)
18157c478bd9Sstevel@tonic-gate {
18167c478bd9Sstevel@tonic-gate 	return (__svc_dupcache_init(condition, basis,
181713147901SMarcel Telka 	    /* LINTED pointer alignment */
181813147901SMarcel Telka 	    &(((struct cf_rendezvous *)xprt->xp_p1)->cf_cache)));
18197c478bd9Sstevel@tonic-gate }
18207c478bd9Sstevel@tonic-gate 
18217c478bd9Sstevel@tonic-gate int
__svc_vc_dup(struct svc_req * req,caddr_t * resp_buf,uint_t * resp_bufsz)18227c478bd9Sstevel@tonic-gate __svc_vc_dup(struct svc_req *req, caddr_t *resp_buf, uint_t *resp_bufsz)
18237c478bd9Sstevel@tonic-gate {
18247c478bd9Sstevel@tonic-gate 	return (__svc_dup(req, resp_buf, resp_bufsz,
182513147901SMarcel Telka 	    /* LINTED pointer alignment */
182613147901SMarcel Telka 	    ((struct cf_conn *)req->rq_xprt->xp_p1)->cf_cache));
18277c478bd9Sstevel@tonic-gate }
18287c478bd9Sstevel@tonic-gate 
18297c478bd9Sstevel@tonic-gate int
__svc_vc_dupdone(struct svc_req * req,caddr_t resp_buf,uint_t resp_bufsz,int status)18307c478bd9Sstevel@tonic-gate __svc_vc_dupdone(struct svc_req *req, caddr_t resp_buf, uint_t resp_bufsz,
1831*a69e76caSToomas Soome     int status)
18327c478bd9Sstevel@tonic-gate {
18337c478bd9Sstevel@tonic-gate 	return (__svc_dupdone(req, resp_buf, resp_bufsz, status,
183413147901SMarcel Telka 	    /* LINTED pointer alignment */
183513147901SMarcel Telka 	    ((struct cf_conn *)req->rq_xprt->xp_p1)->cf_cache));
18367c478bd9Sstevel@tonic-gate }
1837