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 */
26*13147901SMarcel Telka /*
27*13147901SMarcel Telka * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
28*13147901SMarcel 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 */
1647c478bd9Sstevel@tonic-gate (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,
2227c478bd9Sstevel@tonic-gate 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),
2307c478bd9Sstevel@tonic-gate t_errno, errno);
2317c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "%s : %s : %s",
2327c478bd9Sstevel@tonic-gate 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,
2557c478bd9Sstevel@tonic-gate 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,
2657c478bd9Sstevel@tonic-gate 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),
4107c478bd9Sstevel@tonic-gate t_errno, errno);
4117c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "%s : %s : %s",
4127c478bd9Sstevel@tonic-gate 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,
4227c478bd9Sstevel@tonic-gate "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,
5097c478bd9Sstevel@tonic-gate (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,
5227c478bd9Sstevel@tonic-gate 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) {
533*13147901SMarcel Telka XDR **tmp_xdrs = realloc(svc_xdrs,
5347c478bd9Sstevel@tonic-gate sizeof (XDR *) * (nsvc_xdrs + FD_INCREMENT));
5357c478bd9Sstevel@tonic-gate if (tmp_xdrs == NULL) {
5367c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, errstring, makefd_xprt_str,
5377c478bd9Sstevel@tonic-gate 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,
5487c478bd9Sstevel@tonic-gate 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,
5647c478bd9Sstevel@tonic-gate (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,
6417c478bd9Sstevel@tonic-gate (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)
6897c478bd9Sstevel@tonic-gate (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))
7137c478bd9Sstevel@tonic-gate == NULL) {
7147c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, errstring,
715*13147901SMarcel 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
722*13147901SMarcel 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
728*13147901SMarcel Telka struct entry {
729*13147901SMarcel Telka struct t_call *t_call;
730*13147901SMarcel Telka struct entry *next;
731*13147901SMarcel Telka };
732*13147901SMarcel Telka
7337c478bd9Sstevel@tonic-gate static void
do_accept(int srcfd,char * tpname,char * netid,struct cf_rendezvous * r)734*13147901SMarcel 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;
740*13147901SMarcel Telka SVCXPRT *xprt;
741*13147901SMarcel Telka SVCXPRT *xprt_srcfd;
742*13147901SMarcel Telka struct entry *head = NULL;
743*13147901SMarcel Telka struct entry *tail = NULL;
744*13147901SMarcel Telka struct entry *e;
745*13147901SMarcel Telka struct t_call *tcp;
746*13147901SMarcel Telka
747*13147901SMarcel Telka restart:
748*13147901SMarcel 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
778*13147901SMarcel Telka __tli_sys_strerror(errorstr, sizeof (errorstr), t_errno, errno);
7797c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "%s : %s : %s", do_accept_str,
7807c478bd9Sstevel@tonic-gate "can't open connection", errorstr);
7817c478bd9Sstevel@tonic-gate (void) t_snddis(srcfd, tcp);
782*13147901SMarcel Telka
783*13147901SMarcel Telka goto end;
78461961e0fSrobinson }
7857c478bd9Sstevel@tonic-gate if (RPC_FD_NOTIN_FDSET(destfd)) {
786*13147901SMarcel 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);
789*13147901SMarcel Telka
790*13147901SMarcel Telka goto end;
7917c478bd9Sstevel@tonic-gate }
792*13147901SMarcel 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,
7967c478bd9Sstevel@tonic-gate "do_accept: illegal transport");
7977c478bd9Sstevel@tonic-gate (void) t_close(destfd);
7987c478bd9Sstevel@tonic-gate (void) t_snddis(srcfd, tcp);
799*13147901SMarcel Telka
800*13147901SMarcel 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
807*13147901SMarcel Telka __tli_sys_strerror(errorstr, sizeof (errorstr), t_errno, errno);
8087c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, " %s : %s : %s", do_accept_str,
8097c478bd9Sstevel@tonic-gate "t_bind failed", errorstr);
8107c478bd9Sstevel@tonic-gate (void) t_close(destfd);
8117c478bd9Sstevel@tonic-gate (void) t_snddis(srcfd, tcp);
812*13147901SMarcel Telka
813*13147901SMarcel 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,
8597c478bd9Sstevel@tonic-gate do_accept_str, no_mem_str);
860*13147901SMarcel Telka
861*13147901SMarcel 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);
875*13147901SMarcel Telka
876*13147901SMarcel Telka goto end;
8777c478bd9Sstevel@tonic-gate }
878*13147901SMarcel Telka
879*13147901SMarcel Telka e = malloc(sizeof (struct entry));
880*13147901SMarcel Telka if (e == NULL) {
881*13147901SMarcel Telka (void) t_snddis(srcfd, tcp2);
882*13147901SMarcel Telka (void) t_free((char *)tcp2, T_CALL);
883*13147901SMarcel Telka tcp2 = NULL;
884*13147901SMarcel Telka
885*13147901SMarcel Telka break;
886*13147901SMarcel Telka }
887*13147901SMarcel Telka
888*13147901SMarcel Telka e->t_call = tcp2;
889*13147901SMarcel Telka tcp2 = NULL;
890*13147901SMarcel Telka e->next = NULL;
891*13147901SMarcel Telka
892*13147901SMarcel Telka if (head == NULL)
893*13147901SMarcel Telka head = e;
894*13147901SMarcel Telka else
895*13147901SMarcel Telka tail->next = e;
896*13147901SMarcel Telka tail = e;
897*13147901SMarcel 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);
918*13147901SMarcel Telka
919*13147901SMarcel 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);
929*13147901SMarcel Telka
930*13147901SMarcel Telka goto end;
9317c478bd9Sstevel@tonic-gate }
9327c478bd9Sstevel@tonic-gate /* else FALL THROUGH TO */
9337c478bd9Sstevel@tonic-gate
9347c478bd9Sstevel@tonic-gate default:
9357c478bd9Sstevel@tonic-gate __tli_sys_strerror(errorstr, sizeof (errorstr),
9367c478bd9Sstevel@tonic-gate 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);
942*13147901SMarcel Telka
943*13147901SMarcel Telka goto end;
9447c478bd9Sstevel@tonic-gate }
9457c478bd9Sstevel@tonic-gate }
9467c478bd9Sstevel@tonic-gate
9477c478bd9Sstevel@tonic-gate if (r->tcp_flag && r->tcp_keepalive) {
948*13147901SMarcel Telka char *option;
949*13147901SMarcel Telka char *option_ret;
950*13147901SMarcel Telka
95161961e0fSrobinson option = malloc(sizeof (struct opthdr) + sizeof (int));
95261961e0fSrobinson option_ret = malloc(sizeof (struct opthdr) + sizeof (int));
953*13147901SMarcel Telka if (option != NULL && option_ret != NULL) {
954*13147901SMarcel Telka struct opthdr *opt;
955*13147901SMarcel Telka struct t_optmgmt optreq, optret;
956*13147901SMarcel Telka int *p_optval;
957*13147901SMarcel 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 =
9667c478bd9Sstevel@tonic-gate 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)
9707c478bd9Sstevel@tonic-gate + sizeof (int);
9717c478bd9Sstevel@tonic-gate optret.opt.buf = (char *)option_ret;
97261961e0fSrobinson (void) t_optmgmt(destfd, &optreq, &optret);
9737c478bd9Sstevel@tonic-gate }
974*13147901SMarcel Telka free(option);
975*13147901SMarcel 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,
9837c478bd9Sstevel@tonic-gate 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 =
10057c478bd9Sstevel@tonic-gate malloc(xprt->xp_ltaddr.maxlen)) == NULL)
10067c478bd9Sstevel@tonic-gate goto memerr;
10077c478bd9Sstevel@tonic-gate if (t_getname(destfd, &xprt->xp_ltaddr, LOCALNAME) < 0) {
10087c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR,
10097c478bd9Sstevel@tonic-gate "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 =
10157c478bd9Sstevel@tonic-gate 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,
10197c478bd9Sstevel@tonic-gate "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 */
1035*13147901SMarcel 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
1065*13147901SMarcel Telka end:
1066*13147901SMarcel Telka if (head != NULL) {
1067*13147901SMarcel Telka (void) t_free((char *)r->t_call, T_CALL);
1068*13147901SMarcel Telka r->t_call = head->t_call;
1069*13147901SMarcel Telka e = head;
1070*13147901SMarcel Telka head = head->next;
1071*13147901SMarcel Telka free(e);
1072*13147901SMarcel Telka goto restart;
1073*13147901SMarcel Telka }
1074*13147901SMarcel Telka
1075*13147901SMarcel Telka if (tcp2)
1076*13147901SMarcel Telka (void) t_free((char *)tcp2, T_CALL);
1077*13147901SMarcel 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);
1086*13147901SMarcel Telka
1087*13147901SMarcel 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 =
110361961e0fSrobinson /* LINTED pointer cast */
11047c478bd9Sstevel@tonic-gate (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,
11117c478bd9Sstevel@tonic-gate 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,
11177c478bd9Sstevel@tonic-gate 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);
12077c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
120861961e0fSrobinson *(uint32_t *)in = ((struct cf_conn *)(xprt->xp_p1))->x_id;
12097c478bd9Sstevel@tonic-gate 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,
15437c478bd9Sstevel@tonic-gate (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 */
1558*13147901SMarcel Telka ((struct cf_conn *)(xprt->xp_p1))->strm_stat =
1559*13147901SMarcel 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,
15817c478bd9Sstevel@tonic-gate (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 {
159861961e0fSrobinson if (poll(&pfd, 1, WAIT_PER_TRY) < 0) {
15997c478bd9Sstevel@tonic-gate /*
16007c478bd9Sstevel@tonic-gate * If errno is ERESTART, or
1601*13147901SMarcel Telka * EAGAIN ignore error and
1602*13147901SMarcel Telka * repeat poll
16037c478bd9Sstevel@tonic-gate */
16047c478bd9Sstevel@tonic-gate if (errno == ERESTART ||
16057c478bd9Sstevel@tonic-gate errno == EAGAIN)
16067c478bd9Sstevel@tonic-gate continue;
16077c478bd9Sstevel@tonic-gate else
16087c478bd9Sstevel@tonic-gate goto fatal_err;
16097c478bd9Sstevel@tonic-gate }
16107c478bd9Sstevel@tonic-gate } while (pfd.revents == 0);
16117c478bd9Sstevel@tonic-gate if (pfd.revents & (POLLNVAL | POLLERR |
16127c478bd9Sstevel@tonic-gate 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 */
1618*13147901SMarcel Telka ((struct cf_conn *)(xprt->xp_p1))->strm_stat =
1619*13147901SMarcel 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],
17077c478bd9Sstevel@tonic-gate 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 #ifdef __lock_lint
173561961e0fSrobinson (void) mutex_lock(&svc_send_mutex(SVCEXT(xprt)->parent));
17367c478bd9Sstevel@tonic-gate #else
17377c478bd9Sstevel@tonic-gate if (svc_mt_mode != RPC_SVC_MT_NONE)
17387c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
173961961e0fSrobinson (void) mutex_lock(&svc_send_mutex(SVCEXT(xprt)->parent));
17407c478bd9Sstevel@tonic-gate #endif
17417c478bd9Sstevel@tonic-gate
17427c478bd9Sstevel@tonic-gate if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
17437c478bd9Sstevel@tonic-gate msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
17447c478bd9Sstevel@tonic-gate has_args = TRUE;
17457c478bd9Sstevel@tonic-gate xdr_results = msg->acpted_rply.ar_results.proc;
17467c478bd9Sstevel@tonic-gate xdr_location = msg->acpted_rply.ar_results.where;
17477c478bd9Sstevel@tonic-gate msg->acpted_rply.ar_results.proc = xdr_void;
17487c478bd9Sstevel@tonic-gate msg->acpted_rply.ar_results.where = NULL;
17497c478bd9Sstevel@tonic-gate } else
17507c478bd9Sstevel@tonic-gate has_args = FALSE;
17517c478bd9Sstevel@tonic-gate
17527c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_ENCODE;
17537c478bd9Sstevel@tonic-gate msg->rm_xid = cd->x_id;
17547c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
17557c478bd9Sstevel@tonic-gate if (xdr_replymsg(xdrs, msg) && (!has_args || SVCAUTH_WRAP(
17567c478bd9Sstevel@tonic-gate &SVC_XP_AUTH(xprt), xdrs, xdr_results, xdr_location))) {
17577c478bd9Sstevel@tonic-gate stat = TRUE;
17587c478bd9Sstevel@tonic-gate }
17597c478bd9Sstevel@tonic-gate (void) xdrrec_endofrecord(xdrs, TRUE);
17607c478bd9Sstevel@tonic-gate
17617c478bd9Sstevel@tonic-gate #ifdef __lock_lint
176261961e0fSrobinson (void) mutex_unlock(&svc_send_mutex(SVCEXT(xprt)->parent));
17637c478bd9Sstevel@tonic-gate #else
17647c478bd9Sstevel@tonic-gate if (svc_mt_mode != RPC_SVC_MT_NONE)
17657c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
176661961e0fSrobinson (void) mutex_unlock(&svc_send_mutex(SVCEXT(xprt)->parent));
17677c478bd9Sstevel@tonic-gate #endif
17687c478bd9Sstevel@tonic-gate
17697c478bd9Sstevel@tonic-gate return (stat);
17707c478bd9Sstevel@tonic-gate }
17717c478bd9Sstevel@tonic-gate
17727c478bd9Sstevel@tonic-gate static struct xp_ops *
svc_vc_ops(void)177361961e0fSrobinson svc_vc_ops(void)
17747c478bd9Sstevel@tonic-gate {
17757c478bd9Sstevel@tonic-gate static struct xp_ops ops;
17767c478bd9Sstevel@tonic-gate extern mutex_t ops_lock;
17777c478bd9Sstevel@tonic-gate
17787c478bd9Sstevel@tonic-gate /* VARIABLES PROTECTED BY ops_lock: ops */
17797c478bd9Sstevel@tonic-gate
178061961e0fSrobinson (void) mutex_lock(&ops_lock);
17817c478bd9Sstevel@tonic-gate if (ops.xp_recv == NULL) {
17827c478bd9Sstevel@tonic-gate ops.xp_recv = svc_vc_recv;
17837c478bd9Sstevel@tonic-gate ops.xp_stat = svc_vc_stat;
17847c478bd9Sstevel@tonic-gate ops.xp_getargs = svc_vc_getargs;
17857c478bd9Sstevel@tonic-gate ops.xp_reply = svc_vc_reply;
17867c478bd9Sstevel@tonic-gate ops.xp_freeargs = svc_vc_freeargs;
17877c478bd9Sstevel@tonic-gate ops.xp_destroy = svc_vc_destroy;
17887c478bd9Sstevel@tonic-gate ops.xp_control = svc_vc_control;
17897c478bd9Sstevel@tonic-gate }
179061961e0fSrobinson (void) mutex_unlock(&ops_lock);
17917c478bd9Sstevel@tonic-gate return (&ops);
17927c478bd9Sstevel@tonic-gate }
17937c478bd9Sstevel@tonic-gate
17947c478bd9Sstevel@tonic-gate static struct xp_ops *
svc_vc_rendezvous_ops(void)179561961e0fSrobinson svc_vc_rendezvous_ops(void)
17967c478bd9Sstevel@tonic-gate {
17977c478bd9Sstevel@tonic-gate static struct xp_ops ops;
17987c478bd9Sstevel@tonic-gate extern mutex_t ops_lock;
17997c478bd9Sstevel@tonic-gate
180061961e0fSrobinson (void) mutex_lock(&ops_lock);
18017c478bd9Sstevel@tonic-gate if (ops.xp_recv == NULL) {
18027c478bd9Sstevel@tonic-gate ops.xp_recv = rendezvous_request;
18037c478bd9Sstevel@tonic-gate ops.xp_stat = rendezvous_stat;
18047c478bd9Sstevel@tonic-gate ops.xp_getargs = (bool_t (*)())abort;
18057c478bd9Sstevel@tonic-gate ops.xp_reply = (bool_t (*)())abort;
1806*13147901SMarcel Telka ops.xp_freeargs = (bool_t (*)())abort;
18077c478bd9Sstevel@tonic-gate ops.xp_destroy = svc_vc_destroy;
18087c478bd9Sstevel@tonic-gate ops.xp_control = rendezvous_control;
18097c478bd9Sstevel@tonic-gate }
181061961e0fSrobinson (void) mutex_unlock(&ops_lock);
18117c478bd9Sstevel@tonic-gate return (&ops);
18127c478bd9Sstevel@tonic-gate }
18137c478bd9Sstevel@tonic-gate
18147c478bd9Sstevel@tonic-gate /*
18157c478bd9Sstevel@tonic-gate * dup cache wrapper functions for vc requests. The set of dup
18167c478bd9Sstevel@tonic-gate * functions were written with the view that they may be expanded
18177c478bd9Sstevel@tonic-gate * during creation of a generic svc_vc_enablecache routine
18187c478bd9Sstevel@tonic-gate * which would have a size based cache, rather than a time based cache.
18197c478bd9Sstevel@tonic-gate * The real work is done in generic svc.c
18207c478bd9Sstevel@tonic-gate */
18217c478bd9Sstevel@tonic-gate bool_t
__svc_vc_dupcache_init(SVCXPRT * xprt,void * condition,int basis)18227c478bd9Sstevel@tonic-gate __svc_vc_dupcache_init(SVCXPRT *xprt, void *condition, int basis)
18237c478bd9Sstevel@tonic-gate {
18247c478bd9Sstevel@tonic-gate return (__svc_dupcache_init(condition, basis,
18257c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
18267c478bd9Sstevel@tonic-gate &(((struct cf_rendezvous *)xprt->xp_p1)->cf_cache)));
18277c478bd9Sstevel@tonic-gate }
18287c478bd9Sstevel@tonic-gate
18297c478bd9Sstevel@tonic-gate int
__svc_vc_dup(struct svc_req * req,caddr_t * resp_buf,uint_t * resp_bufsz)18307c478bd9Sstevel@tonic-gate __svc_vc_dup(struct svc_req *req, caddr_t *resp_buf, uint_t *resp_bufsz)
18317c478bd9Sstevel@tonic-gate {
18327c478bd9Sstevel@tonic-gate return (__svc_dup(req, resp_buf, resp_bufsz,
18337c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
18347c478bd9Sstevel@tonic-gate ((struct cf_conn *)req->rq_xprt->xp_p1)->cf_cache));
18357c478bd9Sstevel@tonic-gate }
18367c478bd9Sstevel@tonic-gate
18377c478bd9Sstevel@tonic-gate int
__svc_vc_dupdone(struct svc_req * req,caddr_t resp_buf,uint_t resp_bufsz,int status)18387c478bd9Sstevel@tonic-gate __svc_vc_dupdone(struct svc_req *req, caddr_t resp_buf, uint_t resp_bufsz,
18397c478bd9Sstevel@tonic-gate int status)
18407c478bd9Sstevel@tonic-gate {
18417c478bd9Sstevel@tonic-gate return (__svc_dupdone(req, resp_buf, resp_bufsz, status,
18427c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
18437c478bd9Sstevel@tonic-gate ((struct cf_conn *)req->rq_xprt->xp_p1)->cf_cache));
18447c478bd9Sstevel@tonic-gate }
1845