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