1*ba96d07fShrs /*-
2*ba96d07fShrs * Copyright (c) 2009, Sun Microsystems, Inc.
3*ba96d07fShrs * All rights reserved.
4ce0e08e2SPeter Avalos *
5*ba96d07fShrs * Redistribution and use in source and binary forms, with or without
6*ba96d07fShrs * modification, are permitted provided that the following conditions are met:
7*ba96d07fShrs * - Redistributions of source code must retain the above copyright notice,
8*ba96d07fShrs * this list of conditions and the following disclaimer.
9*ba96d07fShrs * - Redistributions in binary form must reproduce the above copyright notice,
10*ba96d07fShrs * this list of conditions and the following disclaimer in the documentation
11*ba96d07fShrs * and/or other materials provided with the distribution.
12*ba96d07fShrs * - Neither the name of Sun Microsystems, Inc. nor the names of its
13*ba96d07fShrs * contributors may be used to endorse or promote products derived
14*ba96d07fShrs * from this software without specific prior written permission.
15ce0e08e2SPeter Avalos *
16*ba96d07fShrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17*ba96d07fShrs * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*ba96d07fShrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*ba96d07fShrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20*ba96d07fShrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*ba96d07fShrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*ba96d07fShrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*ba96d07fShrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*ba96d07fShrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*ba96d07fShrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*ba96d07fShrs * POSSIBILITY OF SUCH DAMAGE.
27ce0e08e2SPeter Avalos *
28ce0e08e2SPeter Avalos * @(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro; 2.2 88/08/01 4.0 RPCSRC
29ce0e08e2SPeter Avalos * @(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro
30ce0e08e2SPeter Avalos * $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $
31ce0e08e2SPeter Avalos * $FreeBSD: src/lib/libc/rpc/clnt_vc.c,v 1.20 2006/09/09 22:18:57 mbr Exp $
32ce0e08e2SPeter Avalos */
33ce0e08e2SPeter Avalos
34ce0e08e2SPeter Avalos /*
35ce0e08e2SPeter Avalos * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
36ce0e08e2SPeter Avalos *
37ce0e08e2SPeter Avalos * Copyright (C) 1984, Sun Microsystems, Inc.
38ce0e08e2SPeter Avalos *
39ce0e08e2SPeter Avalos * TCP based RPC supports 'batched calls'.
40ce0e08e2SPeter Avalos * A sequence of calls may be batched-up in a send buffer. The rpc call
41ce0e08e2SPeter Avalos * return immediately to the client even though the call was not necessarily
42ce0e08e2SPeter Avalos * sent. The batching occurs if the results' xdr routine is NULL (0) AND
43ce0e08e2SPeter Avalos * the rpc timeout value is zero (see clnt.h, rpc).
44ce0e08e2SPeter Avalos *
45ce0e08e2SPeter Avalos * Clients should NOT casually batch calls that in fact return results; that is,
46ce0e08e2SPeter Avalos * the server side should be aware that a call is batched and not produce any
47ce0e08e2SPeter Avalos * return message. Batched calls that produce many result messages can
48ce0e08e2SPeter Avalos * deadlock (netlock) the client and the server....
49ce0e08e2SPeter Avalos *
50ce0e08e2SPeter Avalos * Now go hang yourself.
51ce0e08e2SPeter Avalos */
52ce0e08e2SPeter Avalos
53ce0e08e2SPeter Avalos #include "namespace.h"
54ce0e08e2SPeter Avalos #include "reentrant.h"
55ce0e08e2SPeter Avalos #include <sys/types.h>
56ce0e08e2SPeter Avalos #include <sys/poll.h>
57ce0e08e2SPeter Avalos #include <sys/syslog.h>
58ce0e08e2SPeter Avalos #include <sys/socket.h>
59ce0e08e2SPeter Avalos #include <sys/un.h>
60ce0e08e2SPeter Avalos #include <sys/uio.h>
61ce0e08e2SPeter Avalos
62ce0e08e2SPeter Avalos #include <arpa/inet.h>
63ce0e08e2SPeter Avalos #include <assert.h>
64ce0e08e2SPeter Avalos #include <err.h>
65ce0e08e2SPeter Avalos #include <errno.h>
66ce0e08e2SPeter Avalos #include <netdb.h>
67ce0e08e2SPeter Avalos #include <stdio.h>
68ce0e08e2SPeter Avalos #include <stdlib.h>
69ce0e08e2SPeter Avalos #include <string.h>
70ce0e08e2SPeter Avalos #include <unistd.h>
71ce0e08e2SPeter Avalos #include <signal.h>
72ce0e08e2SPeter Avalos
73ce0e08e2SPeter Avalos #include <rpc/rpc.h>
74ce0e08e2SPeter Avalos #include "un-namespace.h"
75ce0e08e2SPeter Avalos #include "rpc_com.h"
76ce0e08e2SPeter Avalos #include "mt_misc.h"
77ce0e08e2SPeter Avalos
78ce0e08e2SPeter Avalos #define MCALL_MSG_SIZE 24
79ce0e08e2SPeter Avalos
80ce0e08e2SPeter Avalos struct cmessage {
81ce0e08e2SPeter Avalos struct cmsghdr cmsg;
82ce0e08e2SPeter Avalos struct cmsgcred cmcred;
83ce0e08e2SPeter Avalos };
84ce0e08e2SPeter Avalos
85ce0e08e2SPeter Avalos static void clnt_vc_abort(CLIENT *);
86ce0e08e2SPeter Avalos static enum clnt_stat clnt_vc_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
87ce0e08e2SPeter Avalos xdrproc_t, void *, struct timeval);
88ce0e08e2SPeter Avalos static bool_t clnt_vc_control(CLIENT *, u_int, void *);
89ce0e08e2SPeter Avalos static void clnt_vc_destroy(CLIENT *);
90ce0e08e2SPeter Avalos static bool_t clnt_vc_freeres(CLIENT *, xdrproc_t, void *);
91ce0e08e2SPeter Avalos static void clnt_vc_geterr(CLIENT *, struct rpc_err *);
92ce0e08e2SPeter Avalos static struct clnt_ops *clnt_vc_ops(void);
93ce0e08e2SPeter Avalos static int __msgread(int, void *, size_t);
94ce0e08e2SPeter Avalos static int __msgwrite(int, void *, size_t);
95ce0e08e2SPeter Avalos static int read_vc(void *, void *, int);
96ce0e08e2SPeter Avalos static bool_t time_not_ok(struct timeval *);
97ce0e08e2SPeter Avalos static int write_vc(void *, void *, int);
98ce0e08e2SPeter Avalos
99ce0e08e2SPeter Avalos struct ct_data {
100ce0e08e2SPeter Avalos int ct_fd; /* connection's fd */
101ce0e08e2SPeter Avalos bool_t ct_closeit; /* close it on destroy */
102ce0e08e2SPeter Avalos struct timeval ct_wait; /* wait interval in milliseconds */
103ce0e08e2SPeter Avalos bool_t ct_waitset; /* wait set by clnt_control? */
104ce0e08e2SPeter Avalos struct netbuf ct_addr; /* remote addr */
105ce0e08e2SPeter Avalos struct rpc_err ct_error;
106ce0e08e2SPeter Avalos union {
107ce0e08e2SPeter Avalos char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */
108ce0e08e2SPeter Avalos u_int32_t ct_mcalli;
109ce0e08e2SPeter Avalos } ct_u;
110ce0e08e2SPeter Avalos u_int ct_mpos; /* pos after marshal */
111ce0e08e2SPeter Avalos XDR ct_xdrs; /* XDR stream */
112ce0e08e2SPeter Avalos };
113ce0e08e2SPeter Avalos
114ce0e08e2SPeter Avalos /*
115ce0e08e2SPeter Avalos * This machinery implements per-fd locks for MT-safety. It is not
116ce0e08e2SPeter Avalos * sufficient to do per-CLIENT handle locks for MT-safety because a
117ce0e08e2SPeter Avalos * user may create more than one CLIENT handle with the same fd behind
118ce0e08e2SPeter Avalos * it. Therfore, we allocate an array of flags (vc_fd_locks), protected
119ce0e08e2SPeter Avalos * by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables
120ce0e08e2SPeter Avalos * similarly protected. Vc_fd_lock[fd] == 1 => a call is activte on some
121ce0e08e2SPeter Avalos * CLIENT handle created for that fd.
122ce0e08e2SPeter Avalos * The current implementation holds locks across the entire RPC and reply.
123ce0e08e2SPeter Avalos * Yes, this is silly, and as soon as this code is proven to work, this
124ce0e08e2SPeter Avalos * should be the first thing fixed. One step at a time.
125ce0e08e2SPeter Avalos */
126ce0e08e2SPeter Avalos static int *vc_fd_locks;
127ce0e08e2SPeter Avalos static cond_t *vc_cv;
128ce0e08e2SPeter Avalos #define release_fd_lock(fd, mask) { \
129ce0e08e2SPeter Avalos mutex_lock(&clnt_fd_lock); \
130ce0e08e2SPeter Avalos vc_fd_locks[fd] = 0; \
131ce0e08e2SPeter Avalos mutex_unlock(&clnt_fd_lock); \
1322038fb68SSascha Wildner thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \
133ce0e08e2SPeter Avalos cond_signal(&vc_cv[fd]); \
134ce0e08e2SPeter Avalos }
135ce0e08e2SPeter Avalos
136ce0e08e2SPeter Avalos static const char clnt_vc_errstr[] = "%s : %s";
137ce0e08e2SPeter Avalos static const char clnt_vc_str[] = "clnt_vc_create";
138ce0e08e2SPeter Avalos static const char __no_mem_str[] = "out of memory";
139ce0e08e2SPeter Avalos
140ce0e08e2SPeter Avalos /*
141ce0e08e2SPeter Avalos * Create a client handle for a connection.
142ce0e08e2SPeter Avalos * Default options are set, which the user can change using clnt_control()'s.
143ce0e08e2SPeter Avalos * The rpc/vc package does buffering similar to stdio, so the client
144ce0e08e2SPeter Avalos * must pick send and receive buffer sizes, 0 => use the default.
145ce0e08e2SPeter Avalos * NB: fd is copied into a private area.
146ce0e08e2SPeter Avalos * NB: The rpch->cl_auth is set null authentication. Caller may wish to
147ce0e08e2SPeter Avalos * set this something more useful.
148ce0e08e2SPeter Avalos *
149ce0e08e2SPeter Avalos * fd should be an open socket
150ce0e08e2SPeter Avalos */
151ce0e08e2SPeter Avalos CLIENT *
clnt_vc_create(int fd,const struct netbuf * raddr,const rpcprog_t prog,const rpcvers_t vers,u_int sendsz,u_int recvsz)152ce0e08e2SPeter Avalos clnt_vc_create(int fd, /* open file descriptor */
153ce0e08e2SPeter Avalos const struct netbuf *raddr, /* servers address */
154ce0e08e2SPeter Avalos const rpcprog_t prog, /* program number */
155ce0e08e2SPeter Avalos const rpcvers_t vers, /* version number */
156ce0e08e2SPeter Avalos u_int sendsz, /* buffer recv size */
157ce0e08e2SPeter Avalos u_int recvsz) /* buffer send size */
158ce0e08e2SPeter Avalos {
159ce0e08e2SPeter Avalos CLIENT *cl; /* client handle */
160ce0e08e2SPeter Avalos struct ct_data *ct = NULL; /* client handle */
161ce0e08e2SPeter Avalos struct timeval now;
162ce0e08e2SPeter Avalos struct rpc_msg call_msg;
163ce0e08e2SPeter Avalos static u_int32_t disrupt;
164ce0e08e2SPeter Avalos sigset_t mask;
165ce0e08e2SPeter Avalos sigset_t newmask;
166ce0e08e2SPeter Avalos struct sockaddr_storage ss;
167ce0e08e2SPeter Avalos socklen_t slen;
168ce0e08e2SPeter Avalos struct __rpc_sockinfo si;
169ce0e08e2SPeter Avalos
170ce0e08e2SPeter Avalos if (disrupt == 0)
171ce0e08e2SPeter Avalos disrupt = (u_int32_t)(long)raddr;
172ce0e08e2SPeter Avalos
173ce0e08e2SPeter Avalos cl = (CLIENT *)mem_alloc(sizeof (*cl));
174ce0e08e2SPeter Avalos ct = (struct ct_data *)mem_alloc(sizeof (*ct));
1752038fb68SSascha Wildner if ((cl == NULL) || (ct == NULL)) {
176ce0e08e2SPeter Avalos syslog(LOG_ERR, clnt_vc_errstr, clnt_vc_str, __no_mem_str);
177ce0e08e2SPeter Avalos rpc_createerr.cf_stat = RPC_SYSTEMERROR;
178ce0e08e2SPeter Avalos rpc_createerr.cf_error.re_errno = errno;
179ce0e08e2SPeter Avalos goto err;
180ce0e08e2SPeter Avalos }
181ce0e08e2SPeter Avalos ct->ct_addr.buf = NULL;
182ce0e08e2SPeter Avalos sigfillset(&newmask);
183ce0e08e2SPeter Avalos thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
184ce0e08e2SPeter Avalos mutex_lock(&clnt_fd_lock);
1852038fb68SSascha Wildner if (vc_fd_locks == NULL) {
186ce0e08e2SPeter Avalos int cv_allocsz, fd_allocsz;
187ce0e08e2SPeter Avalos int dtbsize = __rpc_dtbsize();
188ce0e08e2SPeter Avalos
189ce0e08e2SPeter Avalos fd_allocsz = dtbsize * sizeof (int);
190ce0e08e2SPeter Avalos vc_fd_locks = (int *) mem_alloc(fd_allocsz);
1912038fb68SSascha Wildner if (vc_fd_locks == NULL) {
192ce0e08e2SPeter Avalos mutex_unlock(&clnt_fd_lock);
193ce0e08e2SPeter Avalos thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
194ce0e08e2SPeter Avalos goto err;
195ce0e08e2SPeter Avalos } else
196ce0e08e2SPeter Avalos memset(vc_fd_locks, '\0', fd_allocsz);
197ce0e08e2SPeter Avalos
1982038fb68SSascha Wildner assert(vc_cv == NULL);
199ce0e08e2SPeter Avalos cv_allocsz = dtbsize * sizeof (cond_t);
200ce0e08e2SPeter Avalos vc_cv = (cond_t *) mem_alloc(cv_allocsz);
2012038fb68SSascha Wildner if (vc_cv == NULL) {
202ce0e08e2SPeter Avalos mem_free(vc_fd_locks, fd_allocsz);
2032038fb68SSascha Wildner vc_fd_locks = NULL;
204ce0e08e2SPeter Avalos mutex_unlock(&clnt_fd_lock);
205ce0e08e2SPeter Avalos thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
206ce0e08e2SPeter Avalos goto err;
207ce0e08e2SPeter Avalos } else {
208ce0e08e2SPeter Avalos int i;
209ce0e08e2SPeter Avalos
210ce0e08e2SPeter Avalos for (i = 0; i < dtbsize; i++)
211902ec341SSascha Wildner cond_init(&vc_cv[i], 0, NULL);
212ce0e08e2SPeter Avalos }
213ce0e08e2SPeter Avalos } else
2142038fb68SSascha Wildner assert(vc_cv != NULL);
215ce0e08e2SPeter Avalos
216ce0e08e2SPeter Avalos /*
217ce0e08e2SPeter Avalos * XXX - fvdl connecting while holding a mutex?
218ce0e08e2SPeter Avalos */
219ce0e08e2SPeter Avalos slen = sizeof ss;
220ce0e08e2SPeter Avalos if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
221ce0e08e2SPeter Avalos if (errno != ENOTCONN) {
222ce0e08e2SPeter Avalos rpc_createerr.cf_stat = RPC_SYSTEMERROR;
223ce0e08e2SPeter Avalos rpc_createerr.cf_error.re_errno = errno;
224ce0e08e2SPeter Avalos mutex_unlock(&clnt_fd_lock);
225ce0e08e2SPeter Avalos thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
226ce0e08e2SPeter Avalos goto err;
227ce0e08e2SPeter Avalos }
228ce0e08e2SPeter Avalos if (_connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){
229ce0e08e2SPeter Avalos rpc_createerr.cf_stat = RPC_SYSTEMERROR;
230ce0e08e2SPeter Avalos rpc_createerr.cf_error.re_errno = errno;
231ce0e08e2SPeter Avalos mutex_unlock(&clnt_fd_lock);
232ce0e08e2SPeter Avalos thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
233ce0e08e2SPeter Avalos goto err;
234ce0e08e2SPeter Avalos }
235ce0e08e2SPeter Avalos }
236ce0e08e2SPeter Avalos mutex_unlock(&clnt_fd_lock);
237ce0e08e2SPeter Avalos thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
238ce0e08e2SPeter Avalos if (!__rpc_fd2sockinfo(fd, &si))
239ce0e08e2SPeter Avalos goto err;
240ce0e08e2SPeter Avalos
241ce0e08e2SPeter Avalos ct->ct_closeit = FALSE;
242ce0e08e2SPeter Avalos
243ce0e08e2SPeter Avalos /*
244ce0e08e2SPeter Avalos * Set up private data struct
245ce0e08e2SPeter Avalos */
246ce0e08e2SPeter Avalos ct->ct_fd = fd;
247ce0e08e2SPeter Avalos ct->ct_wait.tv_usec = 0;
248ce0e08e2SPeter Avalos ct->ct_waitset = FALSE;
249ce0e08e2SPeter Avalos ct->ct_addr.buf = malloc(raddr->maxlen);
250ce0e08e2SPeter Avalos if (ct->ct_addr.buf == NULL)
251ce0e08e2SPeter Avalos goto err;
252ce0e08e2SPeter Avalos memcpy(ct->ct_addr.buf, raddr->buf, raddr->len);
253ce0e08e2SPeter Avalos ct->ct_addr.len = raddr->maxlen;
254ce0e08e2SPeter Avalos ct->ct_addr.maxlen = raddr->maxlen;
255ce0e08e2SPeter Avalos
256ce0e08e2SPeter Avalos /*
257ce0e08e2SPeter Avalos * Initialize call message
258ce0e08e2SPeter Avalos */
259ce0e08e2SPeter Avalos gettimeofday(&now, NULL);
260ce0e08e2SPeter Avalos call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now);
261ce0e08e2SPeter Avalos call_msg.rm_direction = CALL;
262ce0e08e2SPeter Avalos call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
263ce0e08e2SPeter Avalos call_msg.rm_call.cb_prog = (u_int32_t)prog;
264ce0e08e2SPeter Avalos call_msg.rm_call.cb_vers = (u_int32_t)vers;
265ce0e08e2SPeter Avalos
266ce0e08e2SPeter Avalos /*
267ce0e08e2SPeter Avalos * pre-serialize the static part of the call msg and stash it away
268ce0e08e2SPeter Avalos */
269ce0e08e2SPeter Avalos xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE,
270ce0e08e2SPeter Avalos XDR_ENCODE);
271ce0e08e2SPeter Avalos if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
272ce0e08e2SPeter Avalos if (ct->ct_closeit) {
273ce0e08e2SPeter Avalos _close(fd);
274ce0e08e2SPeter Avalos }
275ce0e08e2SPeter Avalos goto err;
276ce0e08e2SPeter Avalos }
277ce0e08e2SPeter Avalos ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
278ce0e08e2SPeter Avalos XDR_DESTROY(&(ct->ct_xdrs));
279ce0e08e2SPeter Avalos
280ce0e08e2SPeter Avalos /*
281ce0e08e2SPeter Avalos * Create a client handle which uses xdrrec for serialization
282ce0e08e2SPeter Avalos * and authnone for authentication.
283ce0e08e2SPeter Avalos */
284ce0e08e2SPeter Avalos cl->cl_ops = clnt_vc_ops();
285ce0e08e2SPeter Avalos cl->cl_private = ct;
286ce0e08e2SPeter Avalos cl->cl_auth = authnone_create();
287ce0e08e2SPeter Avalos sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
288ce0e08e2SPeter Avalos recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
289ce0e08e2SPeter Avalos xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
290ce0e08e2SPeter Avalos cl->cl_private, read_vc, write_vc);
291ce0e08e2SPeter Avalos return (cl);
292ce0e08e2SPeter Avalos
293ce0e08e2SPeter Avalos err:
294ce0e08e2SPeter Avalos if (cl) {
295ce0e08e2SPeter Avalos if (ct) {
296ce0e08e2SPeter Avalos if (ct->ct_addr.len)
297ce0e08e2SPeter Avalos mem_free(ct->ct_addr.buf, ct->ct_addr.len);
298ce0e08e2SPeter Avalos mem_free(ct, sizeof (struct ct_data));
299ce0e08e2SPeter Avalos }
300ce0e08e2SPeter Avalos if (cl)
301ce0e08e2SPeter Avalos mem_free(cl, sizeof (CLIENT));
302ce0e08e2SPeter Avalos }
3032038fb68SSascha Wildner return (NULL);
304ce0e08e2SPeter Avalos }
305ce0e08e2SPeter Avalos
306ce0e08e2SPeter Avalos static enum clnt_stat
clnt_vc_call(CLIENT * cl,rpcproc_t proc,xdrproc_t xdr_args,void * args_ptr,xdrproc_t xdr_results,void * results_ptr,struct timeval timeout)307ce0e08e2SPeter Avalos clnt_vc_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xdr_args, void *args_ptr,
308ce0e08e2SPeter Avalos xdrproc_t xdr_results, void *results_ptr, struct timeval timeout)
309ce0e08e2SPeter Avalos {
310ce0e08e2SPeter Avalos struct ct_data *ct = (struct ct_data *) cl->cl_private;
311ce0e08e2SPeter Avalos XDR *xdrs = &(ct->ct_xdrs);
312ce0e08e2SPeter Avalos struct rpc_msg reply_msg;
313ce0e08e2SPeter Avalos u_int32_t x_id;
314ce0e08e2SPeter Avalos u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */
315ce0e08e2SPeter Avalos bool_t shipnow;
316ce0e08e2SPeter Avalos int refreshes = 2;
317ce0e08e2SPeter Avalos sigset_t mask, newmask;
318ce0e08e2SPeter Avalos int rpc_lock_value;
319ce0e08e2SPeter Avalos
320ce0e08e2SPeter Avalos assert(cl != NULL);
321ce0e08e2SPeter Avalos
322ce0e08e2SPeter Avalos sigfillset(&newmask);
323ce0e08e2SPeter Avalos thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
324ce0e08e2SPeter Avalos mutex_lock(&clnt_fd_lock);
325ce0e08e2SPeter Avalos while (vc_fd_locks[ct->ct_fd])
326ce0e08e2SPeter Avalos cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
327ce0e08e2SPeter Avalos if (__isthreaded)
328ce0e08e2SPeter Avalos rpc_lock_value = 1;
329ce0e08e2SPeter Avalos else
330ce0e08e2SPeter Avalos rpc_lock_value = 0;
331ce0e08e2SPeter Avalos vc_fd_locks[ct->ct_fd] = rpc_lock_value;
332ce0e08e2SPeter Avalos mutex_unlock(&clnt_fd_lock);
333ce0e08e2SPeter Avalos if (!ct->ct_waitset) {
334ce0e08e2SPeter Avalos /* If time is not within limits, we ignore it. */
335ce0e08e2SPeter Avalos if (time_not_ok(&timeout) == FALSE)
336ce0e08e2SPeter Avalos ct->ct_wait = timeout;
337ce0e08e2SPeter Avalos }
338ce0e08e2SPeter Avalos
339ce0e08e2SPeter Avalos shipnow =
340ce0e08e2SPeter Avalos (xdr_results == NULL && timeout.tv_sec == 0
341ce0e08e2SPeter Avalos && timeout.tv_usec == 0) ? FALSE : TRUE;
342ce0e08e2SPeter Avalos
343ce0e08e2SPeter Avalos call_again:
344ce0e08e2SPeter Avalos xdrs->x_op = XDR_ENCODE;
345ce0e08e2SPeter Avalos ct->ct_error.re_status = RPC_SUCCESS;
346ce0e08e2SPeter Avalos x_id = ntohl(--(*msg_x_id));
347ce0e08e2SPeter Avalos
348ce0e08e2SPeter Avalos if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) ||
349ce0e08e2SPeter Avalos (! XDR_PUTINT32(xdrs, &proc)) ||
350ce0e08e2SPeter Avalos (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
351ce0e08e2SPeter Avalos (! (*xdr_args)(xdrs, args_ptr))) {
352ce0e08e2SPeter Avalos if (ct->ct_error.re_status == RPC_SUCCESS)
353ce0e08e2SPeter Avalos ct->ct_error.re_status = RPC_CANTENCODEARGS;
354ce0e08e2SPeter Avalos xdrrec_endofrecord(xdrs, TRUE);
355ce0e08e2SPeter Avalos release_fd_lock(ct->ct_fd, mask);
356ce0e08e2SPeter Avalos return (ct->ct_error.re_status);
357ce0e08e2SPeter Avalos }
358ce0e08e2SPeter Avalos if (! xdrrec_endofrecord(xdrs, shipnow)) {
359ce0e08e2SPeter Avalos release_fd_lock(ct->ct_fd, mask);
360ce0e08e2SPeter Avalos return (ct->ct_error.re_status = RPC_CANTSEND);
361ce0e08e2SPeter Avalos }
362ce0e08e2SPeter Avalos if (! shipnow) {
363ce0e08e2SPeter Avalos release_fd_lock(ct->ct_fd, mask);
364ce0e08e2SPeter Avalos return (RPC_SUCCESS);
365ce0e08e2SPeter Avalos }
366ce0e08e2SPeter Avalos /*
367ce0e08e2SPeter Avalos * Hack to provide rpc-based message passing
368ce0e08e2SPeter Avalos */
369ce0e08e2SPeter Avalos if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
370ce0e08e2SPeter Avalos release_fd_lock(ct->ct_fd, mask);
371ce0e08e2SPeter Avalos return(ct->ct_error.re_status = RPC_TIMEDOUT);
372ce0e08e2SPeter Avalos }
373ce0e08e2SPeter Avalos
374ce0e08e2SPeter Avalos
375ce0e08e2SPeter Avalos /*
376ce0e08e2SPeter Avalos * Keep receiving until we get a valid transaction id
377ce0e08e2SPeter Avalos */
378ce0e08e2SPeter Avalos xdrs->x_op = XDR_DECODE;
379ce0e08e2SPeter Avalos while (TRUE) {
380ce0e08e2SPeter Avalos reply_msg.acpted_rply.ar_verf = _null_auth;
381ce0e08e2SPeter Avalos reply_msg.acpted_rply.ar_results.where = NULL;
382ce0e08e2SPeter Avalos reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
383ce0e08e2SPeter Avalos if (! xdrrec_skiprecord(xdrs)) {
384ce0e08e2SPeter Avalos release_fd_lock(ct->ct_fd, mask);
385ce0e08e2SPeter Avalos return (ct->ct_error.re_status);
386ce0e08e2SPeter Avalos }
387ce0e08e2SPeter Avalos /* now decode and validate the response header */
388ce0e08e2SPeter Avalos if (! xdr_replymsg(xdrs, &reply_msg)) {
389ce0e08e2SPeter Avalos if (ct->ct_error.re_status == RPC_SUCCESS)
390ce0e08e2SPeter Avalos continue;
391ce0e08e2SPeter Avalos release_fd_lock(ct->ct_fd, mask);
392ce0e08e2SPeter Avalos return (ct->ct_error.re_status);
393ce0e08e2SPeter Avalos }
394ce0e08e2SPeter Avalos if (reply_msg.rm_xid == x_id)
395ce0e08e2SPeter Avalos break;
396ce0e08e2SPeter Avalos }
397ce0e08e2SPeter Avalos
398ce0e08e2SPeter Avalos /*
399ce0e08e2SPeter Avalos * process header
400ce0e08e2SPeter Avalos */
401ce0e08e2SPeter Avalos _seterr_reply(&reply_msg, &(ct->ct_error));
402ce0e08e2SPeter Avalos if (ct->ct_error.re_status == RPC_SUCCESS) {
403ce0e08e2SPeter Avalos if (! AUTH_VALIDATE(cl->cl_auth,
404ce0e08e2SPeter Avalos &reply_msg.acpted_rply.ar_verf)) {
405ce0e08e2SPeter Avalos ct->ct_error.re_status = RPC_AUTHERROR;
406ce0e08e2SPeter Avalos ct->ct_error.re_why = AUTH_INVALIDRESP;
407ce0e08e2SPeter Avalos } else if (! (*xdr_results)(xdrs, results_ptr)) {
408ce0e08e2SPeter Avalos if (ct->ct_error.re_status == RPC_SUCCESS)
409ce0e08e2SPeter Avalos ct->ct_error.re_status = RPC_CANTDECODERES;
410ce0e08e2SPeter Avalos }
411ce0e08e2SPeter Avalos /* free verifier ... */
412ce0e08e2SPeter Avalos if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
413ce0e08e2SPeter Avalos xdrs->x_op = XDR_FREE;
414ce0e08e2SPeter Avalos xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf));
415ce0e08e2SPeter Avalos }
416ce0e08e2SPeter Avalos } /* end successful completion */
417ce0e08e2SPeter Avalos else {
418ce0e08e2SPeter Avalos /* maybe our credentials need to be refreshed ... */
419ce0e08e2SPeter Avalos if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg))
420ce0e08e2SPeter Avalos goto call_again;
421ce0e08e2SPeter Avalos } /* end of unsuccessful completion */
422ce0e08e2SPeter Avalos release_fd_lock(ct->ct_fd, mask);
423ce0e08e2SPeter Avalos return (ct->ct_error.re_status);
424ce0e08e2SPeter Avalos }
425ce0e08e2SPeter Avalos
426ce0e08e2SPeter Avalos static void
clnt_vc_geterr(CLIENT * cl,struct rpc_err * errp)427ce0e08e2SPeter Avalos clnt_vc_geterr(CLIENT *cl, struct rpc_err *errp)
428ce0e08e2SPeter Avalos {
429ce0e08e2SPeter Avalos struct ct_data *ct;
430ce0e08e2SPeter Avalos
431ce0e08e2SPeter Avalos assert(cl != NULL);
432ce0e08e2SPeter Avalos assert(errp != NULL);
433ce0e08e2SPeter Avalos
434ce0e08e2SPeter Avalos ct = (struct ct_data *) cl->cl_private;
435ce0e08e2SPeter Avalos *errp = ct->ct_error;
436ce0e08e2SPeter Avalos }
437ce0e08e2SPeter Avalos
438ce0e08e2SPeter Avalos static bool_t
clnt_vc_freeres(CLIENT * cl,xdrproc_t xdr_res,void * res_ptr)439ce0e08e2SPeter Avalos clnt_vc_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
440ce0e08e2SPeter Avalos {
441ce0e08e2SPeter Avalos struct ct_data *ct;
442ce0e08e2SPeter Avalos XDR *xdrs;
443ce0e08e2SPeter Avalos bool_t dummy;
444ce0e08e2SPeter Avalos sigset_t mask;
445ce0e08e2SPeter Avalos sigset_t newmask;
446ce0e08e2SPeter Avalos
447ce0e08e2SPeter Avalos assert(cl != NULL);
448ce0e08e2SPeter Avalos
449ce0e08e2SPeter Avalos ct = (struct ct_data *)cl->cl_private;
450ce0e08e2SPeter Avalos xdrs = &(ct->ct_xdrs);
451ce0e08e2SPeter Avalos
452ce0e08e2SPeter Avalos sigfillset(&newmask);
453ce0e08e2SPeter Avalos thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
454ce0e08e2SPeter Avalos mutex_lock(&clnt_fd_lock);
455ce0e08e2SPeter Avalos while (vc_fd_locks[ct->ct_fd])
456ce0e08e2SPeter Avalos cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
457ce0e08e2SPeter Avalos xdrs->x_op = XDR_FREE;
458ce0e08e2SPeter Avalos dummy = (*xdr_res)(xdrs, res_ptr);
459ce0e08e2SPeter Avalos mutex_unlock(&clnt_fd_lock);
460ce0e08e2SPeter Avalos thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
461ce0e08e2SPeter Avalos cond_signal(&vc_cv[ct->ct_fd]);
462ce0e08e2SPeter Avalos
463ce0e08e2SPeter Avalos return dummy;
464ce0e08e2SPeter Avalos }
465ce0e08e2SPeter Avalos
466ce0e08e2SPeter Avalos /*ARGSUSED*/
467ce0e08e2SPeter Avalos static void
clnt_vc_abort(CLIENT * cl __unused)4686d7019e6SSascha Wildner clnt_vc_abort(CLIENT *cl __unused)
469ce0e08e2SPeter Avalos {
470ce0e08e2SPeter Avalos }
471ce0e08e2SPeter Avalos
472ce0e08e2SPeter Avalos static bool_t
clnt_vc_control(CLIENT * cl,u_int request,void * info)473ce0e08e2SPeter Avalos clnt_vc_control(CLIENT *cl, u_int request, void *info)
474ce0e08e2SPeter Avalos {
475ce0e08e2SPeter Avalos struct ct_data *ct;
476ce0e08e2SPeter Avalos void *infop = info;
477ce0e08e2SPeter Avalos sigset_t mask;
478ce0e08e2SPeter Avalos sigset_t newmask;
479ce0e08e2SPeter Avalos int rpc_lock_value;
480ce0e08e2SPeter Avalos
481ce0e08e2SPeter Avalos assert(cl != NULL);
482ce0e08e2SPeter Avalos
483ce0e08e2SPeter Avalos ct = (struct ct_data *)cl->cl_private;
484ce0e08e2SPeter Avalos
485ce0e08e2SPeter Avalos sigfillset(&newmask);
486ce0e08e2SPeter Avalos thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
487ce0e08e2SPeter Avalos mutex_lock(&clnt_fd_lock);
488ce0e08e2SPeter Avalos while (vc_fd_locks[ct->ct_fd])
489ce0e08e2SPeter Avalos cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
490ce0e08e2SPeter Avalos if (__isthreaded)
491ce0e08e2SPeter Avalos rpc_lock_value = 1;
492ce0e08e2SPeter Avalos else
493ce0e08e2SPeter Avalos rpc_lock_value = 0;
494ce0e08e2SPeter Avalos vc_fd_locks[ct->ct_fd] = rpc_lock_value;
495ce0e08e2SPeter Avalos mutex_unlock(&clnt_fd_lock);
496ce0e08e2SPeter Avalos
497ce0e08e2SPeter Avalos switch (request) {
498ce0e08e2SPeter Avalos case CLSET_FD_CLOSE:
499ce0e08e2SPeter Avalos ct->ct_closeit = TRUE;
500ce0e08e2SPeter Avalos release_fd_lock(ct->ct_fd, mask);
501ce0e08e2SPeter Avalos return (TRUE);
502ce0e08e2SPeter Avalos case CLSET_FD_NCLOSE:
503ce0e08e2SPeter Avalos ct->ct_closeit = FALSE;
504ce0e08e2SPeter Avalos release_fd_lock(ct->ct_fd, mask);
505ce0e08e2SPeter Avalos return (TRUE);
506ce0e08e2SPeter Avalos default:
507ce0e08e2SPeter Avalos break;
508ce0e08e2SPeter Avalos }
509ce0e08e2SPeter Avalos
510ce0e08e2SPeter Avalos /* for other requests which use info */
511ce0e08e2SPeter Avalos if (info == NULL) {
512ce0e08e2SPeter Avalos release_fd_lock(ct->ct_fd, mask);
513ce0e08e2SPeter Avalos return (FALSE);
514ce0e08e2SPeter Avalos }
515ce0e08e2SPeter Avalos switch (request) {
516ce0e08e2SPeter Avalos case CLSET_TIMEOUT:
517ce0e08e2SPeter Avalos if (time_not_ok((struct timeval *)info)) {
518ce0e08e2SPeter Avalos release_fd_lock(ct->ct_fd, mask);
519ce0e08e2SPeter Avalos return (FALSE);
520ce0e08e2SPeter Avalos }
521ce0e08e2SPeter Avalos ct->ct_wait = *(struct timeval *)infop;
522ce0e08e2SPeter Avalos ct->ct_waitset = TRUE;
523ce0e08e2SPeter Avalos break;
524ce0e08e2SPeter Avalos case CLGET_TIMEOUT:
525ce0e08e2SPeter Avalos *(struct timeval *)infop = ct->ct_wait;
526ce0e08e2SPeter Avalos break;
527ce0e08e2SPeter Avalos case CLGET_SERVER_ADDR:
528ce0e08e2SPeter Avalos memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len);
529ce0e08e2SPeter Avalos break;
530ce0e08e2SPeter Avalos case CLGET_FD:
531ce0e08e2SPeter Avalos *(int *)info = ct->ct_fd;
532ce0e08e2SPeter Avalos break;
533ce0e08e2SPeter Avalos case CLGET_SVC_ADDR:
534ce0e08e2SPeter Avalos /* The caller should not free this memory area */
535ce0e08e2SPeter Avalos *(struct netbuf *)info = ct->ct_addr;
536ce0e08e2SPeter Avalos break;
537ce0e08e2SPeter Avalos case CLSET_SVC_ADDR: /* set to new address */
538ce0e08e2SPeter Avalos release_fd_lock(ct->ct_fd, mask);
539ce0e08e2SPeter Avalos return (FALSE);
540ce0e08e2SPeter Avalos case CLGET_XID:
541ce0e08e2SPeter Avalos /*
542ce0e08e2SPeter Avalos * use the knowledge that xid is the
543ce0e08e2SPeter Avalos * first element in the call structure
544ce0e08e2SPeter Avalos * This will get the xid of the PREVIOUS call
545ce0e08e2SPeter Avalos */
546ce0e08e2SPeter Avalos *(u_int32_t *)info =
547ce0e08e2SPeter Avalos ntohl(*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli);
548ce0e08e2SPeter Avalos break;
549ce0e08e2SPeter Avalos case CLSET_XID:
550ce0e08e2SPeter Avalos /* This will set the xid of the NEXT call */
551ce0e08e2SPeter Avalos *(u_int32_t *)(void *)&ct->ct_u.ct_mcalli =
552ce0e08e2SPeter Avalos htonl(*((u_int32_t *)info) + 1);
553ce0e08e2SPeter Avalos /* increment by 1 as clnt_vc_call() decrements once */
554ce0e08e2SPeter Avalos break;
555ce0e08e2SPeter Avalos case CLGET_VERS:
556ce0e08e2SPeter Avalos /*
557ce0e08e2SPeter Avalos * This RELIES on the information that, in the call body,
558ce0e08e2SPeter Avalos * the version number field is the fifth field from the
559ce0e08e2SPeter Avalos * begining of the RPC header. MUST be changed if the
560ce0e08e2SPeter Avalos * call_struct is changed
561ce0e08e2SPeter Avalos */
562ce0e08e2SPeter Avalos *(u_int32_t *)info =
563ce0e08e2SPeter Avalos ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
564ce0e08e2SPeter Avalos 4 * BYTES_PER_XDR_UNIT));
565ce0e08e2SPeter Avalos break;
566ce0e08e2SPeter Avalos
567ce0e08e2SPeter Avalos case CLSET_VERS:
568ce0e08e2SPeter Avalos *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
569ce0e08e2SPeter Avalos 4 * BYTES_PER_XDR_UNIT) =
570ce0e08e2SPeter Avalos htonl(*(u_int32_t *)info);
571ce0e08e2SPeter Avalos break;
572ce0e08e2SPeter Avalos
573ce0e08e2SPeter Avalos case CLGET_PROG:
574ce0e08e2SPeter Avalos /*
575ce0e08e2SPeter Avalos * This RELIES on the information that, in the call body,
576ce0e08e2SPeter Avalos * the program number field is the fourth field from the
577ce0e08e2SPeter Avalos * begining of the RPC header. MUST be changed if the
578ce0e08e2SPeter Avalos * call_struct is changed
579ce0e08e2SPeter Avalos */
580ce0e08e2SPeter Avalos *(u_int32_t *)info =
581ce0e08e2SPeter Avalos ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
582ce0e08e2SPeter Avalos 3 * BYTES_PER_XDR_UNIT));
583ce0e08e2SPeter Avalos break;
584ce0e08e2SPeter Avalos
585ce0e08e2SPeter Avalos case CLSET_PROG:
586ce0e08e2SPeter Avalos *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
587ce0e08e2SPeter Avalos 3 * BYTES_PER_XDR_UNIT) =
588ce0e08e2SPeter Avalos htonl(*(u_int32_t *)info);
589ce0e08e2SPeter Avalos break;
590ce0e08e2SPeter Avalos
591ce0e08e2SPeter Avalos default:
592ce0e08e2SPeter Avalos release_fd_lock(ct->ct_fd, mask);
593ce0e08e2SPeter Avalos return (FALSE);
594ce0e08e2SPeter Avalos }
595ce0e08e2SPeter Avalos release_fd_lock(ct->ct_fd, mask);
596ce0e08e2SPeter Avalos return (TRUE);
597ce0e08e2SPeter Avalos }
598ce0e08e2SPeter Avalos
599ce0e08e2SPeter Avalos
600ce0e08e2SPeter Avalos static void
clnt_vc_destroy(CLIENT * cl)601ce0e08e2SPeter Avalos clnt_vc_destroy(CLIENT *cl)
602ce0e08e2SPeter Avalos {
603ce0e08e2SPeter Avalos struct ct_data *ct = (struct ct_data *) cl->cl_private;
604ce0e08e2SPeter Avalos int ct_fd = ct->ct_fd;
605ce0e08e2SPeter Avalos sigset_t mask;
606ce0e08e2SPeter Avalos sigset_t newmask;
607ce0e08e2SPeter Avalos
608ce0e08e2SPeter Avalos assert(cl != NULL);
609ce0e08e2SPeter Avalos
610ce0e08e2SPeter Avalos ct = (struct ct_data *) cl->cl_private;
611ce0e08e2SPeter Avalos
612ce0e08e2SPeter Avalos sigfillset(&newmask);
613ce0e08e2SPeter Avalos thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
614ce0e08e2SPeter Avalos mutex_lock(&clnt_fd_lock);
615ce0e08e2SPeter Avalos while (vc_fd_locks[ct_fd])
616ce0e08e2SPeter Avalos cond_wait(&vc_cv[ct_fd], &clnt_fd_lock);
617ce0e08e2SPeter Avalos if (ct->ct_closeit && ct->ct_fd != -1) {
618ce0e08e2SPeter Avalos _close(ct->ct_fd);
619ce0e08e2SPeter Avalos }
620ce0e08e2SPeter Avalos XDR_DESTROY(&(ct->ct_xdrs));
621ce0e08e2SPeter Avalos if (ct->ct_addr.buf)
622ce0e08e2SPeter Avalos free(ct->ct_addr.buf);
623ce0e08e2SPeter Avalos mem_free(ct, sizeof(struct ct_data));
624ce0e08e2SPeter Avalos mem_free(cl, sizeof(CLIENT));
625ce0e08e2SPeter Avalos mutex_unlock(&clnt_fd_lock);
626ce0e08e2SPeter Avalos thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
627ce0e08e2SPeter Avalos cond_signal(&vc_cv[ct_fd]);
628ce0e08e2SPeter Avalos }
629ce0e08e2SPeter Avalos
630ce0e08e2SPeter Avalos /*
631ce0e08e2SPeter Avalos * Interface between xdr serializer and tcp connection.
632ce0e08e2SPeter Avalos * Behaves like the system calls, read & write, but keeps some error state
633ce0e08e2SPeter Avalos * around for the rpc level.
634ce0e08e2SPeter Avalos */
635ce0e08e2SPeter Avalos static int
read_vc(void * ctp,void * buf,int len)636ce0e08e2SPeter Avalos read_vc(void *ctp, void *buf, int len)
637ce0e08e2SPeter Avalos {
638ce0e08e2SPeter Avalos struct sockaddr sa;
639ce0e08e2SPeter Avalos socklen_t sal;
640ce0e08e2SPeter Avalos struct ct_data *ct = (struct ct_data *)ctp;
641ce0e08e2SPeter Avalos struct pollfd fd;
642ce0e08e2SPeter Avalos int milliseconds = (int)((ct->ct_wait.tv_sec * 1000) +
643ce0e08e2SPeter Avalos (ct->ct_wait.tv_usec / 1000));
644ce0e08e2SPeter Avalos
645ce0e08e2SPeter Avalos if (len == 0)
646ce0e08e2SPeter Avalos return (0);
647ce0e08e2SPeter Avalos fd.fd = ct->ct_fd;
648ce0e08e2SPeter Avalos fd.events = POLLIN;
649ce0e08e2SPeter Avalos for (;;) {
650ce0e08e2SPeter Avalos switch (_poll(&fd, 1, milliseconds)) {
651ce0e08e2SPeter Avalos case 0:
652ce0e08e2SPeter Avalos ct->ct_error.re_status = RPC_TIMEDOUT;
653ce0e08e2SPeter Avalos return (-1);
654ce0e08e2SPeter Avalos
655ce0e08e2SPeter Avalos case -1:
656ce0e08e2SPeter Avalos if (errno == EINTR)
657ce0e08e2SPeter Avalos continue;
658ce0e08e2SPeter Avalos ct->ct_error.re_status = RPC_CANTRECV;
659ce0e08e2SPeter Avalos ct->ct_error.re_errno = errno;
660ce0e08e2SPeter Avalos return (-1);
661ce0e08e2SPeter Avalos }
662ce0e08e2SPeter Avalos break;
663ce0e08e2SPeter Avalos }
664ce0e08e2SPeter Avalos
665ce0e08e2SPeter Avalos sal = sizeof(sa);
666ce0e08e2SPeter Avalos if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) &&
667ce0e08e2SPeter Avalos (sa.sa_family == AF_LOCAL)) {
668ce0e08e2SPeter Avalos len = __msgread(ct->ct_fd, buf, (size_t)len);
669ce0e08e2SPeter Avalos } else {
670ce0e08e2SPeter Avalos len = _read(ct->ct_fd, buf, (size_t)len);
671ce0e08e2SPeter Avalos }
672ce0e08e2SPeter Avalos
673ce0e08e2SPeter Avalos switch (len) {
674ce0e08e2SPeter Avalos case 0:
675ce0e08e2SPeter Avalos /* premature eof */
676ce0e08e2SPeter Avalos ct->ct_error.re_errno = ECONNRESET;
677ce0e08e2SPeter Avalos ct->ct_error.re_status = RPC_CANTRECV;
678ce0e08e2SPeter Avalos len = -1; /* it's really an error */
679ce0e08e2SPeter Avalos break;
680ce0e08e2SPeter Avalos
681ce0e08e2SPeter Avalos case -1:
682ce0e08e2SPeter Avalos ct->ct_error.re_errno = errno;
683ce0e08e2SPeter Avalos ct->ct_error.re_status = RPC_CANTRECV;
684ce0e08e2SPeter Avalos break;
685ce0e08e2SPeter Avalos }
686ce0e08e2SPeter Avalos return (len);
687ce0e08e2SPeter Avalos }
688ce0e08e2SPeter Avalos
689ce0e08e2SPeter Avalos static int
write_vc(void * ctp,void * buf,int len)690ce0e08e2SPeter Avalos write_vc(void *ctp, void *buf, int len)
691ce0e08e2SPeter Avalos {
692ce0e08e2SPeter Avalos struct sockaddr sa;
693ce0e08e2SPeter Avalos socklen_t sal;
694ce0e08e2SPeter Avalos struct ct_data *ct = (struct ct_data *)ctp;
695ce0e08e2SPeter Avalos int i, cnt;
696ce0e08e2SPeter Avalos
697ce0e08e2SPeter Avalos sal = sizeof(sa);
698ce0e08e2SPeter Avalos if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) &&
699ce0e08e2SPeter Avalos (sa.sa_family == AF_LOCAL)) {
700ce0e08e2SPeter Avalos for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
701ce0e08e2SPeter Avalos if ((i = __msgwrite(ct->ct_fd, buf,
702ce0e08e2SPeter Avalos (size_t)cnt)) == -1) {
703ce0e08e2SPeter Avalos ct->ct_error.re_errno = errno;
704ce0e08e2SPeter Avalos ct->ct_error.re_status = RPC_CANTSEND;
705ce0e08e2SPeter Avalos return (-1);
706ce0e08e2SPeter Avalos }
707ce0e08e2SPeter Avalos }
708ce0e08e2SPeter Avalos } else {
709ce0e08e2SPeter Avalos for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
710ce0e08e2SPeter Avalos if ((i = _write(ct->ct_fd, buf, (size_t)cnt)) == -1) {
711ce0e08e2SPeter Avalos ct->ct_error.re_errno = errno;
712ce0e08e2SPeter Avalos ct->ct_error.re_status = RPC_CANTSEND;
713ce0e08e2SPeter Avalos return (-1);
714ce0e08e2SPeter Avalos }
715ce0e08e2SPeter Avalos }
716ce0e08e2SPeter Avalos }
717ce0e08e2SPeter Avalos return (len);
718ce0e08e2SPeter Avalos }
719ce0e08e2SPeter Avalos
720ce0e08e2SPeter Avalos static struct clnt_ops *
clnt_vc_ops(void)721ce0e08e2SPeter Avalos clnt_vc_ops(void)
722ce0e08e2SPeter Avalos {
723ce0e08e2SPeter Avalos static struct clnt_ops ops;
724ce0e08e2SPeter Avalos sigset_t mask, newmask;
725ce0e08e2SPeter Avalos
726ce0e08e2SPeter Avalos /* VARIABLES PROTECTED BY ops_lock: ops */
727ce0e08e2SPeter Avalos
728ce0e08e2SPeter Avalos sigfillset(&newmask);
729ce0e08e2SPeter Avalos thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
730ce0e08e2SPeter Avalos mutex_lock(&ops_lock);
731ce0e08e2SPeter Avalos if (ops.cl_call == NULL) {
732ce0e08e2SPeter Avalos ops.cl_call = clnt_vc_call;
733ce0e08e2SPeter Avalos ops.cl_abort = clnt_vc_abort;
734ce0e08e2SPeter Avalos ops.cl_geterr = clnt_vc_geterr;
735ce0e08e2SPeter Avalos ops.cl_freeres = clnt_vc_freeres;
736ce0e08e2SPeter Avalos ops.cl_destroy = clnt_vc_destroy;
737ce0e08e2SPeter Avalos ops.cl_control = clnt_vc_control;
738ce0e08e2SPeter Avalos }
739ce0e08e2SPeter Avalos mutex_unlock(&ops_lock);
740ce0e08e2SPeter Avalos thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
741ce0e08e2SPeter Avalos return (&ops);
742ce0e08e2SPeter Avalos }
743ce0e08e2SPeter Avalos
744ce0e08e2SPeter Avalos /*
745ce0e08e2SPeter Avalos * Make sure that the time is not garbage. -1 value is disallowed.
746ce0e08e2SPeter Avalos * Note this is different from time_not_ok in clnt_dg.c
747ce0e08e2SPeter Avalos */
748ce0e08e2SPeter Avalos static bool_t
time_not_ok(struct timeval * t)749ce0e08e2SPeter Avalos time_not_ok(struct timeval *t)
750ce0e08e2SPeter Avalos {
751ce0e08e2SPeter Avalos return (t->tv_sec <= -1 || t->tv_sec > 100000000 ||
752ce0e08e2SPeter Avalos t->tv_usec <= -1 || t->tv_usec > 1000000);
753ce0e08e2SPeter Avalos }
754ce0e08e2SPeter Avalos
755ce0e08e2SPeter Avalos static int
__msgread(int sock,void * buf,size_t cnt)756ce0e08e2SPeter Avalos __msgread(int sock, void *buf, size_t cnt)
757ce0e08e2SPeter Avalos {
758ce0e08e2SPeter Avalos struct iovec iov[1];
759ce0e08e2SPeter Avalos struct msghdr msg;
760ce0e08e2SPeter Avalos union {
761ce0e08e2SPeter Avalos struct cmsghdr cmsg;
762ce0e08e2SPeter Avalos char control[CMSG_SPACE(sizeof(struct cmsgcred))];
763ce0e08e2SPeter Avalos } cm;
764ce0e08e2SPeter Avalos
765ce0e08e2SPeter Avalos bzero((char *)&cm, sizeof(cm));
766ce0e08e2SPeter Avalos iov[0].iov_base = buf;
767ce0e08e2SPeter Avalos iov[0].iov_len = cnt;
768ce0e08e2SPeter Avalos
769ce0e08e2SPeter Avalos msg.msg_iov = iov;
770ce0e08e2SPeter Avalos msg.msg_iovlen = 1;
771ce0e08e2SPeter Avalos msg.msg_name = NULL;
772ce0e08e2SPeter Avalos msg.msg_namelen = 0;
773ce0e08e2SPeter Avalos msg.msg_control = (caddr_t)&cm;
774ce0e08e2SPeter Avalos msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
775ce0e08e2SPeter Avalos msg.msg_flags = 0;
776ce0e08e2SPeter Avalos
777ce0e08e2SPeter Avalos return(_recvmsg(sock, &msg, 0));
778ce0e08e2SPeter Avalos }
779ce0e08e2SPeter Avalos
780ce0e08e2SPeter Avalos static int
__msgwrite(int sock,void * buf,size_t cnt)781ce0e08e2SPeter Avalos __msgwrite(int sock, void *buf, size_t cnt)
782ce0e08e2SPeter Avalos {
783ce0e08e2SPeter Avalos struct iovec iov[1];
784ce0e08e2SPeter Avalos struct msghdr msg;
785ce0e08e2SPeter Avalos union {
786ce0e08e2SPeter Avalos struct cmsghdr cmsg;
787ce0e08e2SPeter Avalos char control[CMSG_SPACE(sizeof(struct cmsgcred))];
788ce0e08e2SPeter Avalos } cm;
789ce0e08e2SPeter Avalos
790ce0e08e2SPeter Avalos bzero((char *)&cm, sizeof(cm));
791ce0e08e2SPeter Avalos iov[0].iov_base = buf;
792ce0e08e2SPeter Avalos iov[0].iov_len = cnt;
793ce0e08e2SPeter Avalos
794ce0e08e2SPeter Avalos cm.cmsg.cmsg_type = SCM_CREDS;
795ce0e08e2SPeter Avalos cm.cmsg.cmsg_level = SOL_SOCKET;
796ce0e08e2SPeter Avalos cm.cmsg.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
797ce0e08e2SPeter Avalos
798ce0e08e2SPeter Avalos msg.msg_iov = iov;
799ce0e08e2SPeter Avalos msg.msg_iovlen = 1;
800ce0e08e2SPeter Avalos msg.msg_name = NULL;
801ce0e08e2SPeter Avalos msg.msg_namelen = 0;
802ce0e08e2SPeter Avalos msg.msg_control = (caddr_t)&cm;
803ce0e08e2SPeter Avalos msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
804ce0e08e2SPeter Avalos msg.msg_flags = 0;
805ce0e08e2SPeter Avalos
806ce0e08e2SPeter Avalos return(_sendmsg(sock, &msg, 0));
807ce0e08e2SPeter Avalos }
808