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