xref: /titanic_52/usr/src/ucblib/librpcsoc/clnt_tcp.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 1990 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*
28*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1984, 1986, 1987, 1988, 1989, 1996 AT&T
29*7c478bd9Sstevel@tonic-gate  * All Rights Reserved
30*7c478bd9Sstevel@tonic-gate  */
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate /*
33*7c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
34*7c478bd9Sstevel@tonic-gate  * The Regents of the University of California
35*7c478bd9Sstevel@tonic-gate  * All Rights Reserved
36*7c478bd9Sstevel@tonic-gate  *
37*7c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
38*7c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
39*7c478bd9Sstevel@tonic-gate  * contributors.
40*7c478bd9Sstevel@tonic-gate  */
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate /*
45*7c478bd9Sstevel@tonic-gate  * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
46*7c478bd9Sstevel@tonic-gate  *
47*7c478bd9Sstevel@tonic-gate  * TCP based RPC supports 'batched calls'.
48*7c478bd9Sstevel@tonic-gate  * A sequence of calls may be batched-up in a send buffer.  The rpc call
49*7c478bd9Sstevel@tonic-gate  * return immediately to the client even though the call was not necessarily
50*7c478bd9Sstevel@tonic-gate  * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
51*7c478bd9Sstevel@tonic-gate  * the rpc timeout value is zero (see clnt.h, rpc).
52*7c478bd9Sstevel@tonic-gate  *
53*7c478bd9Sstevel@tonic-gate  * Clients should NOT casually batch calls that in fact return results; that is,
54*7c478bd9Sstevel@tonic-gate  * the server side should be aware that a call is batched and not produce any
55*7c478bd9Sstevel@tonic-gate  * return message.  Batched calls that produce many result messages can
56*7c478bd9Sstevel@tonic-gate  * deadlock (netlock) the client and the server....
57*7c478bd9Sstevel@tonic-gate  *
58*7c478bd9Sstevel@tonic-gate  * Now go hang yourself.
59*7c478bd9Sstevel@tonic-gate  */
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
63*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
64*7c478bd9Sstevel@tonic-gate #include <netdb.h>
65*7c478bd9Sstevel@tonic-gate #include <errno.h>
66*7c478bd9Sstevel@tonic-gate #include <rpc/pmap_clnt.h>
67*7c478bd9Sstevel@tonic-gate #include <syslog.h>
68*7c478bd9Sstevel@tonic-gate #include <malloc.h>
69*7c478bd9Sstevel@tonic-gate #include <stdio.h>
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate #define	MCALL_MSG_SIZE 24
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate extern int errno;
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate static int	readtcp();
76*7c478bd9Sstevel@tonic-gate static int	writetcp();
77*7c478bd9Sstevel@tonic-gate extern int _socket(int, int, int);
78*7c478bd9Sstevel@tonic-gate extern pid_t getpid();
79*7c478bd9Sstevel@tonic-gate extern int bindresvport(int, struct sockaddr_in *);
80*7c478bd9Sstevel@tonic-gate extern bool_t   xdr_opaque_auth(XDR *, struct opaque_auth *);
81*7c478bd9Sstevel@tonic-gate static struct clnt_ops *clnttcp_ops();
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate struct ct_data {
84*7c478bd9Sstevel@tonic-gate 	int		ct_sock;
85*7c478bd9Sstevel@tonic-gate 	bool_t		ct_closeit;
86*7c478bd9Sstevel@tonic-gate 	struct timeval	ct_wait;
87*7c478bd9Sstevel@tonic-gate 	bool_t		ct_waitset;	/* wait set by clnt_control? */
88*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in ct_addr;
89*7c478bd9Sstevel@tonic-gate 	struct rpc_err	ct_error;
90*7c478bd9Sstevel@tonic-gate 	char		ct_mcall[MCALL_MSG_SIZE];	/* marshalled callmsg */
91*7c478bd9Sstevel@tonic-gate 	u_int		ct_mpos;			/* pos after marshal */
92*7c478bd9Sstevel@tonic-gate 	XDR		ct_xdrs;
93*7c478bd9Sstevel@tonic-gate };
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate /*
96*7c478bd9Sstevel@tonic-gate  * Create a client handle for a tcp/ip connection.
97*7c478bd9Sstevel@tonic-gate  * If *sockp<0, *sockp is set to a newly created TCP socket and it is
98*7c478bd9Sstevel@tonic-gate  * connected to raddr.  If *sockp non-negative then
99*7c478bd9Sstevel@tonic-gate  * raddr is ignored.  The rpc/tcp package does buffering
100*7c478bd9Sstevel@tonic-gate  * similar to stdio, so the client must pick send and receive buffer sizes
101*7c478bd9Sstevel@tonic-gate  * 0 => use the default.
102*7c478bd9Sstevel@tonic-gate  * If raddr->sin_port is 0, then a binder on the remote machine is
103*7c478bd9Sstevel@tonic-gate  * consulted for the right port number.
104*7c478bd9Sstevel@tonic-gate  * NB: *sockp is copied into a private area.
105*7c478bd9Sstevel@tonic-gate  * NB: It is the clients responsibility to close *sockp.
106*7c478bd9Sstevel@tonic-gate  * NB: The rpch->cl_auth is set null authentication.  Caller may wish to
107*7c478bd9Sstevel@tonic-gate  * set this something more useful.
108*7c478bd9Sstevel@tonic-gate  */
109*7c478bd9Sstevel@tonic-gate CLIENT *
110*7c478bd9Sstevel@tonic-gate clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz)
111*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in *raddr;
112*7c478bd9Sstevel@tonic-gate 	rpcprog_t prog;
113*7c478bd9Sstevel@tonic-gate 	rpcvers_t vers;
114*7c478bd9Sstevel@tonic-gate 	register int *sockp;
115*7c478bd9Sstevel@tonic-gate 	u_int sendsz;
116*7c478bd9Sstevel@tonic-gate 	u_int recvsz;
117*7c478bd9Sstevel@tonic-gate {
118*7c478bd9Sstevel@tonic-gate 	CLIENT *h;
119*7c478bd9Sstevel@tonic-gate 	register struct ct_data *ct;
120*7c478bd9Sstevel@tonic-gate 	struct timeval now;
121*7c478bd9Sstevel@tonic-gate 	struct rpc_msg call_msg;
122*7c478bd9Sstevel@tonic-gate 	int i;
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 	h  = (CLIENT *)mem_alloc(sizeof (*h));
125*7c478bd9Sstevel@tonic-gate 	if (h == NULL) {
126*7c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "clnttcp_create: out of memory");
127*7c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
128*7c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_error.re_errno = errno;
129*7c478bd9Sstevel@tonic-gate 		goto fooy;
130*7c478bd9Sstevel@tonic-gate 	}
131*7c478bd9Sstevel@tonic-gate 	ct = (struct ct_data *)mem_alloc(sizeof (*ct));
132*7c478bd9Sstevel@tonic-gate 	if (ct == NULL) {
133*7c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "clnttcp_create: out of memory");
134*7c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
135*7c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_error.re_errno = errno;
136*7c478bd9Sstevel@tonic-gate 		goto fooy;
137*7c478bd9Sstevel@tonic-gate 	}
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate 	/*
140*7c478bd9Sstevel@tonic-gate 	 * If no port number given ask the pmap for one
141*7c478bd9Sstevel@tonic-gate 	 */
142*7c478bd9Sstevel@tonic-gate 	if (raddr->sin_port == 0) {
143*7c478bd9Sstevel@tonic-gate 		u_short port;
144*7c478bd9Sstevel@tonic-gate 		if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP))
145*7c478bd9Sstevel@tonic-gate 		    == 0) {
146*7c478bd9Sstevel@tonic-gate 			mem_free((caddr_t)ct, sizeof (struct ct_data));
147*7c478bd9Sstevel@tonic-gate 			mem_free((caddr_t)h, sizeof (CLIENT));
148*7c478bd9Sstevel@tonic-gate 			return ((CLIENT *)NULL);
149*7c478bd9Sstevel@tonic-gate 		}
150*7c478bd9Sstevel@tonic-gate 		raddr->sin_port = htons(port);
151*7c478bd9Sstevel@tonic-gate 	}
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate 	/*
154*7c478bd9Sstevel@tonic-gate 	 * If no socket given, open one
155*7c478bd9Sstevel@tonic-gate 	 */
156*7c478bd9Sstevel@tonic-gate 	if (*sockp < 0) {
157*7c478bd9Sstevel@tonic-gate 		*sockp = _socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
158*7c478bd9Sstevel@tonic-gate 		i = bindresvport(*sockp, (struct sockaddr_in *)0);
159*7c478bd9Sstevel@tonic-gate 		if ((*sockp < 0)||
160*7c478bd9Sstevel@tonic-gate 			(connect(*sockp, (struct sockaddr *)raddr,
161*7c478bd9Sstevel@tonic-gate 			sizeof (*raddr)) < 0)) {
162*7c478bd9Sstevel@tonic-gate 			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
163*7c478bd9Sstevel@tonic-gate 			rpc_createerr.cf_error.re_errno = errno;
164*7c478bd9Sstevel@tonic-gate 			(void) close(*sockp);
165*7c478bd9Sstevel@tonic-gate 			goto fooy;
166*7c478bd9Sstevel@tonic-gate 		}
167*7c478bd9Sstevel@tonic-gate 		ct->ct_closeit = TRUE;
168*7c478bd9Sstevel@tonic-gate 	} else {
169*7c478bd9Sstevel@tonic-gate 		ct->ct_closeit = FALSE;
170*7c478bd9Sstevel@tonic-gate 	}
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	/*
173*7c478bd9Sstevel@tonic-gate 	 * Set up private data struct
174*7c478bd9Sstevel@tonic-gate 	 */
175*7c478bd9Sstevel@tonic-gate 	ct->ct_sock = *sockp;
176*7c478bd9Sstevel@tonic-gate 	ct->ct_wait.tv_usec = 0;
177*7c478bd9Sstevel@tonic-gate 	ct->ct_waitset = FALSE;
178*7c478bd9Sstevel@tonic-gate 	ct->ct_addr = *raddr;
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	/*
181*7c478bd9Sstevel@tonic-gate 	 * Initialize call message
182*7c478bd9Sstevel@tonic-gate 	 */
183*7c478bd9Sstevel@tonic-gate 	(void) gettimeofday(&now, (struct timezone *)0);
184*7c478bd9Sstevel@tonic-gate 	call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
185*7c478bd9Sstevel@tonic-gate 	call_msg.rm_direction = CALL;
186*7c478bd9Sstevel@tonic-gate 	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
187*7c478bd9Sstevel@tonic-gate 	call_msg.rm_call.cb_prog = prog;
188*7c478bd9Sstevel@tonic-gate 	call_msg.rm_call.cb_vers = vers;
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	/*
191*7c478bd9Sstevel@tonic-gate 	 * pre-serialize the staic part of the call msg and stash it away
192*7c478bd9Sstevel@tonic-gate 	 */
193*7c478bd9Sstevel@tonic-gate 	xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
194*7c478bd9Sstevel@tonic-gate 	    XDR_ENCODE);
195*7c478bd9Sstevel@tonic-gate 	if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
196*7c478bd9Sstevel@tonic-gate 		if (ct->ct_closeit) {
197*7c478bd9Sstevel@tonic-gate 			(void) close(*sockp);
198*7c478bd9Sstevel@tonic-gate 		}
199*7c478bd9Sstevel@tonic-gate 		goto fooy;
200*7c478bd9Sstevel@tonic-gate 	}
201*7c478bd9Sstevel@tonic-gate 	ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
202*7c478bd9Sstevel@tonic-gate 	XDR_DESTROY(&(ct->ct_xdrs));
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	/*
205*7c478bd9Sstevel@tonic-gate 	 * Create a client handle which uses xdrrec for serialization
206*7c478bd9Sstevel@tonic-gate 	 * and authnone for authentication.
207*7c478bd9Sstevel@tonic-gate 	 */
208*7c478bd9Sstevel@tonic-gate 	xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
209*7c478bd9Sstevel@tonic-gate 	    (caddr_t)ct, readtcp, writetcp);
210*7c478bd9Sstevel@tonic-gate 	h->cl_ops = clnttcp_ops();
211*7c478bd9Sstevel@tonic-gate 	h->cl_private = (caddr_t) ct;
212*7c478bd9Sstevel@tonic-gate 	h->cl_auth = authnone_create();
213*7c478bd9Sstevel@tonic-gate 	return (h);
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate fooy:
216*7c478bd9Sstevel@tonic-gate 	/*
217*7c478bd9Sstevel@tonic-gate 	 * Something goofed, free stuff and barf
218*7c478bd9Sstevel@tonic-gate 	 */
219*7c478bd9Sstevel@tonic-gate 	mem_free((caddr_t)ct, sizeof (struct ct_data));
220*7c478bd9Sstevel@tonic-gate 	mem_free((caddr_t)h, sizeof (CLIENT));
221*7c478bd9Sstevel@tonic-gate 	return ((CLIENT *)NULL);
222*7c478bd9Sstevel@tonic-gate }
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate static enum clnt_stat
225*7c478bd9Sstevel@tonic-gate clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
226*7c478bd9Sstevel@tonic-gate 	register CLIENT *h;
227*7c478bd9Sstevel@tonic-gate 	rpcproc_t proc;
228*7c478bd9Sstevel@tonic-gate 	xdrproc_t xdr_args;
229*7c478bd9Sstevel@tonic-gate 	caddr_t args_ptr;
230*7c478bd9Sstevel@tonic-gate 	xdrproc_t xdr_results;
231*7c478bd9Sstevel@tonic-gate 	caddr_t results_ptr;
232*7c478bd9Sstevel@tonic-gate 	struct timeval timeout;
233*7c478bd9Sstevel@tonic-gate {
234*7c478bd9Sstevel@tonic-gate 	register struct ct_data *ct = (struct ct_data *) h->cl_private;
235*7c478bd9Sstevel@tonic-gate 	register XDR *xdrs = &(ct->ct_xdrs);
236*7c478bd9Sstevel@tonic-gate 	struct rpc_msg reply_msg;
237*7c478bd9Sstevel@tonic-gate 	uint32_t x_id;
238*7c478bd9Sstevel@tonic-gate 	uint32_t *msg_x_id = (uint32_t *)(ct->ct_mcall);	/* yuk */
239*7c478bd9Sstevel@tonic-gate 	register bool_t shipnow;
240*7c478bd9Sstevel@tonic-gate 	int refreshes = 2;
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	if (!ct->ct_waitset) {
243*7c478bd9Sstevel@tonic-gate 		ct->ct_wait = timeout;
244*7c478bd9Sstevel@tonic-gate 	}
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 	shipnow =
247*7c478bd9Sstevel@tonic-gate 	    (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 &&
248*7c478bd9Sstevel@tonic-gate 	    timeout.tv_usec == 0) ? FALSE : TRUE;
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate call_again:
251*7c478bd9Sstevel@tonic-gate 	xdrs->x_op = XDR_ENCODE;
252*7c478bd9Sstevel@tonic-gate 	ct->ct_error.re_status = RPC_SUCCESS;
253*7c478bd9Sstevel@tonic-gate 	x_id = ntohl(--(*msg_x_id));
254*7c478bd9Sstevel@tonic-gate 	if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
255*7c478bd9Sstevel@tonic-gate 	    (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
256*7c478bd9Sstevel@tonic-gate 	    (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
257*7c478bd9Sstevel@tonic-gate 	    (! (*xdr_args)(xdrs, args_ptr))) {
258*7c478bd9Sstevel@tonic-gate 		if (ct->ct_error.re_status == RPC_SUCCESS)
259*7c478bd9Sstevel@tonic-gate 			ct->ct_error.re_status = RPC_CANTENCODEARGS;
260*7c478bd9Sstevel@tonic-gate 		(void) xdrrec_endofrecord(xdrs, TRUE);
261*7c478bd9Sstevel@tonic-gate 		return (ct->ct_error.re_status);
262*7c478bd9Sstevel@tonic-gate 	}
263*7c478bd9Sstevel@tonic-gate 	if (! xdrrec_endofrecord(xdrs, shipnow))
264*7c478bd9Sstevel@tonic-gate 		return (ct->ct_error.re_status = RPC_CANTSEND);
265*7c478bd9Sstevel@tonic-gate 	if (! shipnow)
266*7c478bd9Sstevel@tonic-gate 		return (RPC_SUCCESS);
267*7c478bd9Sstevel@tonic-gate 	/*
268*7c478bd9Sstevel@tonic-gate 	 * Hack to provide rpc-based message passing
269*7c478bd9Sstevel@tonic-gate 	 */
270*7c478bd9Sstevel@tonic-gate 	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
271*7c478bd9Sstevel@tonic-gate 		return (ct->ct_error.re_status = RPC_TIMEDOUT);
272*7c478bd9Sstevel@tonic-gate 	}
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 	/*
276*7c478bd9Sstevel@tonic-gate 	 * Keep receiving until we get a valid transaction id
277*7c478bd9Sstevel@tonic-gate 	 */
278*7c478bd9Sstevel@tonic-gate 	xdrs->x_op = XDR_DECODE;
279*7c478bd9Sstevel@tonic-gate 	while (TRUE) {
280*7c478bd9Sstevel@tonic-gate 		reply_msg.acpted_rply.ar_verf = _null_auth;
281*7c478bd9Sstevel@tonic-gate 		reply_msg.acpted_rply.ar_results.where = NULL;
282*7c478bd9Sstevel@tonic-gate 		reply_msg.acpted_rply.ar_results.proc = xdr_void;
283*7c478bd9Sstevel@tonic-gate 		if (! xdrrec_skiprecord(xdrs))
284*7c478bd9Sstevel@tonic-gate 			return (ct->ct_error.re_status);
285*7c478bd9Sstevel@tonic-gate 			/* now decode and validate the response header */
286*7c478bd9Sstevel@tonic-gate 		if (! xdr_replymsg(xdrs, &reply_msg)) {
287*7c478bd9Sstevel@tonic-gate 			if (ct->ct_error.re_status == RPC_SUCCESS)
288*7c478bd9Sstevel@tonic-gate 				continue;
289*7c478bd9Sstevel@tonic-gate 			return (ct->ct_error.re_status);
290*7c478bd9Sstevel@tonic-gate 		}
291*7c478bd9Sstevel@tonic-gate 		if (reply_msg.rm_xid == x_id)
292*7c478bd9Sstevel@tonic-gate 			break;
293*7c478bd9Sstevel@tonic-gate 	}
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 	/*
296*7c478bd9Sstevel@tonic-gate 	 * process header
297*7c478bd9Sstevel@tonic-gate 	 */
298*7c478bd9Sstevel@tonic-gate 	__seterr_reply(&reply_msg, &(ct->ct_error));
299*7c478bd9Sstevel@tonic-gate 	if (ct->ct_error.re_status == RPC_SUCCESS) {
300*7c478bd9Sstevel@tonic-gate 		if (! AUTH_VALIDATE(h->cl_auth,
301*7c478bd9Sstevel@tonic-gate 		    &reply_msg.acpted_rply.ar_verf)) {
302*7c478bd9Sstevel@tonic-gate 			ct->ct_error.re_status = RPC_AUTHERROR;
303*7c478bd9Sstevel@tonic-gate 			ct->ct_error.re_why = AUTH_INVALIDRESP;
304*7c478bd9Sstevel@tonic-gate 		} else if (! (*xdr_results)(xdrs, results_ptr)) {
305*7c478bd9Sstevel@tonic-gate 			if (ct->ct_error.re_status == RPC_SUCCESS)
306*7c478bd9Sstevel@tonic-gate 				ct->ct_error.re_status = RPC_CANTDECODERES;
307*7c478bd9Sstevel@tonic-gate 		}
308*7c478bd9Sstevel@tonic-gate 		/* free verifier ... */
309*7c478bd9Sstevel@tonic-gate 		if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
310*7c478bd9Sstevel@tonic-gate 			xdrs->x_op = XDR_FREE;
311*7c478bd9Sstevel@tonic-gate 			(void) xdr_opaque_auth(xdrs,
312*7c478bd9Sstevel@tonic-gate 			    &(reply_msg.acpted_rply.ar_verf));
313*7c478bd9Sstevel@tonic-gate 		}
314*7c478bd9Sstevel@tonic-gate 	}  /* end successful completion */
315*7c478bd9Sstevel@tonic-gate 	else {
316*7c478bd9Sstevel@tonic-gate 		/* maybe our credentials need to be refreshed ... */
317*7c478bd9Sstevel@tonic-gate 		if (refreshes-- && AUTH_REFRESH(h->cl_auth, &reply_msg))
318*7c478bd9Sstevel@tonic-gate 			goto call_again;
319*7c478bd9Sstevel@tonic-gate 	}  /* end of unsuccessful completion */
320*7c478bd9Sstevel@tonic-gate 	return (ct->ct_error.re_status);
321*7c478bd9Sstevel@tonic-gate }
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate static void
324*7c478bd9Sstevel@tonic-gate clnttcp_geterr(h, errp)
325*7c478bd9Sstevel@tonic-gate 	CLIENT *h;
326*7c478bd9Sstevel@tonic-gate 	struct rpc_err *errp;
327*7c478bd9Sstevel@tonic-gate {
328*7c478bd9Sstevel@tonic-gate 	register struct ct_data *ct =
329*7c478bd9Sstevel@tonic-gate 	    (struct ct_data *) h->cl_private;
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 	*errp = ct->ct_error;
332*7c478bd9Sstevel@tonic-gate }
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate static bool_t
335*7c478bd9Sstevel@tonic-gate clnttcp_freeres(cl, xdr_res, res_ptr)
336*7c478bd9Sstevel@tonic-gate 	CLIENT *cl;
337*7c478bd9Sstevel@tonic-gate 	xdrproc_t xdr_res;
338*7c478bd9Sstevel@tonic-gate 	caddr_t res_ptr;
339*7c478bd9Sstevel@tonic-gate {
340*7c478bd9Sstevel@tonic-gate 	register struct ct_data *ct = (struct ct_data *)cl->cl_private;
341*7c478bd9Sstevel@tonic-gate 	register XDR *xdrs = &(ct->ct_xdrs);
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	xdrs->x_op = XDR_FREE;
344*7c478bd9Sstevel@tonic-gate 	return ((*xdr_res)(xdrs, res_ptr));
345*7c478bd9Sstevel@tonic-gate }
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate static void
348*7c478bd9Sstevel@tonic-gate clnttcp_abort()
349*7c478bd9Sstevel@tonic-gate {
350*7c478bd9Sstevel@tonic-gate }
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate static bool_t
353*7c478bd9Sstevel@tonic-gate clnttcp_control(cl, request, info)
354*7c478bd9Sstevel@tonic-gate 	CLIENT *cl;
355*7c478bd9Sstevel@tonic-gate 	int request;
356*7c478bd9Sstevel@tonic-gate 	char *info;
357*7c478bd9Sstevel@tonic-gate {
358*7c478bd9Sstevel@tonic-gate 	register struct ct_data *ct = (struct ct_data *)cl->cl_private;
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	switch (request) {
361*7c478bd9Sstevel@tonic-gate 	case CLSET_TIMEOUT:
362*7c478bd9Sstevel@tonic-gate 		ct->ct_wait = *(struct timeval *)info;
363*7c478bd9Sstevel@tonic-gate 		ct->ct_waitset = TRUE;
364*7c478bd9Sstevel@tonic-gate 		break;
365*7c478bd9Sstevel@tonic-gate 	case CLGET_TIMEOUT:
366*7c478bd9Sstevel@tonic-gate 		*(struct timeval *)info = ct->ct_wait;
367*7c478bd9Sstevel@tonic-gate 		break;
368*7c478bd9Sstevel@tonic-gate 	case CLGET_SERVER_ADDR:
369*7c478bd9Sstevel@tonic-gate 		*(struct sockaddr_in *)info = ct->ct_addr;
370*7c478bd9Sstevel@tonic-gate 		break;
371*7c478bd9Sstevel@tonic-gate 	case CLGET_FD:
372*7c478bd9Sstevel@tonic-gate 		*(int *)info = ct->ct_sock;
373*7c478bd9Sstevel@tonic-gate 		break;
374*7c478bd9Sstevel@tonic-gate 	case CLSET_FD_CLOSE:
375*7c478bd9Sstevel@tonic-gate 		ct->ct_closeit = TRUE;
376*7c478bd9Sstevel@tonic-gate 		break;
377*7c478bd9Sstevel@tonic-gate 	case CLSET_FD_NCLOSE:
378*7c478bd9Sstevel@tonic-gate 		ct->ct_closeit = FALSE;
379*7c478bd9Sstevel@tonic-gate 		break;
380*7c478bd9Sstevel@tonic-gate 	default:
381*7c478bd9Sstevel@tonic-gate 		return (FALSE);
382*7c478bd9Sstevel@tonic-gate 	}
383*7c478bd9Sstevel@tonic-gate 	return (TRUE);
384*7c478bd9Sstevel@tonic-gate }
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate static void
388*7c478bd9Sstevel@tonic-gate clnttcp_destroy(h)
389*7c478bd9Sstevel@tonic-gate 	CLIENT *h;
390*7c478bd9Sstevel@tonic-gate {
391*7c478bd9Sstevel@tonic-gate 	register struct ct_data *ct =
392*7c478bd9Sstevel@tonic-gate 	    (struct ct_data *) h->cl_private;
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	if (ct->ct_closeit) {
395*7c478bd9Sstevel@tonic-gate 		(void) close(ct->ct_sock);
396*7c478bd9Sstevel@tonic-gate 	}
397*7c478bd9Sstevel@tonic-gate 	XDR_DESTROY(&(ct->ct_xdrs));
398*7c478bd9Sstevel@tonic-gate 	mem_free((caddr_t)ct, sizeof (struct ct_data));
399*7c478bd9Sstevel@tonic-gate 	mem_free((caddr_t)h, sizeof (CLIENT));
400*7c478bd9Sstevel@tonic-gate }
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate /*
403*7c478bd9Sstevel@tonic-gate  * Interface between xdr serializer and tcp connection.
404*7c478bd9Sstevel@tonic-gate  * Behaves like the system calls, read & write, but keeps some error state
405*7c478bd9Sstevel@tonic-gate  * around for the rpc level.
406*7c478bd9Sstevel@tonic-gate  */
407*7c478bd9Sstevel@tonic-gate static int
408*7c478bd9Sstevel@tonic-gate readtcp(ct, buf, len)
409*7c478bd9Sstevel@tonic-gate 	register struct ct_data *ct;
410*7c478bd9Sstevel@tonic-gate 	caddr_t buf;
411*7c478bd9Sstevel@tonic-gate 	register int len;
412*7c478bd9Sstevel@tonic-gate {
413*7c478bd9Sstevel@tonic-gate 	fd_set mask;
414*7c478bd9Sstevel@tonic-gate 	fd_set readfds;
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate 	if (len == 0)
417*7c478bd9Sstevel@tonic-gate 		return (0);
418*7c478bd9Sstevel@tonic-gate 	FD_ZERO(&mask);
419*7c478bd9Sstevel@tonic-gate 	FD_SET(ct->ct_sock, &mask);
420*7c478bd9Sstevel@tonic-gate 	while (TRUE) {
421*7c478bd9Sstevel@tonic-gate 		readfds = mask;
422*7c478bd9Sstevel@tonic-gate 		switch (select(__rpc_dtbsize(),
423*7c478bd9Sstevel@tonic-gate 		    &readfds, NULL, NULL, &(ct->ct_wait))) {
424*7c478bd9Sstevel@tonic-gate 		case 0:
425*7c478bd9Sstevel@tonic-gate 			ct->ct_error.re_status = RPC_TIMEDOUT;
426*7c478bd9Sstevel@tonic-gate 			return (-1);
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 		case -1:
429*7c478bd9Sstevel@tonic-gate 			if (errno == EINTR)
430*7c478bd9Sstevel@tonic-gate 				continue;
431*7c478bd9Sstevel@tonic-gate 			ct->ct_error.re_status = RPC_CANTRECV;
432*7c478bd9Sstevel@tonic-gate 			ct->ct_error.re_errno = errno;
433*7c478bd9Sstevel@tonic-gate 			return (-1);
434*7c478bd9Sstevel@tonic-gate 		}
435*7c478bd9Sstevel@tonic-gate 		break;
436*7c478bd9Sstevel@tonic-gate 	}
437*7c478bd9Sstevel@tonic-gate 	switch (len = read(ct->ct_sock, buf, len)) {
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate 	case 0:
440*7c478bd9Sstevel@tonic-gate 		/* premature eof */
441*7c478bd9Sstevel@tonic-gate 		ct->ct_error.re_errno = ECONNRESET;
442*7c478bd9Sstevel@tonic-gate 		ct->ct_error.re_status = RPC_CANTRECV;
443*7c478bd9Sstevel@tonic-gate 		len = -1;  /* it's really an error */
444*7c478bd9Sstevel@tonic-gate 		break;
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 	case -1:
447*7c478bd9Sstevel@tonic-gate 		ct->ct_error.re_errno = errno;
448*7c478bd9Sstevel@tonic-gate 		ct->ct_error.re_status = RPC_CANTRECV;
449*7c478bd9Sstevel@tonic-gate 		break;
450*7c478bd9Sstevel@tonic-gate 	}
451*7c478bd9Sstevel@tonic-gate 	return (len);
452*7c478bd9Sstevel@tonic-gate }
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate static int
455*7c478bd9Sstevel@tonic-gate writetcp(ct, buf, len)
456*7c478bd9Sstevel@tonic-gate 	struct ct_data *ct;
457*7c478bd9Sstevel@tonic-gate 	caddr_t buf;
458*7c478bd9Sstevel@tonic-gate 	int len;
459*7c478bd9Sstevel@tonic-gate {
460*7c478bd9Sstevel@tonic-gate 	register int i, cnt;
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 	for (cnt = len; cnt > 0; cnt -= i, buf += i) {
463*7c478bd9Sstevel@tonic-gate 		if ((i = write(ct->ct_sock, buf, cnt)) == -1) {
464*7c478bd9Sstevel@tonic-gate 			ct->ct_error.re_errno = errno;
465*7c478bd9Sstevel@tonic-gate 			ct->ct_error.re_status = RPC_CANTSEND;
466*7c478bd9Sstevel@tonic-gate 			return (-1);
467*7c478bd9Sstevel@tonic-gate 		}
468*7c478bd9Sstevel@tonic-gate 	}
469*7c478bd9Sstevel@tonic-gate 	return (len);
470*7c478bd9Sstevel@tonic-gate }
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate static struct clnt_ops *
473*7c478bd9Sstevel@tonic-gate clnttcp_ops()
474*7c478bd9Sstevel@tonic-gate {
475*7c478bd9Sstevel@tonic-gate 	static struct clnt_ops ops;
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	if (ops.cl_call == NULL) {
478*7c478bd9Sstevel@tonic-gate 		ops.cl_call = clnttcp_call;
479*7c478bd9Sstevel@tonic-gate 		ops.cl_abort = clnttcp_abort;
480*7c478bd9Sstevel@tonic-gate 		ops.cl_geterr = clnttcp_geterr;
481*7c478bd9Sstevel@tonic-gate 		ops.cl_freeres = clnttcp_freeres;
482*7c478bd9Sstevel@tonic-gate 		ops.cl_destroy = clnttcp_destroy;
483*7c478bd9Sstevel@tonic-gate 		ops.cl_control = clnttcp_control;
484*7c478bd9Sstevel@tonic-gate 	}
485*7c478bd9Sstevel@tonic-gate 	return (&ops);
486*7c478bd9Sstevel@tonic-gate }
487