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