clnt_vc.c revision 74627
174462Salfred/* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */ 274462Salfred/* $FreeBSD: head/lib/libc/rpc/clnt_vc.c 74627 2001-03-22 04:31:30Z alfred $ */ 374462Salfred 474462Salfred/* 574462Salfred * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 674462Salfred * unrestricted use provided that this legend is included on all tape 774462Salfred * media and as a part of the software program in whole or part. Users 874462Salfred * may copy or modify Sun RPC without charge, but are not authorized 974462Salfred * to license or distribute it to anyone else except as part of a product or 1074462Salfred * program developed by the user. 1174462Salfred * 1274462Salfred * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 1374462Salfred * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 1474462Salfred * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 1574462Salfred * 1674462Salfred * Sun RPC is provided with no support and without any obligation on the 1774462Salfred * part of Sun Microsystems, Inc. to assist in its use, correction, 1874462Salfred * modification or enhancement. 1974462Salfred * 2074462Salfred * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 2174462Salfred * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 2274462Salfred * OR ANY PART THEREOF. 2374462Salfred * 2474462Salfred * In no event will Sun Microsystems, Inc. be liable for any lost revenue 2574462Salfred * or profits or other special, indirect and consequential damages, even if 2674462Salfred * Sun has been advised of the possibility of such damages. 2774462Salfred * 2874462Salfred * Sun Microsystems, Inc. 2974462Salfred * 2550 Garcia Avenue 3074462Salfred * Mountain View, California 94043 3174462Salfred */ 3274462Salfred 3374462Salfred#include <sys/cdefs.h> 3474462Salfred#if defined(LIBC_SCCS) && !defined(lint) 3574462Salfredstatic char *sccsid = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro"; 3674462Salfredstatic char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 3774462Salfredstatic char sccsid[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 3874462Salfred#endif 3974462Salfred 4074462Salfred/* 4174462Salfred * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 4274462Salfred * 4374462Salfred * Copyright (C) 1984, Sun Microsystems, Inc. 4474462Salfred * 4574462Salfred * TCP based RPC supports 'batched calls'. 4674462Salfred * A sequence of calls may be batched-up in a send buffer. The rpc call 4774462Salfred * return immediately to the client even though the call was not necessarily 4874462Salfred * sent. The batching occurs if the results' xdr routine is NULL (0) AND 4974462Salfred * the rpc timeout value is zero (see clnt.h, rpc). 5074462Salfred * 5174462Salfred * Clients should NOT casually batch calls that in fact return results; that is, 5274462Salfred * the server side should be aware that a call is batched and not produce any 5374462Salfred * return message. Batched calls that produce many result messages can 5474462Salfred * deadlock (netlock) the client and the server.... 5574462Salfred * 5674462Salfred * Now go hang yourself. 5774462Salfred */ 5874462Salfred 5974462Salfred#include "reentrant.h" 6074462Salfred#include "namespace.h" 6174462Salfred#include <sys/types.h> 6274462Salfred#include <sys/poll.h> 6374462Salfred#include <sys/syslog.h> 6474462Salfred#include <sys/socket.h> 6574462Salfred#include <sys/un.h> 6674462Salfred#include <sys/uio.h> 6774462Salfred 6874462Salfred#include <assert.h> 6974462Salfred#include <err.h> 7074462Salfred#include <errno.h> 7174462Salfred#include <netdb.h> 7274462Salfred#include <stdio.h> 7374462Salfred#include <stdlib.h> 7474462Salfred#include <string.h> 7574462Salfred#include <unistd.h> 7674462Salfred#include <signal.h> 7774462Salfred 7874462Salfred#include <rpc/rpc.h> 7974462Salfred#include "un-namespace.h" 8074462Salfred#include "rpc_com.h" 8174462Salfred 8274462Salfred#define MCALL_MSG_SIZE 24 8374462Salfred 8474462Salfredstatic enum clnt_stat clnt_vc_call __P((CLIENT *, rpcproc_t, xdrproc_t, caddr_t, 8574462Salfred xdrproc_t, caddr_t, struct timeval)); 8674462Salfredstatic void clnt_vc_geterr __P((CLIENT *, struct rpc_err *)); 8774462Salfredstatic bool_t clnt_vc_freeres __P((CLIENT *, xdrproc_t, caddr_t)); 8874462Salfredstatic void clnt_vc_abort __P((CLIENT *)); 8974462Salfredstatic bool_t clnt_vc_control __P((CLIENT *, u_int, char *)); 9074462Salfredstatic void clnt_vc_destroy __P((CLIENT *)); 9174462Salfredstatic struct clnt_ops *clnt_vc_ops __P((void)); 9274462Salfredstatic bool_t time_not_ok __P((struct timeval *)); 9374462Salfredstatic int read_vc __P((caddr_t, caddr_t, int)); 9474462Salfredstatic int write_vc __P((caddr_t, caddr_t, int)); 9574462Salfredstatic int __msgwrite(int, void *, size_t); 9674462Salfredstatic int __msgread(int, void *, size_t); 9774462Salfred 9874462Salfredstruct ct_data { 9974462Salfred int ct_fd; /* connection's fd */ 10074462Salfred bool_t ct_closeit; /* close it on destroy */ 10174462Salfred struct timeval ct_wait; /* wait interval in milliseconds */ 10274462Salfred bool_t ct_waitset; /* wait set by clnt_control? */ 10374462Salfred struct netbuf ct_addr; /* remote addr */ 10474462Salfred struct rpc_err ct_error; 10574462Salfred union { 10674462Salfred char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */ 10774462Salfred u_int32_t ct_mcalli; 10874462Salfred } ct_u; 10974462Salfred u_int ct_mpos; /* pos after marshal */ 11074462Salfred XDR ct_xdrs; /* XDR stream */ 11174462Salfred}; 11274462Salfred 11374462Salfred/* 11474462Salfred * This machinery implements per-fd locks for MT-safety. It is not 11574462Salfred * sufficient to do per-CLIENT handle locks for MT-safety because a 11674462Salfred * user may create more than one CLIENT handle with the same fd behind 11774462Salfred * it. Therfore, we allocate an array of flags (vc_fd_locks), protected 11874462Salfred * by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables 11974462Salfred * similarly protected. Vc_fd_lock[fd] == 1 => a call is activte on some 12074462Salfred * CLIENT handle created for that fd. 12174462Salfred * The current implementation holds locks across the entire RPC and reply. 12274462Salfred * Yes, this is silly, and as soon as this code is proven to work, this 12374462Salfred * should be the first thing fixed. One step at a time. 12474462Salfred */ 12574462Salfredstatic int *vc_fd_locks; 12674462Salfredextern mutex_t clnt_fd_lock; 12774462Salfredstatic cond_t *vc_cv; 12874462Salfred#define release_fd_lock(fd, mask) { \ 12974462Salfred mutex_lock(&clnt_fd_lock); \ 13074462Salfred if (__isthreaded) \ 13174462Salfred vc_fd_locks[fd] = 0; \ 13274462Salfred mutex_unlock(&clnt_fd_lock); \ 13374462Salfred thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \ 13474462Salfred cond_signal(&vc_cv[fd]); \ 13574462Salfred} 13674462Salfred 13774462Salfredstatic const char clnt_vc_errstr[] = "%s : %s"; 13874462Salfredstatic const char clnt_vc_str[] = "clnt_vc_create"; 13974462Salfredstatic const char clnt_read_vc_str[] = "read_vc"; 14074462Salfredstatic const char __no_mem_str[] = "out of memory"; 14174462Salfred 14274462Salfred/* 14374462Salfred * Create a client handle for a connection. 14474462Salfred * Default options are set, which the user can change using clnt_control()'s. 14574462Salfred * The rpc/vc package does buffering similar to stdio, so the client 14674462Salfred * must pick send and receive buffer sizes, 0 => use the default. 14774462Salfred * NB: fd is copied into a private area. 14874462Salfred * NB: The rpch->cl_auth is set null authentication. Caller may wish to 14974462Salfred * set this something more useful. 15074462Salfred * 15174462Salfred * fd should be an open socket 15274462Salfred */ 15374462SalfredCLIENT * 15474462Salfredclnt_vc_create(fd, raddr, prog, vers, sendsz, recvsz) 15574462Salfred int fd; /* open file descriptor */ 15674462Salfred const struct netbuf *raddr; /* servers address */ 15774462Salfred rpcprog_t prog; /* program number */ 15874462Salfred rpcvers_t vers; /* version number */ 15974462Salfred u_int sendsz; /* buffer recv size */ 16074462Salfred u_int recvsz; /* buffer send size */ 16174462Salfred{ 16274462Salfred CLIENT *cl; /* client handle */ 16374462Salfred struct ct_data *ct = NULL; /* client handle */ 16474462Salfred struct timeval now; 16574462Salfred struct rpc_msg call_msg; 16674462Salfred static u_int32_t disrupt; 16774462Salfred sigset_t mask; 16874462Salfred sigset_t newmask; 16974462Salfred struct sockaddr_storage ss; 17074462Salfred socklen_t slen; 17174462Salfred struct __rpc_sockinfo si; 17274462Salfred 17374462Salfred if (disrupt == 0) 17474462Salfred disrupt = (u_int32_t)(long)raddr; 17574462Salfred 17674462Salfred cl = (CLIENT *)mem_alloc(sizeof (*cl)); 17774462Salfred ct = (struct ct_data *)mem_alloc(sizeof (*ct)); 17874462Salfred if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) { 17974462Salfred (void) syslog(LOG_ERR, clnt_vc_errstr, 18074462Salfred clnt_vc_str, __no_mem_str); 18174462Salfred rpc_createerr.cf_stat = RPC_SYSTEMERROR; 18274462Salfred rpc_createerr.cf_error.re_errno = errno; 18374462Salfred goto err; 18474462Salfred } 18574462Salfred ct->ct_addr.buf = NULL; 18674462Salfred sigfillset(&newmask); 18774462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 18874462Salfred mutex_lock(&clnt_fd_lock); 18974462Salfred if (vc_fd_locks == (int *) NULL) { 19074462Salfred int cv_allocsz, fd_allocsz; 19174462Salfred int dtbsize = __rpc_dtbsize(); 19274462Salfred 19374462Salfred fd_allocsz = dtbsize * sizeof (int); 19474462Salfred vc_fd_locks = (int *) mem_alloc(fd_allocsz); 19574462Salfred if (vc_fd_locks == (int *) NULL) { 19674462Salfred mutex_unlock(&clnt_fd_lock); 19774462Salfred thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 19874462Salfred goto err; 19974462Salfred } else 20074462Salfred memset(vc_fd_locks, '\0', fd_allocsz); 20174462Salfred 20274462Salfred assert(vc_cv == (cond_t *) NULL); 20374462Salfred cv_allocsz = dtbsize * sizeof (cond_t); 20474462Salfred vc_cv = (cond_t *) mem_alloc(cv_allocsz); 20574462Salfred if (vc_cv == (cond_t *) NULL) { 20674462Salfred mem_free(vc_fd_locks, fd_allocsz); 20774462Salfred vc_fd_locks = (int *) NULL; 20874462Salfred mutex_unlock(&clnt_fd_lock); 20974462Salfred thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 21074462Salfred goto err; 21174462Salfred } else { 21274462Salfred int i; 21374462Salfred 21474462Salfred for (i = 0; i < dtbsize; i++) 21574462Salfred cond_init(&vc_cv[i], 0, (void *) 0); 21674462Salfred } 21774462Salfred } else 21874462Salfred assert(vc_cv != (cond_t *) NULL); 21974462Salfred 22074462Salfred /* 22174462Salfred * XXX - fvdl connecting while holding a mutex? 22274462Salfred */ 22374462Salfred slen = sizeof ss; 22474462Salfred if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 22574462Salfred if (errno != ENOTCONN) { 22674462Salfred rpc_createerr.cf_stat = RPC_SYSTEMERROR; 22774462Salfred rpc_createerr.cf_error.re_errno = errno; 22874462Salfred mutex_unlock(&clnt_fd_lock); 22974462Salfred goto err; 23074462Salfred } 23174462Salfred if (_connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){ 23274462Salfred rpc_createerr.cf_stat = RPC_SYSTEMERROR; 23374462Salfred rpc_createerr.cf_error.re_errno = errno; 23474462Salfred mutex_unlock(&clnt_fd_lock); 23574462Salfred goto err; 23674462Salfred } 23774462Salfred } 23874462Salfred mutex_unlock(&clnt_fd_lock); 23974462Salfred if (!__rpc_fd2sockinfo(fd, &si)) 24074462Salfred goto err; 24174462Salfred thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 24274462Salfred 24374462Salfred ct->ct_closeit = FALSE; 24474462Salfred 24574462Salfred /* 24674462Salfred * Set up private data struct 24774462Salfred */ 24874462Salfred ct->ct_fd = fd; 24974462Salfred ct->ct_wait.tv_usec = 0; 25074462Salfred ct->ct_waitset = FALSE; 25174462Salfred ct->ct_addr.buf = malloc(raddr->maxlen); 25274462Salfred if (ct->ct_addr.buf == NULL) 25374462Salfred goto err; 25474462Salfred memcpy(ct->ct_addr.buf, &raddr->buf, raddr->len); 25574462Salfred ct->ct_addr.len = raddr->maxlen; 25674462Salfred ct->ct_addr.maxlen = raddr->maxlen; 25774462Salfred 25874462Salfred /* 25974462Salfred * Initialize call message 26074462Salfred */ 26174462Salfred (void)gettimeofday(&now, NULL); 26274462Salfred call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now); 26374462Salfred call_msg.rm_direction = CALL; 26474462Salfred call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 26574462Salfred call_msg.rm_call.cb_prog = (u_int32_t)prog; 26674462Salfred call_msg.rm_call.cb_vers = (u_int32_t)vers; 26774462Salfred 26874462Salfred /* 26974462Salfred * pre-serialize the static part of the call msg and stash it away 27074462Salfred */ 27174462Salfred xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE, 27274462Salfred XDR_ENCODE); 27374462Salfred if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 27474462Salfred if (ct->ct_closeit) { 27574462Salfred (void)_close(fd); 27674462Salfred } 27774462Salfred goto err; 27874462Salfred } 27974462Salfred ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 28074462Salfred XDR_DESTROY(&(ct->ct_xdrs)); 28174462Salfred 28274462Salfred /* 28374462Salfred * Create a client handle which uses xdrrec for serialization 28474462Salfred * and authnone for authentication. 28574462Salfred */ 28674462Salfred cl->cl_ops = clnt_vc_ops(); 28774462Salfred cl->cl_private = ct; 28874462Salfred cl->cl_auth = authnone_create(); 28974462Salfred sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 29074462Salfred recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 29174462Salfred xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 29274462Salfred cl->cl_private, read_vc, write_vc); 29374462Salfred return (cl); 29474462Salfred 29574462Salfrederr: 29674462Salfred if (cl) { 29774462Salfred if (ct) { 29874462Salfred if (ct->ct_addr.len) 29974462Salfred mem_free(ct->ct_addr.buf, ct->ct_addr.len); 30074462Salfred mem_free((caddr_t)ct, sizeof (struct ct_data)); 30174462Salfred } 30274462Salfred if (cl) 30374462Salfred mem_free((caddr_t)cl, sizeof (CLIENT)); 30474462Salfred } 30574462Salfred return ((CLIENT *)NULL); 30674462Salfred} 30774462Salfred 30874462Salfredstatic enum clnt_stat 30974462Salfredclnt_vc_call(cl, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) 31074462Salfred CLIENT *cl; 31174462Salfred rpcproc_t proc; 31274462Salfred xdrproc_t xdr_args; 31374462Salfred caddr_t args_ptr; 31474462Salfred xdrproc_t xdr_results; 31574462Salfred caddr_t results_ptr; 31674462Salfred struct timeval timeout; 31774462Salfred{ 31874462Salfred struct ct_data *ct = (struct ct_data *) cl->cl_private; 31974462Salfred XDR *xdrs = &(ct->ct_xdrs); 32074462Salfred struct rpc_msg reply_msg; 32174462Salfred u_int32_t x_id; 32274462Salfred u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */ 32374462Salfred bool_t shipnow; 32474462Salfred int refreshes = 2; 32574462Salfred sigset_t mask, newmask; 32674462Salfred int rpc_lock_value; 32774462Salfred 32874462Salfred assert(cl != NULL); 32974462Salfred 33074462Salfred sigfillset(&newmask); 33174462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 33274462Salfred mutex_lock(&clnt_fd_lock); 33374462Salfred while (vc_fd_locks[ct->ct_fd]) 33474462Salfred cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 33574462Salfred if (__isthreaded) 33674462Salfred rpc_lock_value = 1; 33774462Salfred else 33874462Salfred rpc_lock_value = 0; 33974462Salfred vc_fd_locks[ct->ct_fd] = rpc_lock_value; 34074462Salfred mutex_unlock(&clnt_fd_lock); 34174462Salfred if (!ct->ct_waitset) { 34274462Salfred /* If time is not within limits, we ignore it. */ 34374462Salfred if (time_not_ok(&timeout) == FALSE) 34474462Salfred ct->ct_wait = timeout; 34574462Salfred } 34674462Salfred 34774462Salfred shipnow = 34874462Salfred (xdr_results == NULL && timeout.tv_sec == 0 34974462Salfred && timeout.tv_usec == 0) ? FALSE : TRUE; 35074462Salfred 35174462Salfredcall_again: 35274462Salfred xdrs->x_op = XDR_ENCODE; 35374462Salfred ct->ct_error.re_status = RPC_SUCCESS; 35474462Salfred x_id = ntohl(--(*msg_x_id)); 35574462Salfred 35674462Salfred if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) || 35774462Salfred (! XDR_PUTINT32(xdrs, &proc)) || 35874462Salfred (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || 35974462Salfred (! (*xdr_args)(xdrs, args_ptr))) { 36074462Salfred if (ct->ct_error.re_status == RPC_SUCCESS) 36174462Salfred ct->ct_error.re_status = RPC_CANTENCODEARGS; 36274462Salfred (void)xdrrec_endofrecord(xdrs, TRUE); 36374462Salfred release_fd_lock(ct->ct_fd, mask); 36474462Salfred return (ct->ct_error.re_status); 36574462Salfred } 36674462Salfred if (! xdrrec_endofrecord(xdrs, shipnow)) { 36774462Salfred release_fd_lock(ct->ct_fd, mask); 36874462Salfred return (ct->ct_error.re_status = RPC_CANTSEND); 36974462Salfred } 37074462Salfred if (! shipnow) { 37174462Salfred release_fd_lock(ct->ct_fd, mask); 37274462Salfred return (RPC_SUCCESS); 37374462Salfred } 37474462Salfred /* 37574462Salfred * Hack to provide rpc-based message passing 37674462Salfred */ 37774462Salfred if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 37874462Salfred release_fd_lock(ct->ct_fd, mask); 37974462Salfred return(ct->ct_error.re_status = RPC_TIMEDOUT); 38074462Salfred } 38174462Salfred 38274462Salfred 38374462Salfred /* 38474462Salfred * Keep receiving until we get a valid transaction id 38574462Salfred */ 38674462Salfred xdrs->x_op = XDR_DECODE; 38774462Salfred while (TRUE) { 38874462Salfred reply_msg.acpted_rply.ar_verf = _null_auth; 38974462Salfred reply_msg.acpted_rply.ar_results.where = NULL; 39074462Salfred reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 39174462Salfred if (! xdrrec_skiprecord(xdrs)) { 39274462Salfred release_fd_lock(ct->ct_fd, mask); 39374462Salfred return (ct->ct_error.re_status); 39474462Salfred } 39574462Salfred /* now decode and validate the response header */ 39674462Salfred if (! xdr_replymsg(xdrs, &reply_msg)) { 39774462Salfred if (ct->ct_error.re_status == RPC_SUCCESS) 39874462Salfred continue; 39974462Salfred release_fd_lock(ct->ct_fd, mask); 40074462Salfred return (ct->ct_error.re_status); 40174462Salfred } 40274462Salfred if (reply_msg.rm_xid == x_id) 40374462Salfred break; 40474462Salfred } 40574462Salfred 40674462Salfred /* 40774462Salfred * process header 40874462Salfred */ 40974462Salfred _seterr_reply(&reply_msg, &(ct->ct_error)); 41074462Salfred if (ct->ct_error.re_status == RPC_SUCCESS) { 41174462Salfred if (! AUTH_VALIDATE(cl->cl_auth, 41274462Salfred &reply_msg.acpted_rply.ar_verf)) { 41374462Salfred ct->ct_error.re_status = RPC_AUTHERROR; 41474462Salfred ct->ct_error.re_why = AUTH_INVALIDRESP; 41574462Salfred } else if (! (*xdr_results)(xdrs, results_ptr)) { 41674462Salfred if (ct->ct_error.re_status == RPC_SUCCESS) 41774462Salfred ct->ct_error.re_status = RPC_CANTDECODERES; 41874462Salfred } 41974462Salfred /* free verifier ... */ 42074462Salfred if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 42174462Salfred xdrs->x_op = XDR_FREE; 42274462Salfred (void)xdr_opaque_auth(xdrs, 42374462Salfred &(reply_msg.acpted_rply.ar_verf)); 42474462Salfred } 42574462Salfred } /* end successful completion */ 42674462Salfred else { 42774462Salfred /* maybe our credentials need to be refreshed ... */ 42874462Salfred if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg)) 42974462Salfred goto call_again; 43074462Salfred } /* end of unsuccessful completion */ 43174462Salfred release_fd_lock(ct->ct_fd, mask); 43274462Salfred return (ct->ct_error.re_status); 43374462Salfred} 43474462Salfred 43574462Salfredstatic void 43674462Salfredclnt_vc_geterr(cl, errp) 43774462Salfred CLIENT *cl; 43874462Salfred struct rpc_err *errp; 43974462Salfred{ 44074462Salfred struct ct_data *ct; 44174462Salfred 44274462Salfred assert(cl != NULL); 44374462Salfred assert(errp != NULL); 44474462Salfred 44574462Salfred ct = (struct ct_data *) cl->cl_private; 44674462Salfred *errp = ct->ct_error; 44774462Salfred} 44874462Salfred 44974462Salfredstatic bool_t 45074462Salfredclnt_vc_freeres(cl, xdr_res, res_ptr) 45174462Salfred CLIENT *cl; 45274462Salfred xdrproc_t xdr_res; 45374462Salfred caddr_t res_ptr; 45474462Salfred{ 45574462Salfred struct ct_data *ct; 45674462Salfred XDR *xdrs; 45774462Salfred bool_t dummy; 45874462Salfred sigset_t mask; 45974462Salfred sigset_t newmask; 46074462Salfred 46174462Salfred assert(cl != NULL); 46274462Salfred 46374462Salfred ct = (struct ct_data *)cl->cl_private; 46474462Salfred xdrs = &(ct->ct_xdrs); 46574462Salfred 46674462Salfred sigfillset(&newmask); 46774462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 46874462Salfred mutex_lock(&clnt_fd_lock); 46974462Salfred while (vc_fd_locks[ct->ct_fd]) 47074462Salfred cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 47174462Salfred xdrs->x_op = XDR_FREE; 47274462Salfred dummy = (*xdr_res)(xdrs, res_ptr); 47374462Salfred mutex_unlock(&clnt_fd_lock); 47474462Salfred thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 47574462Salfred cond_signal(&vc_cv[ct->ct_fd]); 47674462Salfred 47774462Salfred return dummy; 47874462Salfred} 47974462Salfred 48074462Salfred/*ARGSUSED*/ 48174462Salfredstatic void 48274462Salfredclnt_vc_abort(cl) 48374462Salfred CLIENT *cl; 48474462Salfred{ 48574462Salfred} 48674462Salfred 48774462Salfredstatic bool_t 48874462Salfredclnt_vc_control(cl, request, info) 48974462Salfred CLIENT *cl; 49074462Salfred u_int request; 49174462Salfred char *info; 49274462Salfred{ 49374462Salfred struct ct_data *ct; 49474462Salfred void *infop = info; 49574462Salfred sigset_t mask; 49674462Salfred sigset_t newmask; 49774462Salfred int rpc_lock_value; 49874462Salfred 49974462Salfred assert(cl != NULL); 50074462Salfred 50174462Salfred ct = (struct ct_data *)cl->cl_private; 50274462Salfred 50374462Salfred sigfillset(&newmask); 50474462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 50574462Salfred mutex_lock(&clnt_fd_lock); 50674462Salfred while (vc_fd_locks[ct->ct_fd]) 50774462Salfred cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 50874462Salfred if (__isthreaded) 50974462Salfred rpc_lock_value = 1; 51074462Salfred else 51174462Salfred rpc_lock_value = 0; 51274462Salfred vc_fd_locks[ct->ct_fd] = rpc_lock_value; 51374462Salfred mutex_unlock(&clnt_fd_lock); 51474462Salfred 51574462Salfred switch (request) { 51674462Salfred case CLSET_FD_CLOSE: 51774462Salfred ct->ct_closeit = TRUE; 51874462Salfred release_fd_lock(ct->ct_fd, mask); 51974462Salfred return (TRUE); 52074462Salfred case CLSET_FD_NCLOSE: 52174462Salfred ct->ct_closeit = FALSE; 52274462Salfred release_fd_lock(ct->ct_fd, mask); 52374462Salfred return (TRUE); 52474462Salfred default: 52574462Salfred break; 52674462Salfred } 52774462Salfred 52874462Salfred /* for other requests which use info */ 52974462Salfred if (info == NULL) { 53074462Salfred release_fd_lock(ct->ct_fd, mask); 53174462Salfred return (FALSE); 53274462Salfred } 53374462Salfred switch (request) { 53474462Salfred case CLSET_TIMEOUT: 53574462Salfred if (time_not_ok((struct timeval *)(void *)info)) { 53674462Salfred release_fd_lock(ct->ct_fd, mask); 53774462Salfred return (FALSE); 53874462Salfred } 53974462Salfred ct->ct_wait = *(struct timeval *)infop; 54074462Salfred ct->ct_waitset = TRUE; 54174462Salfred break; 54274462Salfred case CLGET_TIMEOUT: 54374462Salfred *(struct timeval *)infop = ct->ct_wait; 54474462Salfred break; 54574462Salfred case CLGET_SERVER_ADDR: 54674462Salfred (void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len); 54774462Salfred break; 54874462Salfred case CLGET_FD: 54974462Salfred *(int *)(void *)info = ct->ct_fd; 55074462Salfred break; 55174462Salfred case CLGET_SVC_ADDR: 55274462Salfred /* The caller should not free this memory area */ 55374462Salfred *(struct netbuf *)(void *)info = ct->ct_addr; 55474462Salfred break; 55574462Salfred case CLSET_SVC_ADDR: /* set to new address */ 55674462Salfred release_fd_lock(ct->ct_fd, mask); 55774462Salfred return (FALSE); 55874462Salfred case CLGET_XID: 55974462Salfred /* 56074462Salfred * use the knowledge that xid is the 56174462Salfred * first element in the call structure 56274462Salfred * This will get the xid of the PREVIOUS call 56374462Salfred */ 56474462Salfred *(u_int32_t *)(void *)info = 56574462Salfred ntohl(*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli); 56674462Salfred break; 56774462Salfred case CLSET_XID: 56874462Salfred /* This will set the xid of the NEXT call */ 56974462Salfred *(u_int32_t *)(void *)&ct->ct_u.ct_mcalli = 57074462Salfred htonl(*((u_int32_t *)(void *)info) + 1); 57174462Salfred /* increment by 1 as clnt_vc_call() decrements once */ 57274462Salfred break; 57374462Salfred case CLGET_VERS: 57474462Salfred /* 57574462Salfred * This RELIES on the information that, in the call body, 57674462Salfred * the version number field is the fifth field from the 57774462Salfred * begining of the RPC header. MUST be changed if the 57874462Salfred * call_struct is changed 57974462Salfred */ 58074462Salfred *(u_int32_t *)(void *)info = 58174462Salfred ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 58274462Salfred 4 * BYTES_PER_XDR_UNIT)); 58374462Salfred break; 58474462Salfred 58574462Salfred case CLSET_VERS: 58674462Salfred *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 58774462Salfred 4 * BYTES_PER_XDR_UNIT) = 58874462Salfred htonl(*(u_int32_t *)(void *)info); 58974462Salfred break; 59074462Salfred 59174462Salfred case CLGET_PROG: 59274462Salfred /* 59374462Salfred * This RELIES on the information that, in the call body, 59474462Salfred * the program number field is the fourth field from the 59574462Salfred * begining of the RPC header. MUST be changed if the 59674462Salfred * call_struct is changed 59774462Salfred */ 59874462Salfred *(u_int32_t *)(void *)info = 59974462Salfred ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 60074462Salfred 3 * BYTES_PER_XDR_UNIT)); 60174462Salfred break; 60274462Salfred 60374462Salfred case CLSET_PROG: 60474462Salfred *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 60574462Salfred 3 * BYTES_PER_XDR_UNIT) = 60674462Salfred htonl(*(u_int32_t *)(void *)info); 60774462Salfred break; 60874462Salfred 60974462Salfred default: 61074462Salfred release_fd_lock(ct->ct_fd, mask); 61174462Salfred return (FALSE); 61274462Salfred } 61374462Salfred release_fd_lock(ct->ct_fd, mask); 61474462Salfred return (TRUE); 61574462Salfred} 61674462Salfred 61774462Salfred 61874462Salfredstatic void 61974462Salfredclnt_vc_destroy(cl) 62074462Salfred CLIENT *cl; 62174462Salfred{ 62274462Salfred struct ct_data *ct = (struct ct_data *) cl->cl_private; 62374462Salfred int ct_fd = ct->ct_fd; 62474462Salfred sigset_t mask; 62574462Salfred sigset_t newmask; 62674462Salfred 62774462Salfred assert(cl != NULL); 62874462Salfred 62974462Salfred ct = (struct ct_data *) cl->cl_private; 63074462Salfred 63174462Salfred sigfillset(&newmask); 63274462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 63374462Salfred mutex_lock(&clnt_fd_lock); 63474462Salfred while (vc_fd_locks[ct_fd]) 63574462Salfred cond_wait(&vc_cv[ct_fd], &clnt_fd_lock); 63674462Salfred if (ct->ct_closeit && ct->ct_fd != -1) { 63774462Salfred (void)_close(ct->ct_fd); 63874462Salfred } 63974462Salfred XDR_DESTROY(&(ct->ct_xdrs)); 64074462Salfred if (ct->ct_addr.buf) 64174462Salfred free(ct->ct_addr.buf); 64274462Salfred mem_free(ct, sizeof(struct ct_data)); 64374462Salfred mem_free(cl, sizeof(CLIENT)); 64474462Salfred mutex_unlock(&clnt_fd_lock); 64574462Salfred thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 64674462Salfred cond_signal(&vc_cv[ct_fd]); 64774462Salfred} 64874462Salfred 64974462Salfred/* 65074462Salfred * Interface between xdr serializer and tcp connection. 65174462Salfred * Behaves like the system calls, read & write, but keeps some error state 65274462Salfred * around for the rpc level. 65374462Salfred */ 65474462Salfredstatic int 65574462Salfredread_vc(ctp, buf, len) 65674462Salfred caddr_t ctp; 65774462Salfred caddr_t buf; 65874462Salfred int len; 65974462Salfred{ 66074462Salfred struct sockaddr sa; 66174462Salfred socklen_t sal; 66274462Salfred struct ct_data *ct = (struct ct_data *)(void *)ctp; 66374462Salfred struct pollfd fd; 66474462Salfred int milliseconds = (int)((ct->ct_wait.tv_sec * 1000) + 66574462Salfred (ct->ct_wait.tv_usec / 1000)); 66674462Salfred 66774462Salfred if (len == 0) 66874462Salfred return (0); 66974462Salfred fd.fd = ct->ct_fd; 67074462Salfred fd.events = POLLIN; 67174462Salfred for (;;) { 67274462Salfred switch (_poll(&fd, 1, milliseconds)) { 67374462Salfred case 0: 67474462Salfred ct->ct_error.re_status = RPC_TIMEDOUT; 67574462Salfred return (-1); 67674462Salfred 67774462Salfred case -1: 67874462Salfred if (errno == EINTR) 67974462Salfred continue; 68074462Salfred ct->ct_error.re_status = RPC_CANTRECV; 68174462Salfred ct->ct_error.re_errno = errno; 68274462Salfred return (-1); 68374462Salfred } 68474462Salfred break; 68574462Salfred } 68674462Salfred 68774462Salfred sal = sizeof(sa); 68874462Salfred if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) && 68974462Salfred (sa.sa_family == AF_LOCAL)) { 69074462Salfred len = __msgread(ct->ct_fd, buf, (size_t)len); 69174462Salfred } else { 69274462Salfred len = _read(ct->ct_fd, buf, (size_t)len); 69374462Salfred } 69474462Salfred 69574462Salfred switch (len) { 69674462Salfred case 0: 69774462Salfred /* premature eof */ 69874462Salfred ct->ct_error.re_errno = ECONNRESET; 69974462Salfred ct->ct_error.re_status = RPC_CANTRECV; 70074462Salfred len = -1; /* it's really an error */ 70174462Salfred break; 70274462Salfred 70374462Salfred case -1: 70474462Salfred ct->ct_error.re_errno = errno; 70574462Salfred ct->ct_error.re_status = RPC_CANTRECV; 70674462Salfred break; 70774462Salfred } 70874462Salfred return (len); 70974462Salfred} 71074462Salfred 71174462Salfredstatic int 71274462Salfredwrite_vc(ctp, buf, len) 71374462Salfred caddr_t ctp; 71474462Salfred caddr_t buf; 71574462Salfred int len; 71674462Salfred{ 71774462Salfred struct sockaddr sa; 71874462Salfred socklen_t sal; 71974462Salfred struct ct_data *ct = (struct ct_data *)(void *)ctp; 72074462Salfred int i, cnt; 72174462Salfred 72274462Salfred sal = sizeof(sa); 72374462Salfred if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) && 72474462Salfred (sa.sa_family == AF_LOCAL)) { 72574462Salfred for (cnt = len; cnt > 0; cnt -= i, buf += i) { 72674462Salfred if ((i = __msgwrite(ct->ct_fd, buf, 72774462Salfred (size_t)cnt)) == -1) { 72874462Salfred ct->ct_error.re_errno = errno; 72974462Salfred ct->ct_error.re_status = RPC_CANTSEND; 73074462Salfred return (-1); 73174462Salfred } 73274462Salfred } 73374462Salfred } else { 73474462Salfred for (cnt = len; cnt > 0; cnt -= i, buf += i) { 73574462Salfred if ((i = _write(ct->ct_fd, buf, (size_t)cnt)) == -1) { 73674462Salfred ct->ct_error.re_errno = errno; 73774462Salfred ct->ct_error.re_status = RPC_CANTSEND; 73874462Salfred return (-1); 73974462Salfred } 74074462Salfred } 74174462Salfred } 74274462Salfred return (len); 74374462Salfred} 74474462Salfred 74574462Salfredstatic struct clnt_ops * 74674462Salfredclnt_vc_ops() 74774462Salfred{ 74874462Salfred static struct clnt_ops ops; 74974462Salfred extern mutex_t ops_lock; 75074462Salfred sigset_t mask, newmask; 75174462Salfred 75274462Salfred /* VARIABLES PROTECTED BY ops_lock: ops */ 75374462Salfred 75474462Salfred sigfillset(&newmask); 75574462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 75674462Salfred mutex_lock(&ops_lock); 75774462Salfred if (ops.cl_call == NULL) { 75874462Salfred ops.cl_call = clnt_vc_call; 75974462Salfred ops.cl_abort = clnt_vc_abort; 76074462Salfred ops.cl_geterr = clnt_vc_geterr; 76174462Salfred ops.cl_freeres = clnt_vc_freeres; 76274462Salfred ops.cl_destroy = clnt_vc_destroy; 76374462Salfred ops.cl_control = clnt_vc_control; 76474462Salfred } 76574462Salfred mutex_unlock(&ops_lock); 76674462Salfred thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 76774462Salfred return (&ops); 76874462Salfred} 76974462Salfred 77074462Salfred/* 77174462Salfred * Make sure that the time is not garbage. -1 value is disallowed. 77274462Salfred * Note this is different from time_not_ok in clnt_dg.c 77374462Salfred */ 77474462Salfredstatic bool_t 77574462Salfredtime_not_ok(t) 77674462Salfred struct timeval *t; 77774462Salfred{ 77874462Salfred return (t->tv_sec <= -1 || t->tv_sec > 100000000 || 77974462Salfred t->tv_usec <= -1 || t->tv_usec > 1000000); 78074462Salfred} 78174462Salfred 78274627Salfredstatic int 78374462Salfred__msgread(sock, buf, cnt) 78474462Salfred int sock; 78574462Salfred void *buf; 78674462Salfred size_t cnt; 78774462Salfred{ 78874462Salfred struct iovec iov[1]; 78974462Salfred struct msghdr msg; 79074462Salfred struct cmessage cm; 79174462Salfred 79274462Salfred bzero((char *)&cm, sizeof(cm)); 79374462Salfred iov[0].iov_base = buf; 79474462Salfred iov[0].iov_len = cnt; 79574462Salfred 79674462Salfred msg.msg_iov = iov; 79774462Salfred msg.msg_iovlen = 1; 79874462Salfred msg.msg_name = NULL; 79974462Salfred msg.msg_namelen = 0; 80074462Salfred msg.msg_control = (caddr_t)&cm; 80174462Salfred msg.msg_controllen = sizeof(struct cmessage); 80274462Salfred msg.msg_flags = 0; 80374462Salfred 80474462Salfred return(_recvmsg(sock, &msg, 0)); 80574462Salfred} 80674627Salfred 80774462Salfredstatic int 80874462Salfred__msgwrite(sock, buf, cnt) 80974462Salfred int sock; 81074462Salfred void *buf; 81174462Salfred size_t cnt; 81274462Salfred{ 81374462Salfred struct iovec iov[1]; 81474462Salfred struct msghdr msg; 81574462Salfred struct cmessage cm; 81674462Salfred 81774462Salfred bzero((char *)&cm, sizeof(cm)); 81874462Salfred iov[0].iov_base = buf; 81974462Salfred iov[0].iov_len = cnt; 82074462Salfred 82174462Salfred cm.cmsg.cmsg_type = SCM_CREDS; 82274462Salfred cm.cmsg.cmsg_level = SOL_SOCKET; 82374462Salfred cm.cmsg.cmsg_len = sizeof(struct cmessage); 82474462Salfred 82574462Salfred msg.msg_iov = iov; 82674462Salfred msg.msg_iovlen = 1; 82774462Salfred msg.msg_name = NULL; 82874462Salfred msg.msg_namelen = 0; 82974462Salfred msg.msg_control = (caddr_t)&cm; 83074462Salfred msg.msg_controllen = sizeof(struct cmessage); 83174462Salfred msg.msg_flags = 0; 83274462Salfred 83374462Salfred return(_sendmsg(sock, &msg, 0)); 83474462Salfred} 835