clnt_vc.c revision 74627
121308Sache/* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */ 221308Sache/* $FreeBSD: head/lib/libc/rpc/clnt_vc.c 74627 2001-03-22 04:31:30Z alfred $ */ 321308Sache 421308Sache/* 521308Sache * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 621308Sache * unrestricted use provided that this legend is included on all tape 721308Sache * media and as a part of the software program in whole or part. Users 821308Sache * may copy or modify Sun RPC without charge, but are not authorized 921308Sache * to license or distribute it to anyone else except as part of a product or 1058310Sache * program developed by the user. 1121308Sache * 1221308Sache * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 1321308Sache * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 1421308Sache * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 1521308Sache * 1621308Sache * Sun RPC is provided with no support and without any obligation on the 1721308Sache * part of Sun Microsystems, Inc. to assist in its use, correction, 1821308Sache * modification or enhancement. 1921308Sache * 2021308Sache * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 2158310Sache * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 2221308Sache * OR ANY PART THEREOF. 2321308Sache * 2421308Sache * In no event will Sun Microsystems, Inc. be liable for any lost revenue 2521308Sache * or profits or other special, indirect and consequential damages, even if 2621308Sache * Sun has been advised of the possibility of such damages. 2721308Sache * 2821308Sache * Sun Microsystems, Inc. 2921308Sache * 2550 Garcia Avenue 3021308Sache * Mountain View, California 94043 3121308Sache */ 3221308Sache 3321308Sache#include <sys/cdefs.h> 3421308Sache#if defined(LIBC_SCCS) && !defined(lint) 3521308Sachestatic char *sccsid = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro"; 3675406Sachestatic char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 3775406Sachestatic char sccsid[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 3875406Sache#endif 3975406Sache 4075406Sache/* 4175406Sache * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 4275406Sache * 4375406Sache * Copyright (C) 1984, Sun Microsystems, Inc. 44119610Sache * 4575406Sache * TCP based RPC supports 'batched calls'. 4675406Sache * A sequence of calls may be batched-up in a send buffer. The rpc call 4775406Sache * return immediately to the client even though the call was not necessarily 4875406Sache * sent. The batching occurs if the results' xdr routine is NULL (0) AND 4975406Sache * the rpc timeout value is zero (see clnt.h, rpc). 5075406Sache * 5175406Sache * Clients should NOT casually batch calls that in fact return results; that is, 5275406Sache * the server side should be aware that a call is batched and not produce any 5375406Sache * return message. Batched calls that produce many result messages can 5475406Sache * deadlock (netlock) the client and the server.... 5575406Sache * 5675406Sache * Now go hang yourself. 5775406Sache */ 5875406Sache 5975406Sache#include "reentrant.h" 6075406Sache#include "namespace.h" 6175406Sache#include <sys/types.h> 6275406Sache#include <sys/poll.h> 6321308Sache#include <sys/syslog.h> 6475406Sache#include <sys/socket.h> 6575406Sache#include <sys/un.h> 6675406Sache#include <sys/uio.h> 6775406Sache 6875406Sache#include <assert.h> 6921308Sache#include <err.h> 7021308Sache#include <errno.h> 71119610Sache#include <netdb.h> 7275406Sache#include <stdio.h> 7375406Sache#include <stdlib.h> 7475406Sache#include <string.h> 7575406Sache#include <unistd.h> 7675406Sache#include <signal.h> 7775406Sache 7875406Sache#include <rpc/rpc.h> 7975406Sache#include "un-namespace.h" 8075406Sache#include "rpc_com.h" 8175406Sache 8275406Sache#define MCALL_MSG_SIZE 24 8375406Sache 8475406Sachestatic enum clnt_stat clnt_vc_call __P((CLIENT *, rpcproc_t, xdrproc_t, caddr_t, 8575406Sache xdrproc_t, caddr_t, struct timeval)); 8675406Sachestatic void clnt_vc_geterr __P((CLIENT *, struct rpc_err *)); 8721308Sachestatic bool_t clnt_vc_freeres __P((CLIENT *, xdrproc_t, caddr_t)); 8821308Sachestatic void clnt_vc_abort __P((CLIENT *)); 8975406Sachestatic bool_t clnt_vc_control __P((CLIENT *, u_int, char *)); 9075406Sachestatic void clnt_vc_destroy __P((CLIENT *)); 9175406Sachestatic struct clnt_ops *clnt_vc_ops __P((void)); 9275406Sachestatic bool_t time_not_ok __P((struct timeval *)); 9375406Sachestatic int read_vc __P((caddr_t, caddr_t, int)); 9475406Sachestatic int write_vc __P((caddr_t, caddr_t, int)); 9575406Sachestatic int __msgwrite(int, void *, size_t); 9675406Sachestatic int __msgread(int, void *, size_t); 9775406Sache 9875406Sachestruct ct_data { 9921308Sache int ct_fd; /* connection's fd */ 10021308Sache bool_t ct_closeit; /* close it on destroy */ 10175406Sache struct timeval ct_wait; /* wait interval in milliseconds */ 10275406Sache bool_t ct_waitset; /* wait set by clnt_control? */ 10375406Sache struct netbuf ct_addr; /* remote addr */ 10475406Sache struct rpc_err ct_error; 10575406Sache union { 10675406Sache char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */ 10775406Sache u_int32_t ct_mcalli; 10821308Sache } ct_u; 10921308Sache u_int ct_mpos; /* pos after marshal */ 11075406Sache XDR ct_xdrs; /* XDR stream */ 11175406Sache}; 11275406Sache 11375406Sache/* 11475406Sache * This machinery implements per-fd locks for MT-safety. It is not 11575406Sache * sufficient to do per-CLIENT handle locks for MT-safety because a 11675406Sache * user may create more than one CLIENT handle with the same fd behind 11775406Sache * it. Therfore, we allocate an array of flags (vc_fd_locks), protected 11875406Sache * by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables 11975406Sache * similarly protected. Vc_fd_lock[fd] == 1 => a call is activte on some 12075406Sache * CLIENT handle created for that fd. 12175406Sache * The current implementation holds locks across the entire RPC and reply. 12275406Sache * Yes, this is silly, and as soon as this code is proven to work, this 12375406Sache * should be the first thing fixed. One step at a time. 12475406Sache */ 12575406Sachestatic int *vc_fd_locks; 12675406Sacheextern mutex_t clnt_fd_lock; 12775406Sachestatic cond_t *vc_cv; 12875406Sache#define release_fd_lock(fd, mask) { \ 12975406Sache mutex_lock(&clnt_fd_lock); \ 13075406Sache if (__isthreaded) \ 13175406Sache vc_fd_locks[fd] = 0; \ 13275406Sache mutex_unlock(&clnt_fd_lock); \ 133157184Sache thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \ 13475406Sache cond_signal(&vc_cv[fd]); \ 13575406Sache} 13621308Sache 13721308Sachestatic const char clnt_vc_errstr[] = "%s : %s"; 13875406Sachestatic const char clnt_vc_str[] = "clnt_vc_create"; 13975406Sachestatic const char clnt_read_vc_str[] = "read_vc"; 14075406Sachestatic const char __no_mem_str[] = "out of memory"; 14175406Sache 14275406Sache/* 14375406Sache * Create a client handle for a connection. 14421308Sache * Default options are set, which the user can change using clnt_control()'s. 14521308Sache * The rpc/vc package does buffering similar to stdio, so the client 14675406Sache * must pick send and receive buffer sizes, 0 => use the default. 14775406Sache * NB: fd is copied into a private area. 14875406Sache * NB: The rpch->cl_auth is set null authentication. Caller may wish to 14975406Sache * set this something more useful. 15075406Sache * 15175406Sache * fd should be an open socket 15275406Sache */ 153119610SacheCLIENT * 15475406Sacheclnt_vc_create(fd, raddr, prog, vers, sendsz, recvsz) 15575406Sache int fd; /* open file descriptor */ 15675406Sache const struct netbuf *raddr; /* servers address */ 157119610Sache rpcprog_t prog; /* program number */ 15875406Sache rpcvers_t vers; /* version number */ 15975406Sache u_int sendsz; /* buffer recv size */ 16075406Sache u_int recvsz; /* buffer send size */ 16175406Sache{ 16275406Sache CLIENT *cl; /* client handle */ 16375406Sache struct ct_data *ct = NULL; /* client handle */ 16475406Sache struct timeval now; 16575406Sache struct rpc_msg call_msg; 16675406Sache static u_int32_t disrupt; 16775406Sache sigset_t mask; 16875406Sache sigset_t newmask; 16975406Sache struct sockaddr_storage ss; 17075406Sache socklen_t slen; 17175406Sache struct __rpc_sockinfo si; 17221308Sache 17321308Sache if (disrupt == 0) 17475406Sache disrupt = (u_int32_t)(long)raddr; 17575406Sache 17675406Sache cl = (CLIENT *)mem_alloc(sizeof (*cl)); 17775406Sache ct = (struct ct_data *)mem_alloc(sizeof (*ct)); 17875406Sache if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) { 17921308Sache (void) syslog(LOG_ERR, clnt_vc_errstr, 18021308Sache clnt_vc_str, __no_mem_str); 18121308Sache rpc_createerr.cf_stat = RPC_SYSTEMERROR; 18275406Sache rpc_createerr.cf_error.re_errno = errno; 18375406Sache goto err; 18475406Sache } 18575406Sache ct->ct_addr.buf = NULL; 18675406Sache sigfillset(&newmask); 18775406Sache thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 18875406Sache mutex_lock(&clnt_fd_lock); 18975406Sache if (vc_fd_locks == (int *) NULL) { 19075406Sache int cv_allocsz, fd_allocsz; 19175406Sache int dtbsize = __rpc_dtbsize(); 19275406Sache 19375406Sache fd_allocsz = dtbsize * sizeof (int); 19475406Sache vc_fd_locks = (int *) mem_alloc(fd_allocsz); 19575406Sache if (vc_fd_locks == (int *) NULL) { 19675406Sache mutex_unlock(&clnt_fd_lock); 19775406Sache thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 19875406Sache goto err; 19975406Sache } else 20075406Sache memset(vc_fd_locks, '\0', fd_allocsz); 20175406Sache 20275406Sache assert(vc_cv == (cond_t *) NULL); 20375406Sache cv_allocsz = dtbsize * sizeof (cond_t); 20475406Sache vc_cv = (cond_t *) mem_alloc(cv_allocsz); 20575406Sache if (vc_cv == (cond_t *) NULL) { 20675406Sache mem_free(vc_fd_locks, fd_allocsz); 20775406Sache vc_fd_locks = (int *) NULL; 20875406Sache mutex_unlock(&clnt_fd_lock); 20975406Sache thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 21075406Sache goto err; 21175406Sache } else { 21275406Sache int i; 21375406Sache 21475406Sache for (i = 0; i < dtbsize; i++) 21575406Sache cond_init(&vc_cv[i], 0, (void *) 0); 21675406Sache } 21775406Sache } else 21875406Sache assert(vc_cv != (cond_t *) NULL); 21975406Sache 22075406Sache /* 22175406Sache * XXX - fvdl connecting while holding a mutex? 22275406Sache */ 22375406Sache slen = sizeof ss; 22475406Sache if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 22575406Sache if (errno != ENOTCONN) { 22675406Sache rpc_createerr.cf_stat = RPC_SYSTEMERROR; 22775406Sache rpc_createerr.cf_error.re_errno = errno; 22875406Sache mutex_unlock(&clnt_fd_lock); 22975406Sache goto err; 23075406Sache } 23175406Sache if (_connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){ 23275406Sache rpc_createerr.cf_stat = RPC_SYSTEMERROR; 23375406Sache rpc_createerr.cf_error.re_errno = errno; 23475406Sache mutex_unlock(&clnt_fd_lock); 23575406Sache goto err; 23675406Sache } 23775406Sache } 23875406Sache mutex_unlock(&clnt_fd_lock); 23975406Sache if (!__rpc_fd2sockinfo(fd, &si)) 24075406Sache goto err; 24175406Sache thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 24275406Sache 24375406Sache ct->ct_closeit = FALSE; 24475406Sache 24575406Sache /* 24675406Sache * Set up private data struct 24775406Sache */ 24875406Sache ct->ct_fd = fd; 24975406Sache ct->ct_wait.tv_usec = 0; 25075406Sache ct->ct_waitset = FALSE; 25175406Sache ct->ct_addr.buf = malloc(raddr->maxlen); 25275406Sache if (ct->ct_addr.buf == NULL) 25375406Sache goto err; 25475406Sache memcpy(ct->ct_addr.buf, &raddr->buf, raddr->len); 25575406Sache ct->ct_addr.len = raddr->maxlen; 25675406Sache ct->ct_addr.maxlen = raddr->maxlen; 25775406Sache 25875406Sache /* 25975406Sache * Initialize call message 26075406Sache */ 26175406Sache (void)gettimeofday(&now, NULL); 26275406Sache call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now); 26375406Sache call_msg.rm_direction = CALL; 26475406Sache call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 26575406Sache call_msg.rm_call.cb_prog = (u_int32_t)prog; 26675406Sache call_msg.rm_call.cb_vers = (u_int32_t)vers; 26775406Sache 26875406Sache /* 26975406Sache * pre-serialize the static part of the call msg and stash it away 27075406Sache */ 27175406Sache xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE, 27275406Sache XDR_ENCODE); 27375406Sache if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 27475406Sache if (ct->ct_closeit) { 27575406Sache (void)_close(fd); 27675406Sache } 27775406Sache goto err; 27875406Sache } 27975406Sache ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 28075406Sache XDR_DESTROY(&(ct->ct_xdrs)); 28175406Sache 28275406Sache /* 28375406Sache * Create a client handle which uses xdrrec for serialization 28475406Sache * and authnone for authentication. 28575406Sache */ 28675406Sache cl->cl_ops = clnt_vc_ops(); 28775406Sache cl->cl_private = ct; 28875406Sache cl->cl_auth = authnone_create(); 28975406Sache sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 29075406Sache recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 29175406Sache xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 29275406Sache cl->cl_private, read_vc, write_vc); 29375406Sache return (cl); 29475406Sache 29575406Sacheerr: 29675406Sache if (cl) { 29775406Sache if (ct) { 29875406Sache if (ct->ct_addr.len) 29975406Sache mem_free(ct->ct_addr.buf, ct->ct_addr.len); 30075406Sache mem_free((caddr_t)ct, sizeof (struct ct_data)); 30175406Sache } 30275406Sache if (cl) 30375406Sache mem_free((caddr_t)cl, sizeof (CLIENT)); 30475406Sache } 30575406Sache return ((CLIENT *)NULL); 30675406Sache} 30775406Sache 30875406Sachestatic enum clnt_stat 30975406Sacheclnt_vc_call(cl, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) 31021308Sache CLIENT *cl; 31121308Sache rpcproc_t proc; 31221308Sache xdrproc_t xdr_args; 31321308Sache caddr_t args_ptr; 31421308Sache xdrproc_t xdr_results; 31521308Sache caddr_t results_ptr; 31675406Sache struct timeval timeout; 31775406Sache{ 31875406Sache struct ct_data *ct = (struct ct_data *) cl->cl_private; 31975406Sache XDR *xdrs = &(ct->ct_xdrs); 32075406Sache struct rpc_msg reply_msg; 32175406Sache u_int32_t x_id; 32275406Sache u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */ 32375406Sache bool_t shipnow; 32475406Sache int refreshes = 2; 32575406Sache sigset_t mask, newmask; 32675406Sache int rpc_lock_value; 32775406Sache 32875406Sache assert(cl != NULL); 32975406Sache 33075406Sache sigfillset(&newmask); 33175406Sache thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 33275406Sache mutex_lock(&clnt_fd_lock); 33375406Sache while (vc_fd_locks[ct->ct_fd]) 33475406Sache cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 33575406Sache if (__isthreaded) 33675406Sache rpc_lock_value = 1; 33775406Sache else 33875406Sache rpc_lock_value = 0; 33975406Sache vc_fd_locks[ct->ct_fd] = rpc_lock_value; 34075406Sache mutex_unlock(&clnt_fd_lock); 34175406Sache if (!ct->ct_waitset) { 34275406Sache /* If time is not within limits, we ignore it. */ 34321308Sache if (time_not_ok(&timeout) == FALSE) 34475406Sache ct->ct_wait = timeout; 34575406Sache } 34675406Sache 34775406Sache shipnow = 34875406Sache (xdr_results == NULL && timeout.tv_sec == 0 34921308Sache && timeout.tv_usec == 0) ? FALSE : TRUE; 35021308Sache 35175406Sachecall_again: 35275406Sache xdrs->x_op = XDR_ENCODE; 35375406Sache ct->ct_error.re_status = RPC_SUCCESS; 35475406Sache x_id = ntohl(--(*msg_x_id)); 35575406Sache 35675406Sache if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) || 35775406Sache (! XDR_PUTINT32(xdrs, &proc)) || 35875406Sache (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || 35975406Sache (! (*xdr_args)(xdrs, args_ptr))) { 36075406Sache if (ct->ct_error.re_status == RPC_SUCCESS) 36175406Sache ct->ct_error.re_status = RPC_CANTENCODEARGS; 36275406Sache (void)xdrrec_endofrecord(xdrs, TRUE); 36375406Sache release_fd_lock(ct->ct_fd, mask); 36475406Sache return (ct->ct_error.re_status); 36575406Sache } 36675406Sache if (! xdrrec_endofrecord(xdrs, shipnow)) { 36721308Sache release_fd_lock(ct->ct_fd, mask); 36821308Sache return (ct->ct_error.re_status = RPC_CANTSEND); 36975406Sache } 37075406Sache if (! shipnow) { 37175406Sache release_fd_lock(ct->ct_fd, mask); 37275406Sache return (RPC_SUCCESS); 37375406Sache } 37475406Sache /* 37575406Sache * Hack to provide rpc-based message passing 37675406Sache */ 37775406Sache if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 37875406Sache release_fd_lock(ct->ct_fd, mask); 37921308Sache return(ct->ct_error.re_status = RPC_TIMEDOUT); 38021308Sache } 38175406Sache 38275406Sache 38375406Sache /* 38475406Sache * Keep receiving until we get a valid transaction id 38575406Sache */ 38675406Sache xdrs->x_op = XDR_DECODE; 38775406Sache while (TRUE) { 38821308Sache reply_msg.acpted_rply.ar_verf = _null_auth; 38921308Sache reply_msg.acpted_rply.ar_results.where = NULL; 39075406Sache reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 39175406Sache if (! xdrrec_skiprecord(xdrs)) { 39275406Sache release_fd_lock(ct->ct_fd, mask); 39375406Sache return (ct->ct_error.re_status); 39475406Sache } 39575406Sache /* now decode and validate the response header */ 39675406Sache if (! xdr_replymsg(xdrs, &reply_msg)) { 39775406Sache if (ct->ct_error.re_status == RPC_SUCCESS) 39875406Sache continue; 39975406Sache release_fd_lock(ct->ct_fd, mask); 40075406Sache return (ct->ct_error.re_status); 40175406Sache } 40275406Sache if (reply_msg.rm_xid == x_id) 40375406Sache break; 40475406Sache } 40575406Sache 40675406Sache /* 40775406Sache * process header 40875406Sache */ 40975406Sache _seterr_reply(&reply_msg, &(ct->ct_error)); 41075406Sache if (ct->ct_error.re_status == RPC_SUCCESS) { 41175406Sache if (! AUTH_VALIDATE(cl->cl_auth, 41275406Sache &reply_msg.acpted_rply.ar_verf)) { 41375406Sache ct->ct_error.re_status = RPC_AUTHERROR; 41475406Sache ct->ct_error.re_why = AUTH_INVALIDRESP; 41575406Sache } else if (! (*xdr_results)(xdrs, results_ptr)) { 41621308Sache if (ct->ct_error.re_status == RPC_SUCCESS) 41721308Sache ct->ct_error.re_status = RPC_CANTDECODERES; 41875406Sache } 41975406Sache /* free verifier ... */ 42075406Sache if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 42175406Sache xdrs->x_op = XDR_FREE; 42275406Sache (void)xdr_opaque_auth(xdrs, 42375406Sache &(reply_msg.acpted_rply.ar_verf)); 42421308Sache } 42521308Sache } /* end successful completion */ 42675406Sache else { 42775406Sache /* maybe our credentials need to be refreshed ... */ 42875406Sache if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg)) 42975406Sache goto call_again; 43075406Sache } /* end of unsuccessful completion */ 43175406Sache release_fd_lock(ct->ct_fd, mask); 43275406Sache return (ct->ct_error.re_status); 43375406Sache} 43475406Sache 43575406Sachestatic void 43675406Sacheclnt_vc_geterr(cl, errp) 43775406Sache CLIENT *cl; 43875406Sache struct rpc_err *errp; 43975406Sache{ 44075406Sache struct ct_data *ct; 44175406Sache 44275406Sache assert(cl != NULL); 44375406Sache assert(errp != NULL); 44475406Sache 44575406Sache ct = (struct ct_data *) cl->cl_private; 44675406Sache *errp = ct->ct_error; 44775406Sache} 44875406Sache 44975406Sachestatic bool_t 45075406Sacheclnt_vc_freeres(cl, xdr_res, res_ptr) 45175406Sache CLIENT *cl; 45221308Sache xdrproc_t xdr_res; 45321308Sache caddr_t res_ptr; 45475406Sache{ 45575406Sache struct ct_data *ct; 45675406Sache XDR *xdrs; 45775406Sache bool_t dummy; 45875406Sache sigset_t mask; 45921308Sache sigset_t newmask; 46021308Sache 46121308Sache assert(cl != NULL); 46221308Sache 46321308Sache ct = (struct ct_data *)cl->cl_private; 46421308Sache xdrs = &(ct->ct_xdrs); 46521308Sache 46621308Sache sigfillset(&newmask); 46721308Sache thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 46821308Sache mutex_lock(&clnt_fd_lock); 46921308Sache while (vc_fd_locks[ct->ct_fd]) 47021308Sache cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 47121308Sache xdrs->x_op = XDR_FREE; 47221308Sache dummy = (*xdr_res)(xdrs, res_ptr); 47321308Sache mutex_unlock(&clnt_fd_lock); 47421308Sache thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 47521308Sache cond_signal(&vc_cv[ct->ct_fd]); 47621308Sache 47721308Sache return dummy; 47821308Sache} 47921308Sache 48021308Sache/*ARGSUSED*/ 48121308Sachestatic void 48221308Sacheclnt_vc_abort(cl) 48321308Sache CLIENT *cl; 48421308Sache{ 48521308Sache} 48621308Sache 48721308Sachestatic bool_t 48821308Sacheclnt_vc_control(cl, request, info) 48921308Sache CLIENT *cl; 49021308Sache u_int request; 49121308Sache char *info; 49221308Sache{ 49321308Sache struct ct_data *ct; 49421308Sache void *infop = info; 49521308Sache sigset_t mask; 49621308Sache sigset_t newmask; 49721308Sache int rpc_lock_value; 49821308Sache 49921308Sache assert(cl != NULL); 50021308Sache 50121308Sache ct = (struct ct_data *)cl->cl_private; 50221308Sache 50321308Sache sigfillset(&newmask); 50421308Sache thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 50521308Sache mutex_lock(&clnt_fd_lock); 50621308Sache while (vc_fd_locks[ct->ct_fd]) 50721308Sache cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 50821308Sache if (__isthreaded) 50921308Sache rpc_lock_value = 1; 51021308Sache else 51121308Sache rpc_lock_value = 0; 51221308Sache vc_fd_locks[ct->ct_fd] = rpc_lock_value; 51321308Sache mutex_unlock(&clnt_fd_lock); 51421308Sache 51521308Sache switch (request) { 51621308Sache case CLSET_FD_CLOSE: 51721308Sache ct->ct_closeit = TRUE; 51821308Sache release_fd_lock(ct->ct_fd, mask); 51921308Sache return (TRUE); 52021308Sache case CLSET_FD_NCLOSE: 52121308Sache ct->ct_closeit = FALSE; 52221308Sache release_fd_lock(ct->ct_fd, mask); 52321308Sache return (TRUE); 52421308Sache default: 52521308Sache break; 52621308Sache } 52721308Sache 52821308Sache /* for other requests which use info */ 52921308Sache if (info == NULL) { 53021308Sache release_fd_lock(ct->ct_fd, mask); 53121308Sache return (FALSE); 53221308Sache } 53321308Sache switch (request) { 53421308Sache case CLSET_TIMEOUT: 53521308Sache if (time_not_ok((struct timeval *)(void *)info)) { 53621308Sache release_fd_lock(ct->ct_fd, mask); 53721308Sache return (FALSE); 53821308Sache } 53921308Sache ct->ct_wait = *(struct timeval *)infop; 54021308Sache ct->ct_waitset = TRUE; 54121308Sache break; 54221308Sache case CLGET_TIMEOUT: 54321308Sache *(struct timeval *)infop = ct->ct_wait; 54421308Sache break; 54521308Sache case CLGET_SERVER_ADDR: 54621308Sache (void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len); 54721308Sache break; 54821308Sache case CLGET_FD: 54921308Sache *(int *)(void *)info = ct->ct_fd; 55021308Sache break; 55121308Sache case CLGET_SVC_ADDR: 55221308Sache /* The caller should not free this memory area */ 55321308Sache *(struct netbuf *)(void *)info = ct->ct_addr; 55421308Sache break; 55521308Sache case CLSET_SVC_ADDR: /* set to new address */ 55621308Sache release_fd_lock(ct->ct_fd, mask); 55721308Sache return (FALSE); 55821308Sache case CLGET_XID: 55921308Sache /* 56021308Sache * use the knowledge that xid is the 56121308Sache * first element in the call structure 56221308Sache * This will get the xid of the PREVIOUS call 56321308Sache */ 56421308Sache *(u_int32_t *)(void *)info = 56521308Sache ntohl(*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli); 56621308Sache break; 56721308Sache case CLSET_XID: 56821308Sache /* This will set the xid of the NEXT call */ 56921308Sache *(u_int32_t *)(void *)&ct->ct_u.ct_mcalli = 57021308Sache htonl(*((u_int32_t *)(void *)info) + 1); 57121308Sache /* increment by 1 as clnt_vc_call() decrements once */ 57221308Sache break; 57321308Sache case CLGET_VERS: 57421308Sache /* 57521308Sache * This RELIES on the information that, in the call body, 57621308Sache * the version number field is the fifth field from the 57721308Sache * begining of the RPC header. MUST be changed if the 57821308Sache * call_struct is changed 57921308Sache */ 58021308Sache *(u_int32_t *)(void *)info = 58121308Sache ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 58221308Sache 4 * BYTES_PER_XDR_UNIT)); 58321308Sache break; 58421308Sache 58521308Sache case CLSET_VERS: 58621308Sache *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 58721308Sache 4 * BYTES_PER_XDR_UNIT) = 58821308Sache htonl(*(u_int32_t *)(void *)info); 58921308Sache break; 59021308Sache 59121308Sache case CLGET_PROG: 59221308Sache /* 59321308Sache * This RELIES on the information that, in the call body, 59421308Sache * the program number field is the fourth field from the 59521308Sache * begining of the RPC header. MUST be changed if the 59621308Sache * call_struct is changed 59721308Sache */ 59821308Sache *(u_int32_t *)(void *)info = 59921308Sache ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 60021308Sache 3 * BYTES_PER_XDR_UNIT)); 60175406Sache break; 60275406Sache 60375406Sache case CLSET_PROG: 60475406Sache *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 60575406Sache 3 * BYTES_PER_XDR_UNIT) = 60675406Sache htonl(*(u_int32_t *)(void *)info); 60775406Sache break; 60875406Sache 60975406Sache default: 61075406Sache release_fd_lock(ct->ct_fd, mask); 61175406Sache return (FALSE); 61275406Sache } 61375406Sache release_fd_lock(ct->ct_fd, mask); 61475406Sache return (TRUE); 61575406Sache} 61675406Sache 61775406Sache 61875406Sachestatic void 61975406Sacheclnt_vc_destroy(cl) 62075406Sache CLIENT *cl; 62175406Sache{ 62275406Sache struct ct_data *ct = (struct ct_data *) cl->cl_private; 62375406Sache int ct_fd = ct->ct_fd; 62475406Sache sigset_t mask; 62575406Sache sigset_t newmask; 62675406Sache 62775406Sache assert(cl != NULL); 62821308Sache 62975406Sache ct = (struct ct_data *) cl->cl_private; 63075406Sache 63175406Sache sigfillset(&newmask); 63275406Sache thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 63375406Sache mutex_lock(&clnt_fd_lock); 63421308Sache while (vc_fd_locks[ct_fd]) 63521308Sache cond_wait(&vc_cv[ct_fd], &clnt_fd_lock); 63675406Sache if (ct->ct_closeit && ct->ct_fd != -1) { 63775406Sache (void)_close(ct->ct_fd); 63875406Sache } 63975406Sache XDR_DESTROY(&(ct->ct_xdrs)); 64075406Sache if (ct->ct_addr.buf) 64175406Sache free(ct->ct_addr.buf); 64275406Sache mem_free(ct, sizeof(struct ct_data)); 64375406Sache mem_free(cl, sizeof(CLIENT)); 64475406Sache mutex_unlock(&clnt_fd_lock); 64575406Sache thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 64675406Sache cond_signal(&vc_cv[ct_fd]); 64775406Sache} 64875406Sache 64975406Sache/* 65075406Sache * Interface between xdr serializer and tcp connection. 65175406Sache * Behaves like the system calls, read & write, but keeps some error state 65221308Sache * around for the rpc level. 65321308Sache */ 65475406Sachestatic int 65575406Sacheread_vc(ctp, buf, len) 65675406Sache caddr_t ctp; 65775406Sache caddr_t buf; 65875406Sache int len; 65975406Sache{ 66075406Sache struct sockaddr sa; 66175406Sache socklen_t sal; 66275406Sache struct ct_data *ct = (struct ct_data *)(void *)ctp; 66375406Sache struct pollfd fd; 66421308Sache int milliseconds = (int)((ct->ct_wait.tv_sec * 1000) + 66521308Sache (ct->ct_wait.tv_usec / 1000)); 66675406Sache 66775406Sache if (len == 0) 66875406Sache return (0); 66975406Sache fd.fd = ct->ct_fd; 67075406Sache fd.events = POLLIN; 67175406Sache for (;;) { 67275406Sache switch (_poll(&fd, 1, milliseconds)) { 67321308Sache case 0: 67421308Sache ct->ct_error.re_status = RPC_TIMEDOUT; 67575406Sache return (-1); 67675406Sache 67775406Sache case -1: 67875406Sache if (errno == EINTR) 67975406Sache continue; 68075406Sache ct->ct_error.re_status = RPC_CANTRECV; 68175406Sache ct->ct_error.re_errno = errno; 68275406Sache return (-1); 68375406Sache } 68475406Sache break; 68575406Sache } 68675406Sache 68775406Sache sal = sizeof(sa); 68875406Sache if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) && 68975406Sache (sa.sa_family == AF_LOCAL)) { 69075406Sache len = __msgread(ct->ct_fd, buf, (size_t)len); 69175406Sache } else { 69275406Sache len = _read(ct->ct_fd, buf, (size_t)len); 69375406Sache } 69475406Sache 69575406Sache switch (len) { 69675406Sache case 0: 69775406Sache /* premature eof */ 69875406Sache ct->ct_error.re_errno = ECONNRESET; 69975406Sache ct->ct_error.re_status = RPC_CANTRECV; 70075406Sache len = -1; /* it's really an error */ 70121308Sache break; 70221308Sache 70375406Sache case -1: 70475406Sache ct->ct_error.re_errno = errno; 70575406Sache ct->ct_error.re_status = RPC_CANTRECV; 70675406Sache break; 70775406Sache } 70875406Sache return (len); 70921308Sache} 71021308Sache 71175406Sachestatic int 71275406Sachewrite_vc(ctp, buf, len) 71375406Sache caddr_t ctp; 71475406Sache caddr_t buf; 71575406Sache int len; 71675406Sache{ 71775406Sache struct sockaddr sa; 71875406Sache socklen_t sal; 71975406Sache struct ct_data *ct = (struct ct_data *)(void *)ctp; 72075406Sache int i, cnt; 72175406Sache 72275406Sache sal = sizeof(sa); 72375406Sache if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) && 72475406Sache (sa.sa_family == AF_LOCAL)) { 72575406Sache for (cnt = len; cnt > 0; cnt -= i, buf += i) { 72675406Sache if ((i = __msgwrite(ct->ct_fd, buf, 72775406Sache (size_t)cnt)) == -1) { 72875406Sache ct->ct_error.re_errno = errno; 72975406Sache ct->ct_error.re_status = RPC_CANTSEND; 73075406Sache return (-1); 73175406Sache } 73275406Sache } 73375406Sache } else { 73475406Sache for (cnt = len; cnt > 0; cnt -= i, buf += i) { 73575406Sache if ((i = _write(ct->ct_fd, buf, (size_t)cnt)) == -1) { 73675406Sache ct->ct_error.re_errno = errno; 73721308Sache ct->ct_error.re_status = RPC_CANTSEND; 73821308Sache return (-1); 73975406Sache } 74075406Sache } 74175406Sache } 74275406Sache return (len); 74375406Sache} 74421308Sache 74521308Sachestatic struct clnt_ops * 74621308Sacheclnt_vc_ops() 74775406Sache{ 74875406Sache static struct clnt_ops ops; 74975406Sache extern mutex_t ops_lock; 75075406Sache sigset_t mask, newmask; 75175406Sache 75275406Sache /* VARIABLES PROTECTED BY ops_lock: ops */ 75375406Sache 75475406Sache sigfillset(&newmask); 75575406Sache thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 75675406Sache mutex_lock(&ops_lock); 75775406Sache if (ops.cl_call == NULL) { 75875406Sache ops.cl_call = clnt_vc_call; 75975406Sache ops.cl_abort = clnt_vc_abort; 76075406Sache ops.cl_geterr = clnt_vc_geterr; 76175406Sache ops.cl_freeres = clnt_vc_freeres; 76275406Sache ops.cl_destroy = clnt_vc_destroy; 76375406Sache ops.cl_control = clnt_vc_control; 76475406Sache } 76575406Sache mutex_unlock(&ops_lock); 76675406Sache thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 76775406Sache return (&ops); 76875406Sache} 76975406Sache 77075406Sache/* 77175406Sache * Make sure that the time is not garbage. -1 value is disallowed. 77275406Sache * Note this is different from time_not_ok in clnt_dg.c 77375406Sache */ 77475406Sachestatic bool_t 77575406Sachetime_not_ok(t) 77675406Sache struct timeval *t; 77775406Sache{ 77875406Sache return (t->tv_sec <= -1 || t->tv_sec > 100000000 || 77975406Sache t->tv_usec <= -1 || t->tv_usec > 1000000); 78075406Sache} 78175406Sache 78275406Sachestatic int 78375406Sache__msgread(sock, buf, cnt) 78475406Sache int sock; 78575406Sache void *buf; 78675406Sache size_t cnt; 78775406Sache{ 78875406Sache struct iovec iov[1]; 78975406Sache struct msghdr msg; 79075406Sache struct cmessage cm; 79175406Sache 79275406Sache bzero((char *)&cm, sizeof(cm)); 79375406Sache iov[0].iov_base = buf; 79475406Sache iov[0].iov_len = cnt; 79575406Sache 79675406Sache msg.msg_iov = iov; 79775406Sache msg.msg_iovlen = 1; 79875406Sache msg.msg_name = NULL; 79975406Sache msg.msg_namelen = 0; 80075406Sache msg.msg_control = (caddr_t)&cm; 80175406Sache msg.msg_controllen = sizeof(struct cmessage); 80275406Sache msg.msg_flags = 0; 80375406Sache 80475406Sache return(_recvmsg(sock, &msg, 0)); 80575406Sache} 80675406Sache 80775406Sachestatic int 80875406Sache__msgwrite(sock, buf, cnt) 80975406Sache int sock; 81075406Sache void *buf; 81175406Sache size_t cnt; 81275406Sache{ 81375406Sache struct iovec iov[1]; 81475406Sache struct msghdr msg; 81575406Sache struct cmessage cm; 81675406Sache 81775406Sache bzero((char *)&cm, sizeof(cm)); 81875406Sache iov[0].iov_base = buf; 81975406Sache iov[0].iov_len = cnt; 82075406Sache 82175406Sache cm.cmsg.cmsg_type = SCM_CREDS; 82275406Sache cm.cmsg.cmsg_level = SOL_SOCKET; 82375406Sache cm.cmsg.cmsg_len = sizeof(struct cmessage); 82475406Sache 82575406Sache msg.msg_iov = iov; 82675406Sache msg.msg_iovlen = 1; 82775406Sache msg.msg_name = NULL; 82875406Sache msg.msg_namelen = 0; 82975406Sache msg.msg_control = (caddr_t)&cm; 83075406Sache msg.msg_controllen = sizeof(struct cmessage); 83175406Sache msg.msg_flags = 0; 83275406Sache 83375406Sache return(_sendmsg(sock, &msg, 0)); 83475406Sache} 83575406Sache