1*0a6a1f1dSLionel Sambuc /* $NetBSD: clnt_vc.c,v 1.26 2015/01/20 18:31:25 christos Exp $ */
22fe8fb19SBen Gras
32fe8fb19SBen Gras /*
484d9c625SLionel Sambuc * Copyright (c) 2010, Oracle America, Inc.
52fe8fb19SBen Gras *
684d9c625SLionel Sambuc * Redistribution and use in source and binary forms, with or without
784d9c625SLionel Sambuc * modification, are permitted provided that the following conditions are
884d9c625SLionel Sambuc * met:
92fe8fb19SBen Gras *
1084d9c625SLionel Sambuc * * Redistributions of source code must retain the above copyright
1184d9c625SLionel Sambuc * notice, this list of conditions and the following disclaimer.
1284d9c625SLionel Sambuc * * Redistributions in binary form must reproduce the above
1384d9c625SLionel Sambuc * copyright notice, this list of conditions and the following
1484d9c625SLionel Sambuc * disclaimer in the documentation and/or other materials
1584d9c625SLionel Sambuc * provided with the distribution.
1684d9c625SLionel Sambuc * * Neither the name of the "Oracle America, Inc." nor the names of its
1784d9c625SLionel Sambuc * contributors may be used to endorse or promote products derived
1884d9c625SLionel Sambuc * from this software without specific prior written permission.
192fe8fb19SBen Gras *
2084d9c625SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2184d9c625SLionel Sambuc * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2284d9c625SLionel Sambuc * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2384d9c625SLionel Sambuc * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2484d9c625SLionel Sambuc * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
2584d9c625SLionel Sambuc * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2684d9c625SLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2784d9c625SLionel Sambuc * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2884d9c625SLionel Sambuc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2984d9c625SLionel Sambuc * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3084d9c625SLionel Sambuc * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3184d9c625SLionel Sambuc * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
322fe8fb19SBen Gras */
332fe8fb19SBen Gras
342fe8fb19SBen Gras #include <sys/cdefs.h>
352fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
362fe8fb19SBen Gras #if 0
372fe8fb19SBen Gras static char *sccsid = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
382fe8fb19SBen Gras static char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC";
392fe8fb19SBen Gras static char sccsid[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro";
402fe8fb19SBen Gras #else
41*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: clnt_vc.c,v 1.26 2015/01/20 18:31:25 christos Exp $");
422fe8fb19SBen Gras #endif
432fe8fb19SBen Gras #endif
442fe8fb19SBen Gras
452fe8fb19SBen Gras /*
462fe8fb19SBen Gras * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
472fe8fb19SBen Gras *
482fe8fb19SBen Gras * Copyright (C) 1984, Sun Microsystems, Inc.
492fe8fb19SBen Gras *
502fe8fb19SBen Gras * TCP based RPC supports 'batched calls'.
512fe8fb19SBen Gras * A sequence of calls may be batched-up in a send buffer. The rpc call
522fe8fb19SBen Gras * return immediately to the client even though the call was not necessarily
532fe8fb19SBen Gras * sent. The batching occurs if the results' xdr routine is NULL (0) AND
542fe8fb19SBen Gras * the rpc timeout value is zero (see clnt.h, rpc).
552fe8fb19SBen Gras *
562fe8fb19SBen Gras * Clients should NOT casually batch calls that in fact return results; that is,
572fe8fb19SBen Gras * the server side should be aware that a call is batched and not produce any
582fe8fb19SBen Gras * return message. Batched calls that produce many result messages can
592fe8fb19SBen Gras * deadlock (netlock) the client and the server....
602fe8fb19SBen Gras *
612fe8fb19SBen Gras * Now go hang yourself.
622fe8fb19SBen Gras */
632fe8fb19SBen Gras
642fe8fb19SBen Gras #include "namespace.h"
652fe8fb19SBen Gras #include "reentrant.h"
662fe8fb19SBen Gras #include <sys/types.h>
672fe8fb19SBen Gras #include <sys/poll.h>
682fe8fb19SBen Gras #include <sys/socket.h>
692fe8fb19SBen Gras
702fe8fb19SBen Gras #include <assert.h>
712fe8fb19SBen Gras #include <err.h>
722fe8fb19SBen Gras #include <errno.h>
732fe8fb19SBen Gras #include <netdb.h>
742fe8fb19SBen Gras #include <stdio.h>
752fe8fb19SBen Gras #include <stdlib.h>
762fe8fb19SBen Gras #include <string.h>
772fe8fb19SBen Gras #include <unistd.h>
782fe8fb19SBen Gras #include <signal.h>
792fe8fb19SBen Gras
802fe8fb19SBen Gras #include <rpc/rpc.h>
812fe8fb19SBen Gras
8284d9c625SLionel Sambuc #include "svc_fdset.h"
832fe8fb19SBen Gras #include "rpc_internal.h"
842fe8fb19SBen Gras
852fe8fb19SBen Gras #ifdef __weak_alias
862fe8fb19SBen Gras __weak_alias(clnt_vc_create,_clnt_vc_create)
872fe8fb19SBen Gras #endif
882fe8fb19SBen Gras
892fe8fb19SBen Gras #define MCALL_MSG_SIZE 24
902fe8fb19SBen Gras
91f14fb602SLionel Sambuc static enum clnt_stat clnt_vc_call(CLIENT *, rpcproc_t, xdrproc_t,
92f14fb602SLionel Sambuc const char *, xdrproc_t, caddr_t, struct timeval);
93f14fb602SLionel Sambuc static void clnt_vc_geterr(CLIENT *, struct rpc_err *);
94f14fb602SLionel Sambuc static bool_t clnt_vc_freeres(CLIENT *, xdrproc_t, caddr_t);
95f14fb602SLionel Sambuc static void clnt_vc_abort(CLIENT *);
96f14fb602SLionel Sambuc static bool_t clnt_vc_control(CLIENT *, u_int, char *);
97f14fb602SLionel Sambuc static void clnt_vc_destroy(CLIENT *);
98f14fb602SLionel Sambuc static struct clnt_ops *clnt_vc_ops(void);
99f14fb602SLionel Sambuc static bool_t time_not_ok(struct timeval *);
100f14fb602SLionel Sambuc static int read_vc(caddr_t, caddr_t, int);
101f14fb602SLionel Sambuc static int write_vc(caddr_t, caddr_t, int);
1022fe8fb19SBen Gras
1032fe8fb19SBen Gras struct ct_data {
1042fe8fb19SBen Gras int ct_fd;
1052fe8fb19SBen Gras bool_t ct_closeit;
1062fe8fb19SBen Gras struct timeval ct_wait;
1072fe8fb19SBen Gras bool_t ct_waitset; /* wait set by clnt_control? */
1082fe8fb19SBen Gras struct netbuf ct_addr;
1092fe8fb19SBen Gras struct rpc_err ct_error;
1102fe8fb19SBen Gras union {
1112fe8fb19SBen Gras char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */
1122fe8fb19SBen Gras u_int32_t ct_mcalli;
1132fe8fb19SBen Gras } ct_u;
1142fe8fb19SBen Gras u_int ct_mpos; /* pos after marshal */
1152fe8fb19SBen Gras XDR ct_xdrs;
1162fe8fb19SBen Gras };
1172fe8fb19SBen Gras
1182fe8fb19SBen Gras /*
1192fe8fb19SBen Gras * This machinery implements per-fd locks for MT-safety. It is not
1202fe8fb19SBen Gras * sufficient to do per-CLIENT handle locks for MT-safety because a
1212fe8fb19SBen Gras * user may create more than one CLIENT handle with the same fd behind
1222fe8fb19SBen Gras * it. Therfore, we allocate an array of flags (vc_fd_locks), protected
1232fe8fb19SBen Gras * by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables
1242fe8fb19SBen Gras * similarly protected. Vc_fd_lock[fd] == 1 => a call is activte on some
1252fe8fb19SBen Gras * CLIENT handle created for that fd.
1262fe8fb19SBen Gras * The current implementation holds locks across the entire RPC and reply.
1272fe8fb19SBen Gras * Yes, this is silly, and as soon as this code is proven to work, this
1282fe8fb19SBen Gras * should be the first thing fixed. One step at a time.
1292fe8fb19SBen Gras */
1302fe8fb19SBen Gras #ifdef _REENTRANT
1312fe8fb19SBen Gras static int *vc_fd_locks;
1322fe8fb19SBen Gras #define __rpc_lock_value __isthreaded;
1332fe8fb19SBen Gras extern mutex_t clnt_fd_lock;
1342fe8fb19SBen Gras static cond_t *vc_cv;
1352fe8fb19SBen Gras #define release_fd_lock(fd, mask) { \
1362fe8fb19SBen Gras mutex_lock(&clnt_fd_lock); \
1372fe8fb19SBen Gras vc_fd_locks[fd] = 0; \
1382fe8fb19SBen Gras mutex_unlock(&clnt_fd_lock); \
1392fe8fb19SBen Gras thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \
1402fe8fb19SBen Gras cond_signal(&vc_cv[fd]); \
1412fe8fb19SBen Gras }
1422fe8fb19SBen Gras #else
1432fe8fb19SBen Gras #define release_fd_lock(fd,mask)
1442fe8fb19SBen Gras #define __rpc_lock_value 0
1452fe8fb19SBen Gras #endif
1462fe8fb19SBen Gras
14784d9c625SLionel Sambuc static __inline void
htonlp(void * dst,const void * src,uint32_t incr)148*0a6a1f1dSLionel Sambuc htonlp(void *dst, const void *src, uint32_t incr)
14984d9c625SLionel Sambuc {
15084d9c625SLionel Sambuc #if 0
15184d9c625SLionel Sambuc uint32_t tmp;
15284d9c625SLionel Sambuc memcpy(&tmp, src, sizeof(tmp));
153*0a6a1f1dSLionel Sambuc tmp = htonl(tmp + incr);
15484d9c625SLionel Sambuc memcpy(dst, &tmp, sizeof(tmp));
15584d9c625SLionel Sambuc #else
15684d9c625SLionel Sambuc /* We are aligned, so we think */
157*0a6a1f1dSLionel Sambuc *(uint32_t *)dst = htonl(*(const uint32_t *)src + incr);
15884d9c625SLionel Sambuc #endif
15984d9c625SLionel Sambuc }
16084d9c625SLionel Sambuc
16184d9c625SLionel Sambuc static __inline void
ntohlp(void * dst,const void * src)16284d9c625SLionel Sambuc ntohlp(void *dst, const void *src)
16384d9c625SLionel Sambuc {
16484d9c625SLionel Sambuc #if 0
16584d9c625SLionel Sambuc uint32_t tmp;
16684d9c625SLionel Sambuc memcpy(&tmp, src, sizeof(tmp));
16784d9c625SLionel Sambuc tmp = ntohl(tmp);
16884d9c625SLionel Sambuc memcpy(dst, &tmp, sizeof(tmp));
16984d9c625SLionel Sambuc #else
17084d9c625SLionel Sambuc /* We are aligned, so we think */
17184d9c625SLionel Sambuc *(uint32_t *)dst = htonl(*(const uint32_t *)src);
17284d9c625SLionel Sambuc #endif
17384d9c625SLionel Sambuc }
1742fe8fb19SBen Gras
1752fe8fb19SBen Gras /*
1762fe8fb19SBen Gras * Create a client handle for a connection.
1772fe8fb19SBen Gras * Default options are set, which the user can change using clnt_control()'s.
1782fe8fb19SBen Gras * The rpc/vc package does buffering similar to stdio, so the client
1792fe8fb19SBen Gras * must pick send and receive buffer sizes, 0 => use the default.
1802fe8fb19SBen Gras * NB: fd is copied into a private area.
1812fe8fb19SBen Gras * NB: The rpch->cl_auth is set null authentication. Caller may wish to
1822fe8fb19SBen Gras * set this something more useful.
1832fe8fb19SBen Gras *
1842fe8fb19SBen Gras * fd should be an open socket
1852fe8fb19SBen Gras */
1862fe8fb19SBen Gras CLIENT *
clnt_vc_create(int fd,const struct netbuf * raddr,rpcprog_t prog,rpcvers_t vers,u_int sendsz,u_int recvsz)187f14fb602SLionel Sambuc clnt_vc_create(
188f14fb602SLionel Sambuc int fd,
189f14fb602SLionel Sambuc const struct netbuf *raddr,
190f14fb602SLionel Sambuc rpcprog_t prog,
191f14fb602SLionel Sambuc rpcvers_t vers,
192f14fb602SLionel Sambuc u_int sendsz,
193f14fb602SLionel Sambuc u_int recvsz
194f14fb602SLionel Sambuc )
1952fe8fb19SBen Gras {
1962fe8fb19SBen Gras CLIENT *h;
1972fe8fb19SBen Gras struct ct_data *ct = NULL;
1982fe8fb19SBen Gras struct rpc_msg call_msg;
1992fe8fb19SBen Gras #ifdef _REENTRANT
2002fe8fb19SBen Gras sigset_t mask;
2012fe8fb19SBen Gras #endif
2022fe8fb19SBen Gras sigset_t newmask;
2032fe8fb19SBen Gras struct sockaddr_storage ss;
2042fe8fb19SBen Gras socklen_t slen;
2052fe8fb19SBen Gras struct __rpc_sockinfo si;
2062fe8fb19SBen Gras
2072fe8fb19SBen Gras _DIAGASSERT(raddr != NULL);
2082fe8fb19SBen Gras
2092fe8fb19SBen Gras h = mem_alloc(sizeof(*h));
2102fe8fb19SBen Gras if (h == NULL) {
2112fe8fb19SBen Gras warnx("clnt_vc_create: out of memory");
2122fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_SYSTEMERROR;
2132fe8fb19SBen Gras rpc_createerr.cf_error.re_errno = errno;
2142fe8fb19SBen Gras goto fooy;
2152fe8fb19SBen Gras }
2162fe8fb19SBen Gras ct = mem_alloc(sizeof(*ct));
2172fe8fb19SBen Gras if (ct == NULL) {
2182fe8fb19SBen Gras warnx("clnt_vc_create: out of memory");
2192fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_SYSTEMERROR;
2202fe8fb19SBen Gras rpc_createerr.cf_error.re_errno = errno;
2212fe8fb19SBen Gras goto fooy;
2222fe8fb19SBen Gras }
2232fe8fb19SBen Gras
22484d9c625SLionel Sambuc __clnt_sigfillset(&newmask);
2252fe8fb19SBen Gras thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
2262fe8fb19SBen Gras #ifdef _REENTRANT
2272fe8fb19SBen Gras mutex_lock(&clnt_fd_lock);
2282fe8fb19SBen Gras if (vc_fd_locks == NULL) {
2292fe8fb19SBen Gras size_t cv_allocsz, fd_allocsz;
2302fe8fb19SBen Gras int dtbsize = __rpc_dtbsize();
2312fe8fb19SBen Gras
2322fe8fb19SBen Gras fd_allocsz = dtbsize * sizeof (int);
2332fe8fb19SBen Gras vc_fd_locks = mem_alloc(fd_allocsz);
2342fe8fb19SBen Gras if (vc_fd_locks == NULL) {
23584d9c625SLionel Sambuc goto blooy;
2362fe8fb19SBen Gras } else
2372fe8fb19SBen Gras memset(vc_fd_locks, '\0', fd_allocsz);
2382fe8fb19SBen Gras
2392fe8fb19SBen Gras _DIAGASSERT(vc_cv == NULL);
2402fe8fb19SBen Gras cv_allocsz = dtbsize * sizeof (cond_t);
2412fe8fb19SBen Gras vc_cv = mem_alloc(cv_allocsz);
2422fe8fb19SBen Gras if (vc_cv == NULL) {
2432fe8fb19SBen Gras mem_free(vc_fd_locks, fd_allocsz);
2442fe8fb19SBen Gras vc_fd_locks = NULL;
24584d9c625SLionel Sambuc goto blooy;
2462fe8fb19SBen Gras } else {
2472fe8fb19SBen Gras int i;
2482fe8fb19SBen Gras
2492fe8fb19SBen Gras for (i = 0; i < dtbsize; i++)
2502fe8fb19SBen Gras cond_init(&vc_cv[i], 0, (void *) 0);
2512fe8fb19SBen Gras }
2522fe8fb19SBen Gras } else
2532fe8fb19SBen Gras _DIAGASSERT(vc_cv != NULL);
2542fe8fb19SBen Gras #endif
2552fe8fb19SBen Gras
2562fe8fb19SBen Gras /*
2572fe8fb19SBen Gras * XXX - fvdl connecting while holding a mutex?
2582fe8fb19SBen Gras */
2592fe8fb19SBen Gras slen = sizeof ss;
2602fe8fb19SBen Gras if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
2612fe8fb19SBen Gras if (errno != ENOTCONN) {
2622fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_SYSTEMERROR;
2632fe8fb19SBen Gras rpc_createerr.cf_error.re_errno = errno;
26484d9c625SLionel Sambuc goto blooy;
2652fe8fb19SBen Gras }
2662fe8fb19SBen Gras if (connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){
2672fe8fb19SBen Gras rpc_createerr.cf_stat = RPC_SYSTEMERROR;
2682fe8fb19SBen Gras rpc_createerr.cf_error.re_errno = errno;
26984d9c625SLionel Sambuc goto blooy;
2702fe8fb19SBen Gras }
2712fe8fb19SBen Gras }
2722fe8fb19SBen Gras mutex_unlock(&clnt_fd_lock);
2732fe8fb19SBen Gras thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
2742fe8fb19SBen Gras if (!__rpc_fd2sockinfo(fd, &si))
2752fe8fb19SBen Gras goto fooy;
2762fe8fb19SBen Gras
2772fe8fb19SBen Gras ct->ct_closeit = FALSE;
2782fe8fb19SBen Gras
2792fe8fb19SBen Gras /*
2802fe8fb19SBen Gras * Set up private data struct
2812fe8fb19SBen Gras */
2822fe8fb19SBen Gras ct->ct_fd = fd;
2832fe8fb19SBen Gras ct->ct_wait.tv_usec = 0;
2842fe8fb19SBen Gras ct->ct_waitset = FALSE;
2852fe8fb19SBen Gras ct->ct_addr.buf = malloc((size_t)raddr->maxlen);
2862fe8fb19SBen Gras if (ct->ct_addr.buf == NULL)
2872fe8fb19SBen Gras goto fooy;
28884d9c625SLionel Sambuc memcpy(ct->ct_addr.buf, raddr->buf, (size_t)raddr->len);
28984d9c625SLionel Sambuc ct->ct_addr.len = raddr->len;
2902fe8fb19SBen Gras ct->ct_addr.maxlen = raddr->maxlen;
2912fe8fb19SBen Gras
2922fe8fb19SBen Gras /*
2932fe8fb19SBen Gras * Initialize call message
2942fe8fb19SBen Gras */
2952fe8fb19SBen Gras call_msg.rm_xid = __RPC_GETXID();
2962fe8fb19SBen Gras call_msg.rm_direction = CALL;
2972fe8fb19SBen Gras call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
2982fe8fb19SBen Gras call_msg.rm_call.cb_prog = (u_int32_t)prog;
2992fe8fb19SBen Gras call_msg.rm_call.cb_vers = (u_int32_t)vers;
3002fe8fb19SBen Gras
3012fe8fb19SBen Gras /*
3022fe8fb19SBen Gras * pre-serialize the static part of the call msg and stash it away
3032fe8fb19SBen Gras */
3042fe8fb19SBen Gras xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE,
3052fe8fb19SBen Gras XDR_ENCODE);
3062fe8fb19SBen Gras if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
3072fe8fb19SBen Gras if (ct->ct_closeit) {
3082fe8fb19SBen Gras (void)close(fd);
3092fe8fb19SBen Gras }
3102fe8fb19SBen Gras goto fooy;
3112fe8fb19SBen Gras }
3122fe8fb19SBen Gras ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
3132fe8fb19SBen Gras XDR_DESTROY(&(ct->ct_xdrs));
3142fe8fb19SBen Gras
3152fe8fb19SBen Gras /*
3162fe8fb19SBen Gras * Create a client handle which uses xdrrec for serialization
3172fe8fb19SBen Gras * and authnone for authentication.
3182fe8fb19SBen Gras */
3192fe8fb19SBen Gras h->cl_ops = clnt_vc_ops();
3202fe8fb19SBen Gras h->cl_private = ct;
3212fe8fb19SBen Gras h->cl_auth = authnone_create();
3222fe8fb19SBen Gras sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
3232fe8fb19SBen Gras recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
3242fe8fb19SBen Gras xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
3252fe8fb19SBen Gras h->cl_private, read_vc, write_vc);
3262fe8fb19SBen Gras return (h);
3272fe8fb19SBen Gras
32884d9c625SLionel Sambuc blooy:
32984d9c625SLionel Sambuc mutex_unlock(&clnt_fd_lock);
33084d9c625SLionel Sambuc thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
3312fe8fb19SBen Gras fooy:
3322fe8fb19SBen Gras /*
3332fe8fb19SBen Gras * Something goofed, free stuff and barf
3342fe8fb19SBen Gras */
3352fe8fb19SBen Gras if (ct)
3362fe8fb19SBen Gras mem_free(ct, sizeof(struct ct_data));
3372fe8fb19SBen Gras if (h)
3382fe8fb19SBen Gras mem_free(h, sizeof(CLIENT));
3392fe8fb19SBen Gras return (NULL);
3402fe8fb19SBen Gras }
3412fe8fb19SBen Gras
3422fe8fb19SBen Gras static enum clnt_stat
clnt_vc_call(CLIENT * h,rpcproc_t proc,xdrproc_t xdr_args,const char * args_ptr,xdrproc_t xdr_results,caddr_t results_ptr,struct timeval timeout)343f14fb602SLionel Sambuc clnt_vc_call(
344f14fb602SLionel Sambuc CLIENT *h,
345f14fb602SLionel Sambuc rpcproc_t proc,
346f14fb602SLionel Sambuc xdrproc_t xdr_args,
347f14fb602SLionel Sambuc const char *args_ptr,
348f14fb602SLionel Sambuc xdrproc_t xdr_results,
349f14fb602SLionel Sambuc caddr_t results_ptr,
350f14fb602SLionel Sambuc struct timeval timeout
351f14fb602SLionel Sambuc )
3522fe8fb19SBen Gras {
3532fe8fb19SBen Gras struct ct_data *ct;
3542fe8fb19SBen Gras XDR *xdrs;
3552fe8fb19SBen Gras struct rpc_msg reply_msg;
3562fe8fb19SBen Gras u_int32_t x_id;
3572fe8fb19SBen Gras u_int32_t *msg_x_id;
3582fe8fb19SBen Gras bool_t shipnow;
3592fe8fb19SBen Gras int refreshes = 2;
3602fe8fb19SBen Gras #ifdef _REENTRANT
3612fe8fb19SBen Gras sigset_t mask, newmask;
3622fe8fb19SBen Gras #endif
3632fe8fb19SBen Gras
3642fe8fb19SBen Gras _DIAGASSERT(h != NULL);
3652fe8fb19SBen Gras
3662fe8fb19SBen Gras ct = (struct ct_data *) h->cl_private;
3672fe8fb19SBen Gras
3682fe8fb19SBen Gras #ifdef _REENTRANT
36984d9c625SLionel Sambuc __clnt_sigfillset(&newmask);
3702fe8fb19SBen Gras thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
3712fe8fb19SBen Gras mutex_lock(&clnt_fd_lock);
3722fe8fb19SBen Gras while (vc_fd_locks[ct->ct_fd])
3732fe8fb19SBen Gras cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
3742fe8fb19SBen Gras vc_fd_locks[ct->ct_fd] = __rpc_lock_value;
3752fe8fb19SBen Gras mutex_unlock(&clnt_fd_lock);
3762fe8fb19SBen Gras #endif
3772fe8fb19SBen Gras
3782fe8fb19SBen Gras xdrs = &(ct->ct_xdrs);
3792fe8fb19SBen Gras msg_x_id = &ct->ct_u.ct_mcalli;
3802fe8fb19SBen Gras
3812fe8fb19SBen Gras if (!ct->ct_waitset) {
3822fe8fb19SBen Gras if (time_not_ok(&timeout) == FALSE)
3832fe8fb19SBen Gras ct->ct_wait = timeout;
3842fe8fb19SBen Gras }
3852fe8fb19SBen Gras
3862fe8fb19SBen Gras shipnow =
3872fe8fb19SBen Gras (xdr_results == NULL && timeout.tv_sec == 0
3882fe8fb19SBen Gras && timeout.tv_usec == 0) ? FALSE : TRUE;
3892fe8fb19SBen Gras
3902fe8fb19SBen Gras call_again:
3912fe8fb19SBen Gras xdrs->x_op = XDR_ENCODE;
3922fe8fb19SBen Gras ct->ct_error.re_status = RPC_SUCCESS;
3932fe8fb19SBen Gras x_id = ntohl(--(*msg_x_id));
3942fe8fb19SBen Gras if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) ||
3952fe8fb19SBen Gras (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
3962fe8fb19SBen Gras (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
3972fe8fb19SBen Gras (! (*xdr_args)(xdrs, __UNCONST(args_ptr)))) {
3982fe8fb19SBen Gras if (ct->ct_error.re_status == RPC_SUCCESS)
3992fe8fb19SBen Gras ct->ct_error.re_status = RPC_CANTENCODEARGS;
4002fe8fb19SBen Gras (void)xdrrec_endofrecord(xdrs, TRUE);
4012fe8fb19SBen Gras release_fd_lock(ct->ct_fd, mask);
4022fe8fb19SBen Gras return (ct->ct_error.re_status);
4032fe8fb19SBen Gras }
4042fe8fb19SBen Gras if (! xdrrec_endofrecord(xdrs, shipnow)) {
4052fe8fb19SBen Gras release_fd_lock(ct->ct_fd, mask);
4062fe8fb19SBen Gras return (ct->ct_error.re_status = RPC_CANTSEND);
4072fe8fb19SBen Gras }
4082fe8fb19SBen Gras if (! shipnow) {
4092fe8fb19SBen Gras release_fd_lock(ct->ct_fd, mask);
4102fe8fb19SBen Gras return (RPC_SUCCESS);
4112fe8fb19SBen Gras }
4122fe8fb19SBen Gras /*
4132fe8fb19SBen Gras * Hack to provide rpc-based message passing
4142fe8fb19SBen Gras */
4152fe8fb19SBen Gras if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
4162fe8fb19SBen Gras release_fd_lock(ct->ct_fd, mask);
4172fe8fb19SBen Gras return(ct->ct_error.re_status = RPC_TIMEDOUT);
4182fe8fb19SBen Gras }
4192fe8fb19SBen Gras
4202fe8fb19SBen Gras
4212fe8fb19SBen Gras /*
4222fe8fb19SBen Gras * Keep receiving until we get a valid transaction id
4232fe8fb19SBen Gras */
4242fe8fb19SBen Gras xdrs->x_op = XDR_DECODE;
4252fe8fb19SBen Gras for (;;) {
4262fe8fb19SBen Gras reply_msg.acpted_rply.ar_verf = _null_auth;
4272fe8fb19SBen Gras reply_msg.acpted_rply.ar_results.where = NULL;
4282fe8fb19SBen Gras reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
4292fe8fb19SBen Gras if (! xdrrec_skiprecord(xdrs)) {
4302fe8fb19SBen Gras release_fd_lock(ct->ct_fd, mask);
4312fe8fb19SBen Gras return (ct->ct_error.re_status);
4322fe8fb19SBen Gras }
4332fe8fb19SBen Gras /* now decode and validate the response header */
4342fe8fb19SBen Gras if (! xdr_replymsg(xdrs, &reply_msg)) {
4352fe8fb19SBen Gras if (ct->ct_error.re_status == RPC_SUCCESS)
4362fe8fb19SBen Gras continue;
4372fe8fb19SBen Gras release_fd_lock(ct->ct_fd, mask);
4382fe8fb19SBen Gras return (ct->ct_error.re_status);
4392fe8fb19SBen Gras }
4402fe8fb19SBen Gras if (reply_msg.rm_xid == x_id)
4412fe8fb19SBen Gras break;
4422fe8fb19SBen Gras }
4432fe8fb19SBen Gras
4442fe8fb19SBen Gras /*
4452fe8fb19SBen Gras * process header
4462fe8fb19SBen Gras */
4472fe8fb19SBen Gras _seterr_reply(&reply_msg, &(ct->ct_error));
4482fe8fb19SBen Gras if (ct->ct_error.re_status == RPC_SUCCESS) {
4492fe8fb19SBen Gras if (! AUTH_VALIDATE(h->cl_auth,
4502fe8fb19SBen Gras &reply_msg.acpted_rply.ar_verf)) {
4512fe8fb19SBen Gras ct->ct_error.re_status = RPC_AUTHERROR;
4522fe8fb19SBen Gras ct->ct_error.re_why = AUTH_INVALIDRESP;
4532fe8fb19SBen Gras } else if (! (*xdr_results)(xdrs, results_ptr)) {
4542fe8fb19SBen Gras if (ct->ct_error.re_status == RPC_SUCCESS)
4552fe8fb19SBen Gras ct->ct_error.re_status = RPC_CANTDECODERES;
4562fe8fb19SBen Gras }
4572fe8fb19SBen Gras /* free verifier ... */
4582fe8fb19SBen Gras if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
4592fe8fb19SBen Gras xdrs->x_op = XDR_FREE;
4602fe8fb19SBen Gras (void)xdr_opaque_auth(xdrs,
4612fe8fb19SBen Gras &(reply_msg.acpted_rply.ar_verf));
4622fe8fb19SBen Gras }
4632fe8fb19SBen Gras } /* end successful completion */
4642fe8fb19SBen Gras else {
4652fe8fb19SBen Gras /* maybe our credentials need to be refreshed ... */
4662fe8fb19SBen Gras if (refreshes-- && AUTH_REFRESH(h->cl_auth))
4672fe8fb19SBen Gras goto call_again;
4682fe8fb19SBen Gras } /* end of unsuccessful completion */
4692fe8fb19SBen Gras release_fd_lock(ct->ct_fd, mask);
4702fe8fb19SBen Gras return (ct->ct_error.re_status);
4712fe8fb19SBen Gras }
4722fe8fb19SBen Gras
4732fe8fb19SBen Gras static void
clnt_vc_geterr(CLIENT * h,struct rpc_err * errp)474f14fb602SLionel Sambuc clnt_vc_geterr(
475f14fb602SLionel Sambuc CLIENT *h,
476f14fb602SLionel Sambuc struct rpc_err *errp
477f14fb602SLionel Sambuc )
4782fe8fb19SBen Gras {
4792fe8fb19SBen Gras struct ct_data *ct;
4802fe8fb19SBen Gras
4812fe8fb19SBen Gras _DIAGASSERT(h != NULL);
4822fe8fb19SBen Gras _DIAGASSERT(errp != NULL);
4832fe8fb19SBen Gras
4842fe8fb19SBen Gras ct = (struct ct_data *) h->cl_private;
4852fe8fb19SBen Gras *errp = ct->ct_error;
4862fe8fb19SBen Gras }
4872fe8fb19SBen Gras
4882fe8fb19SBen Gras static bool_t
clnt_vc_freeres(CLIENT * cl,xdrproc_t xdr_res,caddr_t res_ptr)489f14fb602SLionel Sambuc clnt_vc_freeres(
490f14fb602SLionel Sambuc CLIENT *cl,
491f14fb602SLionel Sambuc xdrproc_t xdr_res,
492f14fb602SLionel Sambuc caddr_t res_ptr
493f14fb602SLionel Sambuc )
4942fe8fb19SBen Gras {
4952fe8fb19SBen Gras struct ct_data *ct;
4962fe8fb19SBen Gras XDR *xdrs;
4972fe8fb19SBen Gras bool_t dummy;
4982fe8fb19SBen Gras #ifdef _REENTRANT
4992fe8fb19SBen Gras sigset_t mask;
5002fe8fb19SBen Gras #endif
5012fe8fb19SBen Gras sigset_t newmask;
5022fe8fb19SBen Gras
5032fe8fb19SBen Gras _DIAGASSERT(cl != NULL);
5042fe8fb19SBen Gras
5052fe8fb19SBen Gras ct = (struct ct_data *)cl->cl_private;
5062fe8fb19SBen Gras xdrs = &(ct->ct_xdrs);
5072fe8fb19SBen Gras
50884d9c625SLionel Sambuc __clnt_sigfillset(&newmask);
5092fe8fb19SBen Gras thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
5102fe8fb19SBen Gras mutex_lock(&clnt_fd_lock);
5112fe8fb19SBen Gras #ifdef _REENTRANT
5122fe8fb19SBen Gras while (vc_fd_locks[ct->ct_fd])
5132fe8fb19SBen Gras cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
5142fe8fb19SBen Gras #endif
5152fe8fb19SBen Gras
5162fe8fb19SBen Gras xdrs->x_op = XDR_FREE;
5172fe8fb19SBen Gras dummy = (*xdr_res)(xdrs, res_ptr);
5182fe8fb19SBen Gras mutex_unlock(&clnt_fd_lock);
5192fe8fb19SBen Gras thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
5202fe8fb19SBen Gras cond_signal(&vc_cv[ct->ct_fd]);
5212fe8fb19SBen Gras
5222fe8fb19SBen Gras return dummy;
5232fe8fb19SBen Gras }
5242fe8fb19SBen Gras
5252fe8fb19SBen Gras /*ARGSUSED*/
5262fe8fb19SBen Gras static void
clnt_vc_abort(CLIENT * cl)527f14fb602SLionel Sambuc clnt_vc_abort(CLIENT *cl)
5282fe8fb19SBen Gras {
5292fe8fb19SBen Gras }
5302fe8fb19SBen Gras
5312fe8fb19SBen Gras static bool_t
clnt_vc_control(CLIENT * cl,u_int request,char * info)532f14fb602SLionel Sambuc clnt_vc_control(
533f14fb602SLionel Sambuc CLIENT *cl,
534f14fb602SLionel Sambuc u_int request,
535f14fb602SLionel Sambuc char *info
536f14fb602SLionel Sambuc )
5372fe8fb19SBen Gras {
5382fe8fb19SBen Gras struct ct_data *ct;
5392fe8fb19SBen Gras void *infop = info;
5402fe8fb19SBen Gras #ifdef _REENTRANT
5412fe8fb19SBen Gras sigset_t mask;
5422fe8fb19SBen Gras #endif
5432fe8fb19SBen Gras sigset_t newmask;
5442fe8fb19SBen Gras
5452fe8fb19SBen Gras _DIAGASSERT(cl != NULL);
5462fe8fb19SBen Gras
5472fe8fb19SBen Gras ct = (struct ct_data *)cl->cl_private;
5482fe8fb19SBen Gras
54984d9c625SLionel Sambuc __clnt_sigfillset(&newmask);
5502fe8fb19SBen Gras thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
5512fe8fb19SBen Gras mutex_lock(&clnt_fd_lock);
5522fe8fb19SBen Gras #ifdef _REENTRANT
5532fe8fb19SBen Gras while (vc_fd_locks[ct->ct_fd])
5542fe8fb19SBen Gras cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
5552fe8fb19SBen Gras vc_fd_locks[ct->ct_fd] = __rpc_lock_value;
5562fe8fb19SBen Gras #endif
5572fe8fb19SBen Gras mutex_unlock(&clnt_fd_lock);
5582fe8fb19SBen Gras
5592fe8fb19SBen Gras switch (request) {
5602fe8fb19SBen Gras case CLSET_FD_CLOSE:
5612fe8fb19SBen Gras ct->ct_closeit = TRUE;
5622fe8fb19SBen Gras release_fd_lock(ct->ct_fd, mask);
5632fe8fb19SBen Gras return (TRUE);
5642fe8fb19SBen Gras case CLSET_FD_NCLOSE:
5652fe8fb19SBen Gras ct->ct_closeit = FALSE;
5662fe8fb19SBen Gras release_fd_lock(ct->ct_fd, mask);
5672fe8fb19SBen Gras return (TRUE);
5682fe8fb19SBen Gras default:
5692fe8fb19SBen Gras break;
5702fe8fb19SBen Gras }
5712fe8fb19SBen Gras
5722fe8fb19SBen Gras /* for other requests which use info */
5732fe8fb19SBen Gras if (info == NULL) {
5742fe8fb19SBen Gras release_fd_lock(ct->ct_fd, mask);
5752fe8fb19SBen Gras return (FALSE);
5762fe8fb19SBen Gras }
5772fe8fb19SBen Gras switch (request) {
5782fe8fb19SBen Gras case CLSET_TIMEOUT:
5792fe8fb19SBen Gras if (time_not_ok((struct timeval *)(void *)info)) {
5802fe8fb19SBen Gras release_fd_lock(ct->ct_fd, mask);
5812fe8fb19SBen Gras return (FALSE);
5822fe8fb19SBen Gras }
5832fe8fb19SBen Gras ct->ct_wait = *(struct timeval *)infop;
5842fe8fb19SBen Gras ct->ct_waitset = TRUE;
5852fe8fb19SBen Gras break;
5862fe8fb19SBen Gras case CLGET_TIMEOUT:
5872fe8fb19SBen Gras *(struct timeval *)infop = ct->ct_wait;
5882fe8fb19SBen Gras break;
5892fe8fb19SBen Gras case CLGET_SERVER_ADDR:
5902fe8fb19SBen Gras (void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len);
5912fe8fb19SBen Gras break;
5922fe8fb19SBen Gras case CLGET_FD:
5932fe8fb19SBen Gras *(int *)(void *)info = ct->ct_fd;
5942fe8fb19SBen Gras break;
5952fe8fb19SBen Gras case CLGET_SVC_ADDR:
5962fe8fb19SBen Gras /* The caller should not free this memory area */
5972fe8fb19SBen Gras *(struct netbuf *)(void *)info = ct->ct_addr;
5982fe8fb19SBen Gras break;
5992fe8fb19SBen Gras case CLSET_SVC_ADDR: /* set to new address */
6002fe8fb19SBen Gras release_fd_lock(ct->ct_fd, mask);
6012fe8fb19SBen Gras return (FALSE);
6022fe8fb19SBen Gras case CLGET_XID:
6032fe8fb19SBen Gras /*
6042fe8fb19SBen Gras * use the knowledge that xid is the
6052fe8fb19SBen Gras * first element in the call structure
6062fe8fb19SBen Gras * This will get the xid of the PREVIOUS call
6072fe8fb19SBen Gras */
60884d9c625SLionel Sambuc ntohlp(info, &ct->ct_u.ct_mcalli);
6092fe8fb19SBen Gras break;
6102fe8fb19SBen Gras case CLSET_XID:
6112fe8fb19SBen Gras /* This will set the xid of the NEXT call */
6122fe8fb19SBen Gras /* increment by 1 as clnt_vc_call() decrements once */
613*0a6a1f1dSLionel Sambuc htonlp(&ct->ct_u.ct_mcalli, info, 1);
6142fe8fb19SBen Gras break;
6152fe8fb19SBen Gras case CLGET_VERS:
6162fe8fb19SBen Gras /*
6172fe8fb19SBen Gras * This RELIES on the information that, in the call body,
6182fe8fb19SBen Gras * the version number field is the fifth field from the
6192fe8fb19SBen Gras * begining of the RPC header. MUST be changed if the
6202fe8fb19SBen Gras * call_struct is changed
6212fe8fb19SBen Gras */
62284d9c625SLionel Sambuc ntohlp(info, ct->ct_u.ct_mcallc + 4 * BYTES_PER_XDR_UNIT);
6232fe8fb19SBen Gras break;
6242fe8fb19SBen Gras
6252fe8fb19SBen Gras case CLSET_VERS:
626*0a6a1f1dSLionel Sambuc htonlp(ct->ct_u.ct_mcallc + 4 * BYTES_PER_XDR_UNIT, info, 0);
6272fe8fb19SBen Gras break;
6282fe8fb19SBen Gras
6292fe8fb19SBen Gras case CLGET_PROG:
6302fe8fb19SBen Gras /*
6312fe8fb19SBen Gras * This RELIES on the information that, in the call body,
6322fe8fb19SBen Gras * the program number field is the fourth field from the
6332fe8fb19SBen Gras * begining of the RPC header. MUST be changed if the
6342fe8fb19SBen Gras * call_struct is changed
6352fe8fb19SBen Gras */
63684d9c625SLionel Sambuc ntohlp(info, ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT);
6372fe8fb19SBen Gras break;
6382fe8fb19SBen Gras
6392fe8fb19SBen Gras case CLSET_PROG:
640*0a6a1f1dSLionel Sambuc htonlp(ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT, info, 0);
6412fe8fb19SBen Gras break;
6422fe8fb19SBen Gras
6432fe8fb19SBen Gras default:
6442fe8fb19SBen Gras release_fd_lock(ct->ct_fd, mask);
6452fe8fb19SBen Gras return (FALSE);
6462fe8fb19SBen Gras }
6472fe8fb19SBen Gras release_fd_lock(ct->ct_fd, mask);
6482fe8fb19SBen Gras return (TRUE);
6492fe8fb19SBen Gras }
6502fe8fb19SBen Gras
6512fe8fb19SBen Gras
6522fe8fb19SBen Gras static void
clnt_vc_destroy(CLIENT * cl)653f14fb602SLionel Sambuc clnt_vc_destroy(CLIENT *cl)
6542fe8fb19SBen Gras {
6552fe8fb19SBen Gras struct ct_data *ct;
6562fe8fb19SBen Gras #ifdef _REENTRANT
6572fe8fb19SBen Gras int ct_fd;
6582fe8fb19SBen Gras sigset_t mask;
6592fe8fb19SBen Gras #endif
6602fe8fb19SBen Gras sigset_t newmask;
6612fe8fb19SBen Gras
6622fe8fb19SBen Gras _DIAGASSERT(cl != NULL);
6632fe8fb19SBen Gras
6642fe8fb19SBen Gras ct = (struct ct_data *) cl->cl_private;
6652fe8fb19SBen Gras
66684d9c625SLionel Sambuc __clnt_sigfillset(&newmask);
6672fe8fb19SBen Gras thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
6682fe8fb19SBen Gras mutex_lock(&clnt_fd_lock);
6692fe8fb19SBen Gras #ifdef _REENTRANT
670*0a6a1f1dSLionel Sambuc ct_fd = ct->ct_fd;
6712fe8fb19SBen Gras while (vc_fd_locks[ct_fd])
6722fe8fb19SBen Gras cond_wait(&vc_cv[ct_fd], &clnt_fd_lock);
6732fe8fb19SBen Gras #endif
6742fe8fb19SBen Gras if (ct->ct_closeit && ct->ct_fd != -1) {
6752fe8fb19SBen Gras (void)close(ct->ct_fd);
6762fe8fb19SBen Gras }
6772fe8fb19SBen Gras XDR_DESTROY(&(ct->ct_xdrs));
6782fe8fb19SBen Gras if (ct->ct_addr.buf)
6792fe8fb19SBen Gras free(ct->ct_addr.buf);
6802fe8fb19SBen Gras mem_free(ct, sizeof(struct ct_data));
6812fe8fb19SBen Gras mem_free(cl, sizeof(CLIENT));
6822fe8fb19SBen Gras mutex_unlock(&clnt_fd_lock);
6832fe8fb19SBen Gras thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
6842fe8fb19SBen Gras
6852fe8fb19SBen Gras cond_signal(&vc_cv[ct_fd]);
6862fe8fb19SBen Gras }
6872fe8fb19SBen Gras
6882fe8fb19SBen Gras /*
6892fe8fb19SBen Gras * Interface between xdr serializer and tcp connection.
6902fe8fb19SBen Gras * Behaves like the system calls, read & write, but keeps some error state
6912fe8fb19SBen Gras * around for the rpc level.
6922fe8fb19SBen Gras */
6932fe8fb19SBen Gras static int
read_vc(char * ctp,char * buf,int len)694f14fb602SLionel Sambuc read_vc(char *ctp, char *buf, int len)
6952fe8fb19SBen Gras {
6962fe8fb19SBen Gras struct ct_data *ct = (struct ct_data *)(void *)ctp;
6972fe8fb19SBen Gras struct pollfd fd;
6982fe8fb19SBen Gras struct timespec ts;
699f14fb602SLionel Sambuc ssize_t nread;
7002fe8fb19SBen Gras
7012fe8fb19SBen Gras if (len == 0)
7022fe8fb19SBen Gras return (0);
7032fe8fb19SBen Gras
7042fe8fb19SBen Gras TIMEVAL_TO_TIMESPEC(&ct->ct_wait, &ts);
7052fe8fb19SBen Gras fd.fd = ct->ct_fd;
7062fe8fb19SBen Gras fd.events = POLLIN;
7072fe8fb19SBen Gras for (;;) {
7082fe8fb19SBen Gras switch (pollts(&fd, 1, &ts, NULL)) {
7092fe8fb19SBen Gras case 0:
7102fe8fb19SBen Gras ct->ct_error.re_status = RPC_TIMEDOUT;
7112fe8fb19SBen Gras return (-1);
7122fe8fb19SBen Gras
7132fe8fb19SBen Gras case -1:
7142fe8fb19SBen Gras if (errno == EINTR)
7152fe8fb19SBen Gras continue;
7162fe8fb19SBen Gras ct->ct_error.re_status = RPC_CANTRECV;
7172fe8fb19SBen Gras ct->ct_error.re_errno = errno;
7182fe8fb19SBen Gras return (-1);
7192fe8fb19SBen Gras }
7202fe8fb19SBen Gras break;
7212fe8fb19SBen Gras }
722f14fb602SLionel Sambuc switch (nread = read(ct->ct_fd, buf, (size_t)len)) {
7232fe8fb19SBen Gras
7242fe8fb19SBen Gras case 0:
7252fe8fb19SBen Gras /* premature eof */
7262fe8fb19SBen Gras ct->ct_error.re_errno = ECONNRESET;
7272fe8fb19SBen Gras ct->ct_error.re_status = RPC_CANTRECV;
72884d9c625SLionel Sambuc nread = -1; /* it's really an error */
7292fe8fb19SBen Gras break;
7302fe8fb19SBen Gras
7312fe8fb19SBen Gras case -1:
7322fe8fb19SBen Gras ct->ct_error.re_errno = errno;
7332fe8fb19SBen Gras ct->ct_error.re_status = RPC_CANTRECV;
7342fe8fb19SBen Gras break;
7352fe8fb19SBen Gras }
736f14fb602SLionel Sambuc return (int)nread;
7372fe8fb19SBen Gras }
7382fe8fb19SBen Gras
7392fe8fb19SBen Gras static int
write_vc(char * ctp,char * buf,int len)740f14fb602SLionel Sambuc write_vc(char *ctp, char *buf, int len)
7412fe8fb19SBen Gras {
7422fe8fb19SBen Gras struct ct_data *ct = (struct ct_data *)(void *)ctp;
743f14fb602SLionel Sambuc ssize_t i;
744f14fb602SLionel Sambuc size_t cnt;
7452fe8fb19SBen Gras
7462fe8fb19SBen Gras for (cnt = len; cnt > 0; cnt -= i, buf += i) {
747f14fb602SLionel Sambuc if ((i = write(ct->ct_fd, buf, cnt)) == -1) {
7482fe8fb19SBen Gras ct->ct_error.re_errno = errno;
7492fe8fb19SBen Gras ct->ct_error.re_status = RPC_CANTSEND;
7502fe8fb19SBen Gras return (-1);
7512fe8fb19SBen Gras }
7522fe8fb19SBen Gras }
753f14fb602SLionel Sambuc return len;
7542fe8fb19SBen Gras }
7552fe8fb19SBen Gras
7562fe8fb19SBen Gras static struct clnt_ops *
clnt_vc_ops(void)757f14fb602SLionel Sambuc clnt_vc_ops(void)
7582fe8fb19SBen Gras {
7592fe8fb19SBen Gras static struct clnt_ops ops;
7602fe8fb19SBen Gras #ifdef _REENTRANT
7612fe8fb19SBen Gras extern mutex_t ops_lock;
7622fe8fb19SBen Gras sigset_t mask;
7632fe8fb19SBen Gras #endif
7642fe8fb19SBen Gras sigset_t newmask;
7652fe8fb19SBen Gras
7662fe8fb19SBen Gras /* VARIABLES PROTECTED BY ops_lock: ops */
7672fe8fb19SBen Gras
76884d9c625SLionel Sambuc __clnt_sigfillset(&newmask);
7692fe8fb19SBen Gras thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
7702fe8fb19SBen Gras mutex_lock(&ops_lock);
7712fe8fb19SBen Gras if (ops.cl_call == NULL) {
7722fe8fb19SBen Gras ops.cl_call = clnt_vc_call;
7732fe8fb19SBen Gras ops.cl_abort = clnt_vc_abort;
7742fe8fb19SBen Gras ops.cl_geterr = clnt_vc_geterr;
7752fe8fb19SBen Gras ops.cl_freeres = clnt_vc_freeres;
7762fe8fb19SBen Gras ops.cl_destroy = clnt_vc_destroy;
7772fe8fb19SBen Gras ops.cl_control = clnt_vc_control;
7782fe8fb19SBen Gras }
7792fe8fb19SBen Gras mutex_unlock(&ops_lock);
7802fe8fb19SBen Gras thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
7812fe8fb19SBen Gras return (&ops);
7822fe8fb19SBen Gras }
7832fe8fb19SBen Gras
7842fe8fb19SBen Gras /*
7852fe8fb19SBen Gras * Make sure that the time is not garbage. -1 value is disallowed.
7862fe8fb19SBen Gras * Note this is different from time_not_ok in clnt_dg.c
7872fe8fb19SBen Gras */
7882fe8fb19SBen Gras static bool_t
time_not_ok(struct timeval * t)789f14fb602SLionel Sambuc time_not_ok(struct timeval *t)
7902fe8fb19SBen Gras {
7912fe8fb19SBen Gras
7922fe8fb19SBen Gras _DIAGASSERT(t != NULL);
7932fe8fb19SBen Gras
7942fe8fb19SBen Gras return (t->tv_sec <= -1 || t->tv_sec > 100000000 ||
7952fe8fb19SBen Gras t->tv_usec <= -1 || t->tv_usec > 1000000);
7962fe8fb19SBen Gras }
797