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 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 * 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 * 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 * 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 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 * 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 * 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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 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 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 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