18360efbdSAlfred Perlstein /* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */
28360efbdSAlfred Perlstein
32e322d37SHiroki Sato /*-
48a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
58a16b7a1SPedro F. Giffuni *
62e322d37SHiroki Sato * Copyright (c) 2009, Sun Microsystems, Inc.
72e322d37SHiroki Sato * All rights reserved.
88360efbdSAlfred Perlstein *
92e322d37SHiroki Sato * Redistribution and use in source and binary forms, with or without
102e322d37SHiroki Sato * modification, are permitted provided that the following conditions are met:
112e322d37SHiroki Sato * - Redistributions of source code must retain the above copyright notice,
122e322d37SHiroki Sato * this list of conditions and the following disclaimer.
132e322d37SHiroki Sato * - Redistributions in binary form must reproduce the above copyright notice,
142e322d37SHiroki Sato * this list of conditions and the following disclaimer in the documentation
152e322d37SHiroki Sato * and/or other materials provided with the distribution.
162e322d37SHiroki Sato * - Neither the name of Sun Microsystems, Inc. nor the names of its
172e322d37SHiroki Sato * contributors may be used to endorse or promote products derived
182e322d37SHiroki Sato * from this software without specific prior written permission.
198360efbdSAlfred Perlstein *
202e322d37SHiroki Sato * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
212e322d37SHiroki Sato * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
222e322d37SHiroki Sato * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
232e322d37SHiroki Sato * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
242e322d37SHiroki Sato * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
252e322d37SHiroki Sato * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
262e322d37SHiroki Sato * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
272e322d37SHiroki Sato * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
282e322d37SHiroki Sato * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
292e322d37SHiroki Sato * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
302e322d37SHiroki Sato * POSSIBILITY OF SUCH DAMAGE.
318360efbdSAlfred Perlstein */
328360efbdSAlfred Perlstein
338360efbdSAlfred Perlstein /*
348360efbdSAlfred Perlstein * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
358360efbdSAlfred Perlstein *
368360efbdSAlfred Perlstein * Copyright (C) 1984, Sun Microsystems, Inc.
378360efbdSAlfred Perlstein *
388360efbdSAlfred Perlstein * TCP based RPC supports 'batched calls'.
398360efbdSAlfred Perlstein * A sequence of calls may be batched-up in a send buffer. The rpc call
408360efbdSAlfred Perlstein * return immediately to the client even though the call was not necessarily
418360efbdSAlfred Perlstein * sent. The batching occurs if the results' xdr routine is NULL (0) AND
428360efbdSAlfred Perlstein * the rpc timeout value is zero (see clnt.h, rpc).
438360efbdSAlfred Perlstein *
448360efbdSAlfred Perlstein * Clients should NOT casually batch calls that in fact return results; that is,
458360efbdSAlfred Perlstein * the server side should be aware that a call is batched and not produce any
468360efbdSAlfred Perlstein * return message. Batched calls that produce many result messages can
478360efbdSAlfred Perlstein * deadlock (netlock) the client and the server....
488360efbdSAlfred Perlstein *
498360efbdSAlfred Perlstein * Now go hang yourself.
508360efbdSAlfred Perlstein */
518360efbdSAlfred Perlstein
528360efbdSAlfred Perlstein #include "namespace.h"
539f5afc13SIan Dowse #include "reentrant.h"
548360efbdSAlfred Perlstein #include <sys/types.h>
558360efbdSAlfred Perlstein #include <sys/poll.h>
568360efbdSAlfred Perlstein #include <sys/syslog.h>
578360efbdSAlfred Perlstein #include <sys/socket.h>
58*24938f93SAlan Somers #include <sys/tree.h>
598360efbdSAlfred Perlstein #include <sys/un.h>
608360efbdSAlfred Perlstein #include <sys/uio.h>
618360efbdSAlfred Perlstein
62fd8e4ebcSMike Barcroft #include <arpa/inet.h>
638360efbdSAlfred Perlstein #include <assert.h>
648360efbdSAlfred Perlstein #include <err.h>
658360efbdSAlfred Perlstein #include <errno.h>
668360efbdSAlfred Perlstein #include <netdb.h>
67*24938f93SAlan Somers #include <pthread.h>
688360efbdSAlfred Perlstein #include <stdio.h>
69*24938f93SAlan Somers #include <stdbool.h>
708360efbdSAlfred Perlstein #include <stdlib.h>
718360efbdSAlfred Perlstein #include <string.h>
728360efbdSAlfred Perlstein #include <unistd.h>
738360efbdSAlfred Perlstein #include <signal.h>
748360efbdSAlfred Perlstein
758360efbdSAlfred Perlstein #include <rpc/rpc.h>
768f55a568SDoug Rabson #include <rpc/rpcsec_gss.h>
778360efbdSAlfred Perlstein #include "un-namespace.h"
788360efbdSAlfred Perlstein #include "rpc_com.h"
79235baf26SDaniel Eischen #include "mt_misc.h"
808360efbdSAlfred Perlstein
818360efbdSAlfred Perlstein #define MCALL_MSG_SIZE 24
828360efbdSAlfred Perlstein
83392df6bcSAlfred Perlstein struct cmessage {
84392df6bcSAlfred Perlstein struct cmsghdr cmsg;
85392df6bcSAlfred Perlstein struct cmsgcred cmcred;
86392df6bcSAlfred Perlstein };
87392df6bcSAlfred Perlstein
88f249dbccSDag-Erling Smørgrav static enum clnt_stat clnt_vc_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
89f249dbccSDag-Erling Smørgrav xdrproc_t, void *, struct timeval);
90c05ac53bSDavid E. O'Brien static void clnt_vc_geterr(CLIENT *, struct rpc_err *);
91f249dbccSDag-Erling Smørgrav static bool_t clnt_vc_freeres(CLIENT *, xdrproc_t, void *);
92c05ac53bSDavid E. O'Brien static void clnt_vc_abort(CLIENT *);
93cffc0b57SAlfred Perlstein static bool_t clnt_vc_control(CLIENT *, u_int, void *);
94c05ac53bSDavid E. O'Brien static void clnt_vc_destroy(CLIENT *);
95c05ac53bSDavid E. O'Brien static struct clnt_ops *clnt_vc_ops(void);
96c05ac53bSDavid E. O'Brien static bool_t time_not_ok(struct timeval *);
97f249dbccSDag-Erling Smørgrav static int read_vc(void *, void *, int);
98f249dbccSDag-Erling Smørgrav static int write_vc(void *, void *, int);
998360efbdSAlfred Perlstein static int __msgwrite(int, void *, size_t);
1008360efbdSAlfred Perlstein static int __msgread(int, void *, size_t);
1018360efbdSAlfred Perlstein
1028360efbdSAlfred Perlstein struct ct_data {
1038360efbdSAlfred Perlstein int ct_fd; /* connection's fd */
1048360efbdSAlfred Perlstein bool_t ct_closeit; /* close it on destroy */
1058360efbdSAlfred Perlstein struct timeval ct_wait; /* wait interval in milliseconds */
1068360efbdSAlfred Perlstein bool_t ct_waitset; /* wait set by clnt_control? */
1078360efbdSAlfred Perlstein struct netbuf ct_addr; /* remote addr */
1088360efbdSAlfred Perlstein struct rpc_err ct_error;
1098360efbdSAlfred Perlstein union {
1108360efbdSAlfred Perlstein char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */
1118360efbdSAlfred Perlstein u_int32_t ct_mcalli;
1128360efbdSAlfred Perlstein } ct_u;
1138360efbdSAlfred Perlstein u_int ct_mpos; /* pos after marshal */
1148360efbdSAlfred Perlstein XDR ct_xdrs; /* XDR stream */
1158360efbdSAlfred Perlstein };
1168360efbdSAlfred Perlstein
1178360efbdSAlfred Perlstein /*
1188360efbdSAlfred Perlstein * This machinery implements per-fd locks for MT-safety. It is not
1198360efbdSAlfred Perlstein * sufficient to do per-CLIENT handle locks for MT-safety because a
1208360efbdSAlfred Perlstein * user may create more than one CLIENT handle with the same fd behind
121*24938f93SAlan Somers * it. Therefore, we allocate an associative array of flags and condition
122*24938f93SAlan Somers * variables (vc_fd). The flags and the array are protected by the
123*24938f93SAlan Somers * clnt_fd_lock mutex. vc_fd_lock[fd] == 1 => a call is active on some
124*24938f93SAlan Somers * CLIENT handle created for that fd. The current implementation holds
125*24938f93SAlan Somers * locks across the entire RPC and reply. Yes, this is silly, and as soon
126*24938f93SAlan Somers * as this code is proven to work, this should be the first thing fixed.
127*24938f93SAlan Somers * One step at a time.
1288360efbdSAlfred Perlstein */
129*24938f93SAlan Somers struct vc_fd {
130*24938f93SAlan Somers RB_ENTRY(vc_fd) vc_link;
131*24938f93SAlan Somers int fd;
132*24938f93SAlan Somers mutex_t mtx;
133*24938f93SAlan Somers };
134*24938f93SAlan Somers static inline int
cmp_vc_fd(struct vc_fd * a,struct vc_fd * b)135*24938f93SAlan Somers cmp_vc_fd(struct vc_fd *a, struct vc_fd *b)
136a5c2f4e9SAlan Somers {
137*24938f93SAlan Somers if (a->fd > b->fd) {
138*24938f93SAlan Somers return (1);
139*24938f93SAlan Somers } else if (a->fd < b->fd) {
140*24938f93SAlan Somers return (-1);
141*24938f93SAlan Somers } else {
142*24938f93SAlan Somers return (0);
143*24938f93SAlan Somers }
144*24938f93SAlan Somers }
145*24938f93SAlan Somers RB_HEAD(vc_fd_list, vc_fd);
146*24938f93SAlan Somers RB_PROTOTYPE(vc_fd_list, vc_fd, vc_link, cmp_vc_fd);
147*24938f93SAlan Somers RB_GENERATE(vc_fd_list, vc_fd, vc_link, cmp_vc_fd);
148*24938f93SAlan Somers struct vc_fd_list vc_fd_head = RB_INITIALIZER(&vc_fd_head);
149*24938f93SAlan Somers
150*24938f93SAlan Somers /*
151*24938f93SAlan Somers * Find the lock structure for the given file descriptor, or initialize it if
152*24938f93SAlan Somers * it does not already exist. The clnt_fd_lock mutex must be held.
153*24938f93SAlan Somers */
154*24938f93SAlan Somers static struct vc_fd *
vc_fd_find(int fd)155*24938f93SAlan Somers vc_fd_find(int fd)
156*24938f93SAlan Somers {
157*24938f93SAlan Somers struct vc_fd key, *elem;
158*24938f93SAlan Somers
159*24938f93SAlan Somers key.fd = fd;
160*24938f93SAlan Somers elem = RB_FIND(vc_fd_list, &vc_fd_head, &key);
161*24938f93SAlan Somers if (elem == NULL) {
162*24938f93SAlan Somers elem = calloc(1, sizeof(*elem));
163*24938f93SAlan Somers elem->fd = fd;
164*24938f93SAlan Somers mutex_init(&elem->mtx, NULL);
165*24938f93SAlan Somers RB_INSERT(vc_fd_list, &vc_fd_head, elem);
166*24938f93SAlan Somers }
167*24938f93SAlan Somers return (elem);
168*24938f93SAlan Somers }
169*24938f93SAlan Somers
170*24938f93SAlan Somers static void
release_fd_lock(struct vc_fd * elem,sigset_t mask)171*24938f93SAlan Somers release_fd_lock(struct vc_fd *elem, sigset_t mask)
172*24938f93SAlan Somers {
173*24938f93SAlan Somers mutex_unlock(&elem->mtx);
174*24938f93SAlan Somers thr_sigsetmask(SIG_SETMASK, &mask, NULL);
1758360efbdSAlfred Perlstein }
1768360efbdSAlfred Perlstein
1778360efbdSAlfred Perlstein static const char clnt_vc_errstr[] = "%s : %s";
1788360efbdSAlfred Perlstein static const char clnt_vc_str[] = "clnt_vc_create";
1798360efbdSAlfred Perlstein static const char __no_mem_str[] = "out of memory";
1808360efbdSAlfred Perlstein
1818360efbdSAlfred Perlstein /*
1828360efbdSAlfred Perlstein * Create a client handle for a connection.
1838360efbdSAlfred Perlstein * Default options are set, which the user can change using clnt_control()'s.
1848360efbdSAlfred Perlstein * The rpc/vc package does buffering similar to stdio, so the client
1858360efbdSAlfred Perlstein * must pick send and receive buffer sizes, 0 => use the default.
1868360efbdSAlfred Perlstein * NB: fd is copied into a private area.
1878360efbdSAlfred Perlstein * NB: The rpch->cl_auth is set null authentication. Caller may wish to
1888360efbdSAlfred Perlstein * set this something more useful.
1898360efbdSAlfred Perlstein *
1908360efbdSAlfred Perlstein * fd should be an open socket
191587cf682SCraig Rodrigues *
192587cf682SCraig Rodrigues * fd - open file descriptor
193587cf682SCraig Rodrigues * raddr - servers address
194587cf682SCraig Rodrigues * prog - program number
195587cf682SCraig Rodrigues * vers - version number
196587cf682SCraig Rodrigues * sendsz - buffer send size
197587cf682SCraig Rodrigues * recvsz - buffer recv size
1988360efbdSAlfred Perlstein */
1998360efbdSAlfred Perlstein CLIENT *
clnt_vc_create(int fd,const struct netbuf * raddr,const rpcprog_t prog,const rpcvers_t vers,u_int sendsz,u_int recvsz)200587cf682SCraig Rodrigues clnt_vc_create(int fd, const struct netbuf *raddr, const rpcprog_t prog,
201587cf682SCraig Rodrigues const rpcvers_t vers, u_int sendsz, u_int recvsz)
2028360efbdSAlfred Perlstein {
2038360efbdSAlfred Perlstein CLIENT *cl; /* client handle */
2048360efbdSAlfred Perlstein struct ct_data *ct = NULL; /* client handle */
2058360efbdSAlfred Perlstein struct timeval now;
2068360efbdSAlfred Perlstein struct rpc_msg call_msg;
2078360efbdSAlfred Perlstein static u_int32_t disrupt;
2088360efbdSAlfred Perlstein struct sockaddr_storage ss;
2098360efbdSAlfred Perlstein socklen_t slen;
2108360efbdSAlfred Perlstein struct __rpc_sockinfo si;
2118360efbdSAlfred Perlstein
2128360efbdSAlfred Perlstein if (disrupt == 0)
2138360efbdSAlfred Perlstein disrupt = (u_int32_t)(long)raddr;
2148360efbdSAlfred Perlstein
2158360efbdSAlfred Perlstein cl = (CLIENT *)mem_alloc(sizeof (*cl));
2168360efbdSAlfred Perlstein ct = (struct ct_data *)mem_alloc(sizeof (*ct));
2178360efbdSAlfred Perlstein if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) {
2188360efbdSAlfred Perlstein (void) syslog(LOG_ERR, clnt_vc_errstr,
2198360efbdSAlfred Perlstein clnt_vc_str, __no_mem_str);
2208360efbdSAlfred Perlstein rpc_createerr.cf_stat = RPC_SYSTEMERROR;
2218360efbdSAlfred Perlstein rpc_createerr.cf_error.re_errno = errno;
2228360efbdSAlfred Perlstein goto err;
2238360efbdSAlfred Perlstein }
2248360efbdSAlfred Perlstein ct->ct_addr.buf = NULL;
2258360efbdSAlfred Perlstein
2268360efbdSAlfred Perlstein /*
2278360efbdSAlfred Perlstein * XXX - fvdl connecting while holding a mutex?
2288360efbdSAlfred Perlstein */
2298360efbdSAlfred Perlstein slen = sizeof ss;
2308360efbdSAlfred Perlstein if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
2318360efbdSAlfred Perlstein if (errno != ENOTCONN) {
2328360efbdSAlfred Perlstein rpc_createerr.cf_stat = RPC_SYSTEMERROR;
2338360efbdSAlfred Perlstein rpc_createerr.cf_error.re_errno = errno;
2348360efbdSAlfred Perlstein mutex_unlock(&clnt_fd_lock);
2358360efbdSAlfred Perlstein goto err;
2368360efbdSAlfred Perlstein }
2378360efbdSAlfred Perlstein if (_connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){
2388360efbdSAlfred Perlstein rpc_createerr.cf_stat = RPC_SYSTEMERROR;
2398360efbdSAlfred Perlstein rpc_createerr.cf_error.re_errno = errno;
2408360efbdSAlfred Perlstein mutex_unlock(&clnt_fd_lock);
2418360efbdSAlfred Perlstein goto err;
2428360efbdSAlfred Perlstein }
2438360efbdSAlfred Perlstein }
2448360efbdSAlfred Perlstein mutex_unlock(&clnt_fd_lock);
2458360efbdSAlfred Perlstein if (!__rpc_fd2sockinfo(fd, &si))
2468360efbdSAlfred Perlstein goto err;
2478360efbdSAlfred Perlstein
2488360efbdSAlfred Perlstein ct->ct_closeit = FALSE;
2498360efbdSAlfred Perlstein
2508360efbdSAlfred Perlstein /*
2518360efbdSAlfred Perlstein * Set up private data struct
2528360efbdSAlfred Perlstein */
2538360efbdSAlfred Perlstein ct->ct_fd = fd;
2548360efbdSAlfred Perlstein ct->ct_wait.tv_usec = 0;
2558360efbdSAlfred Perlstein ct->ct_waitset = FALSE;
2568360efbdSAlfred Perlstein ct->ct_addr.buf = malloc(raddr->maxlen);
2578360efbdSAlfred Perlstein if (ct->ct_addr.buf == NULL)
2588360efbdSAlfred Perlstein goto err;
259a8634a00SIan Dowse memcpy(ct->ct_addr.buf, raddr->buf, raddr->len);
2605ee74037SKevin Lo ct->ct_addr.len = raddr->len;
2618360efbdSAlfred Perlstein ct->ct_addr.maxlen = raddr->maxlen;
2628360efbdSAlfred Perlstein
2638360efbdSAlfred Perlstein /*
2648360efbdSAlfred Perlstein * Initialize call message
2658360efbdSAlfred Perlstein */
2668360efbdSAlfred Perlstein (void)gettimeofday(&now, NULL);
2678360efbdSAlfred Perlstein call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now);
2688360efbdSAlfred Perlstein call_msg.rm_direction = CALL;
2698360efbdSAlfred Perlstein call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
2708360efbdSAlfred Perlstein call_msg.rm_call.cb_prog = (u_int32_t)prog;
2718360efbdSAlfred Perlstein call_msg.rm_call.cb_vers = (u_int32_t)vers;
2728360efbdSAlfred Perlstein
2738360efbdSAlfred Perlstein /*
2748360efbdSAlfred Perlstein * pre-serialize the static part of the call msg and stash it away
2758360efbdSAlfred Perlstein */
2768360efbdSAlfred Perlstein xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE,
2778360efbdSAlfred Perlstein XDR_ENCODE);
2788360efbdSAlfred Perlstein if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
2798360efbdSAlfred Perlstein if (ct->ct_closeit) {
2808360efbdSAlfred Perlstein (void)_close(fd);
2818360efbdSAlfred Perlstein }
2828360efbdSAlfred Perlstein goto err;
2838360efbdSAlfred Perlstein }
2848360efbdSAlfred Perlstein ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
2858360efbdSAlfred Perlstein XDR_DESTROY(&(ct->ct_xdrs));
2868f55a568SDoug Rabson assert(ct->ct_mpos + sizeof(uint32_t) <= MCALL_MSG_SIZE);
2878360efbdSAlfred Perlstein
2888360efbdSAlfred Perlstein /*
2898360efbdSAlfred Perlstein * Create a client handle which uses xdrrec for serialization
2908360efbdSAlfred Perlstein * and authnone for authentication.
2918360efbdSAlfred Perlstein */
2928360efbdSAlfred Perlstein cl->cl_ops = clnt_vc_ops();
2938360efbdSAlfred Perlstein cl->cl_private = ct;
2948360efbdSAlfred Perlstein cl->cl_auth = authnone_create();
2958360efbdSAlfred Perlstein sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
2968360efbdSAlfred Perlstein recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
2978360efbdSAlfred Perlstein xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
2988360efbdSAlfred Perlstein cl->cl_private, read_vc, write_vc);
2998360efbdSAlfred Perlstein return (cl);
3008360efbdSAlfred Perlstein
3018360efbdSAlfred Perlstein err:
3028360efbdSAlfred Perlstein if (ct) {
3038360efbdSAlfred Perlstein if (ct->ct_addr.len)
3048360efbdSAlfred Perlstein mem_free(ct->ct_addr.buf, ct->ct_addr.len);
305f249dbccSDag-Erling Smørgrav mem_free(ct, sizeof (struct ct_data));
3068360efbdSAlfred Perlstein }
3078360efbdSAlfred Perlstein if (cl)
308f249dbccSDag-Erling Smørgrav mem_free(cl, sizeof (CLIENT));
3098360efbdSAlfred Perlstein return ((CLIENT *)NULL);
3108360efbdSAlfred Perlstein }
3118360efbdSAlfred Perlstein
3128360efbdSAlfred Perlstein 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)313587cf682SCraig Rodrigues clnt_vc_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xdr_args, void *args_ptr,
314587cf682SCraig Rodrigues xdrproc_t xdr_results, void *results_ptr, struct timeval timeout)
3158360efbdSAlfred Perlstein {
3168360efbdSAlfred Perlstein struct ct_data *ct = (struct ct_data *) cl->cl_private;
3178360efbdSAlfred Perlstein XDR *xdrs = &(ct->ct_xdrs);
3188360efbdSAlfred Perlstein struct rpc_msg reply_msg;
319*24938f93SAlan Somers struct vc_fd *elem;
3208360efbdSAlfred Perlstein u_int32_t x_id;
3218360efbdSAlfred Perlstein u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */
3228360efbdSAlfred Perlstein bool_t shipnow;
3238360efbdSAlfred Perlstein int refreshes = 2;
3248360efbdSAlfred Perlstein sigset_t mask, newmask;
3258f55a568SDoug Rabson bool_t reply_stat;
3268360efbdSAlfred Perlstein
3278360efbdSAlfred Perlstein assert(cl != NULL);
3288360efbdSAlfred Perlstein
3298360efbdSAlfred Perlstein sigfillset(&newmask);
3308360efbdSAlfred Perlstein thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
3318360efbdSAlfred Perlstein mutex_lock(&clnt_fd_lock);
332*24938f93SAlan Somers elem = vc_fd_find(ct->ct_fd);
3338360efbdSAlfred Perlstein mutex_unlock(&clnt_fd_lock);
334*24938f93SAlan Somers mutex_lock(&elem->mtx);
3358360efbdSAlfred Perlstein if (!ct->ct_waitset) {
3368360efbdSAlfred Perlstein /* If time is not within limits, we ignore it. */
3378360efbdSAlfred Perlstein if (time_not_ok(&timeout) == FALSE)
3388360efbdSAlfred Perlstein ct->ct_wait = timeout;
3398360efbdSAlfred Perlstein }
3408360efbdSAlfred Perlstein
3418360efbdSAlfred Perlstein shipnow =
3428360efbdSAlfred Perlstein (xdr_results == NULL && timeout.tv_sec == 0
3438360efbdSAlfred Perlstein && timeout.tv_usec == 0) ? FALSE : TRUE;
3448360efbdSAlfred Perlstein
3458360efbdSAlfred Perlstein call_again:
3468360efbdSAlfred Perlstein xdrs->x_op = XDR_ENCODE;
3478360efbdSAlfred Perlstein ct->ct_error.re_status = RPC_SUCCESS;
3488360efbdSAlfred Perlstein x_id = ntohl(--(*msg_x_id));
3498360efbdSAlfred Perlstein
3508f55a568SDoug Rabson if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
3518360efbdSAlfred Perlstein if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) ||
3528360efbdSAlfred Perlstein (! XDR_PUTINT32(xdrs, &proc)) ||
3538360efbdSAlfred Perlstein (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
3548360efbdSAlfred Perlstein (! (*xdr_args)(xdrs, args_ptr))) {
3558360efbdSAlfred Perlstein if (ct->ct_error.re_status == RPC_SUCCESS)
3568360efbdSAlfred Perlstein ct->ct_error.re_status = RPC_CANTENCODEARGS;
3578360efbdSAlfred Perlstein (void)xdrrec_endofrecord(xdrs, TRUE);
358*24938f93SAlan Somers release_fd_lock(elem, mask);
3598360efbdSAlfred Perlstein return (ct->ct_error.re_status);
3608360efbdSAlfred Perlstein }
3618f55a568SDoug Rabson } else {
3628f55a568SDoug Rabson *(uint32_t *) &ct->ct_u.ct_mcallc[ct->ct_mpos] = htonl(proc);
3638f55a568SDoug Rabson if (! __rpc_gss_wrap(cl->cl_auth, ct->ct_u.ct_mcallc,
3648f55a568SDoug Rabson ct->ct_mpos + sizeof(uint32_t),
3658f55a568SDoug Rabson xdrs, xdr_args, args_ptr)) {
3668f55a568SDoug Rabson if (ct->ct_error.re_status == RPC_SUCCESS)
3678f55a568SDoug Rabson ct->ct_error.re_status = RPC_CANTENCODEARGS;
3688f55a568SDoug Rabson (void)xdrrec_endofrecord(xdrs, TRUE);
369*24938f93SAlan Somers release_fd_lock(elem, mask);
3708f55a568SDoug Rabson return (ct->ct_error.re_status);
3718f55a568SDoug Rabson }
3728f55a568SDoug Rabson }
3738360efbdSAlfred Perlstein if (! xdrrec_endofrecord(xdrs, shipnow)) {
374*24938f93SAlan Somers release_fd_lock(elem, mask);
3758360efbdSAlfred Perlstein return (ct->ct_error.re_status = RPC_CANTSEND);
3768360efbdSAlfred Perlstein }
3778360efbdSAlfred Perlstein if (! shipnow) {
378*24938f93SAlan Somers release_fd_lock(elem, mask);
3798360efbdSAlfred Perlstein return (RPC_SUCCESS);
3808360efbdSAlfred Perlstein }
3818360efbdSAlfred Perlstein /*
3828360efbdSAlfred Perlstein * Hack to provide rpc-based message passing
3838360efbdSAlfred Perlstein */
3848360efbdSAlfred Perlstein if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
385*24938f93SAlan Somers release_fd_lock(elem, mask);
3868360efbdSAlfred Perlstein return(ct->ct_error.re_status = RPC_TIMEDOUT);
3878360efbdSAlfred Perlstein }
3888360efbdSAlfred Perlstein
3898360efbdSAlfred Perlstein
3908360efbdSAlfred Perlstein /*
3918360efbdSAlfred Perlstein * Keep receiving until we get a valid transaction id
3928360efbdSAlfred Perlstein */
3938360efbdSAlfred Perlstein xdrs->x_op = XDR_DECODE;
3948360efbdSAlfred Perlstein while (TRUE) {
3958360efbdSAlfred Perlstein reply_msg.acpted_rply.ar_verf = _null_auth;
3968360efbdSAlfred Perlstein reply_msg.acpted_rply.ar_results.where = NULL;
3978360efbdSAlfred Perlstein reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
3988360efbdSAlfred Perlstein if (! xdrrec_skiprecord(xdrs)) {
399*24938f93SAlan Somers release_fd_lock(elem, mask);
4008360efbdSAlfred Perlstein return (ct->ct_error.re_status);
4018360efbdSAlfred Perlstein }
4028360efbdSAlfred Perlstein /* now decode and validate the response header */
4038360efbdSAlfred Perlstein if (! xdr_replymsg(xdrs, &reply_msg)) {
4048360efbdSAlfred Perlstein if (ct->ct_error.re_status == RPC_SUCCESS)
4058360efbdSAlfred Perlstein continue;
406*24938f93SAlan Somers release_fd_lock(elem, mask);
4078360efbdSAlfred Perlstein return (ct->ct_error.re_status);
4088360efbdSAlfred Perlstein }
4098360efbdSAlfred Perlstein if (reply_msg.rm_xid == x_id)
4108360efbdSAlfred Perlstein break;
4118360efbdSAlfred Perlstein }
4128360efbdSAlfred Perlstein
4138360efbdSAlfred Perlstein /*
4148360efbdSAlfred Perlstein * process header
4158360efbdSAlfred Perlstein */
4168360efbdSAlfred Perlstein _seterr_reply(&reply_msg, &(ct->ct_error));
4178360efbdSAlfred Perlstein if (ct->ct_error.re_status == RPC_SUCCESS) {
4188360efbdSAlfred Perlstein if (! AUTH_VALIDATE(cl->cl_auth,
4198360efbdSAlfred Perlstein &reply_msg.acpted_rply.ar_verf)) {
4208360efbdSAlfred Perlstein ct->ct_error.re_status = RPC_AUTHERROR;
4218360efbdSAlfred Perlstein ct->ct_error.re_why = AUTH_INVALIDRESP;
4228f55a568SDoug Rabson } else {
4238f55a568SDoug Rabson if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
4248f55a568SDoug Rabson reply_stat = (*xdr_results)(xdrs, results_ptr);
4258f55a568SDoug Rabson } else {
4268f55a568SDoug Rabson reply_stat = __rpc_gss_unwrap(cl->cl_auth,
4278f55a568SDoug Rabson xdrs, xdr_results, results_ptr);
4288f55a568SDoug Rabson }
4298f55a568SDoug Rabson if (! reply_stat) {
4308360efbdSAlfred Perlstein if (ct->ct_error.re_status == RPC_SUCCESS)
4318f55a568SDoug Rabson ct->ct_error.re_status =
4328f55a568SDoug Rabson RPC_CANTDECODERES;
4338f55a568SDoug Rabson }
4348360efbdSAlfred Perlstein }
4358360efbdSAlfred Perlstein /* free verifier ... */
4368360efbdSAlfred Perlstein if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
4378360efbdSAlfred Perlstein xdrs->x_op = XDR_FREE;
4388360efbdSAlfred Perlstein (void)xdr_opaque_auth(xdrs,
4398360efbdSAlfred Perlstein &(reply_msg.acpted_rply.ar_verf));
4408360efbdSAlfred Perlstein }
4418360efbdSAlfred Perlstein } /* end successful completion */
4428360efbdSAlfred Perlstein else {
4438360efbdSAlfred Perlstein /* maybe our credentials need to be refreshed ... */
4448360efbdSAlfred Perlstein if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg))
4458360efbdSAlfred Perlstein goto call_again;
4468360efbdSAlfred Perlstein } /* end of unsuccessful completion */
447*24938f93SAlan Somers release_fd_lock(elem, mask);
4488360efbdSAlfred Perlstein return (ct->ct_error.re_status);
4498360efbdSAlfred Perlstein }
4508360efbdSAlfred Perlstein
4518360efbdSAlfred Perlstein static void
clnt_vc_geterr(CLIENT * cl,struct rpc_err * errp)452587cf682SCraig Rodrigues clnt_vc_geterr(CLIENT *cl, struct rpc_err *errp)
4538360efbdSAlfred Perlstein {
4548360efbdSAlfred Perlstein struct ct_data *ct;
4558360efbdSAlfred Perlstein
4568360efbdSAlfred Perlstein assert(cl != NULL);
4578360efbdSAlfred Perlstein assert(errp != NULL);
4588360efbdSAlfred Perlstein
4598360efbdSAlfred Perlstein ct = (struct ct_data *) cl->cl_private;
4608360efbdSAlfred Perlstein *errp = ct->ct_error;
4618360efbdSAlfred Perlstein }
4628360efbdSAlfred Perlstein
4638360efbdSAlfred Perlstein static bool_t
clnt_vc_freeres(CLIENT * cl,xdrproc_t xdr_res,void * res_ptr)464587cf682SCraig Rodrigues clnt_vc_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
4658360efbdSAlfred Perlstein {
4668360efbdSAlfred Perlstein struct ct_data *ct;
467*24938f93SAlan Somers struct vc_fd *elem;
4688360efbdSAlfred Perlstein XDR *xdrs;
4698360efbdSAlfred Perlstein bool_t dummy;
4708360efbdSAlfred Perlstein sigset_t mask;
4718360efbdSAlfred Perlstein sigset_t newmask;
4728360efbdSAlfred Perlstein
4738360efbdSAlfred Perlstein assert(cl != NULL);
4748360efbdSAlfred Perlstein
4758360efbdSAlfred Perlstein ct = (struct ct_data *)cl->cl_private;
4768360efbdSAlfred Perlstein xdrs = &(ct->ct_xdrs);
4778360efbdSAlfred Perlstein
4788360efbdSAlfred Perlstein sigfillset(&newmask);
4798360efbdSAlfred Perlstein thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
4808360efbdSAlfred Perlstein mutex_lock(&clnt_fd_lock);
481*24938f93SAlan Somers elem = vc_fd_find(ct->ct_fd);
482*24938f93SAlan Somers mutex_lock(&elem->mtx);
4838360efbdSAlfred Perlstein xdrs->x_op = XDR_FREE;
4848360efbdSAlfred Perlstein dummy = (*xdr_res)(xdrs, res_ptr);
4858360efbdSAlfred Perlstein
486*24938f93SAlan Somers mutex_unlock(&clnt_fd_lock);
487*24938f93SAlan Somers release_fd_lock(elem, mask);
4888360efbdSAlfred Perlstein return dummy;
4898360efbdSAlfred Perlstein }
4908360efbdSAlfred Perlstein
4918360efbdSAlfred Perlstein /*ARGSUSED*/
4928360efbdSAlfred Perlstein static void
clnt_vc_abort(CLIENT * cl)493587cf682SCraig Rodrigues clnt_vc_abort(CLIENT *cl)
4948360efbdSAlfred Perlstein {
4958360efbdSAlfred Perlstein }
4968360efbdSAlfred Perlstein
497ef2c4faeSPedro F. Giffuni static __inline void
htonlp(void * dst,const void * src,uint32_t incr)498ef2c4faeSPedro F. Giffuni htonlp(void *dst, const void *src, uint32_t incr)
499ef2c4faeSPedro F. Giffuni {
500ef2c4faeSPedro F. Giffuni /* We are aligned, so we think */
501ef2c4faeSPedro F. Giffuni *(uint32_t *)dst = htonl(*(const uint32_t *)src + incr);
502ef2c4faeSPedro F. Giffuni }
503ef2c4faeSPedro F. Giffuni
504ef2c4faeSPedro F. Giffuni static __inline void
ntohlp(void * dst,const void * src)505ef2c4faeSPedro F. Giffuni ntohlp(void *dst, const void *src)
506ef2c4faeSPedro F. Giffuni {
507ef2c4faeSPedro F. Giffuni /* We are aligned, so we think */
508ef2c4faeSPedro F. Giffuni *(uint32_t *)dst = htonl(*(const uint32_t *)src);
509ef2c4faeSPedro F. Giffuni }
510ef2c4faeSPedro F. Giffuni
5118360efbdSAlfred Perlstein static bool_t
clnt_vc_control(CLIENT * cl,u_int request,void * info)512587cf682SCraig Rodrigues clnt_vc_control(CLIENT *cl, u_int request, void *info)
5138360efbdSAlfred Perlstein {
5148360efbdSAlfred Perlstein struct ct_data *ct;
515*24938f93SAlan Somers struct vc_fd *elem;
5168360efbdSAlfred Perlstein void *infop = info;
5178360efbdSAlfred Perlstein sigset_t mask;
5188360efbdSAlfred Perlstein sigset_t newmask;
5198360efbdSAlfred Perlstein
5208360efbdSAlfred Perlstein assert(cl != NULL);
5218360efbdSAlfred Perlstein
5228360efbdSAlfred Perlstein ct = (struct ct_data *)cl->cl_private;
5238360efbdSAlfred Perlstein
5248360efbdSAlfred Perlstein sigfillset(&newmask);
5258360efbdSAlfred Perlstein thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
5268360efbdSAlfred Perlstein mutex_lock(&clnt_fd_lock);
527*24938f93SAlan Somers elem = vc_fd_find(ct->ct_fd);
5288360efbdSAlfred Perlstein mutex_unlock(&clnt_fd_lock);
529*24938f93SAlan Somers mutex_lock(&elem->mtx);
5308360efbdSAlfred Perlstein
5318360efbdSAlfred Perlstein switch (request) {
5328360efbdSAlfred Perlstein case CLSET_FD_CLOSE:
5338360efbdSAlfred Perlstein ct->ct_closeit = TRUE;
534*24938f93SAlan Somers release_fd_lock(elem, mask);
5358360efbdSAlfred Perlstein return (TRUE);
5368360efbdSAlfred Perlstein case CLSET_FD_NCLOSE:
5378360efbdSAlfred Perlstein ct->ct_closeit = FALSE;
538*24938f93SAlan Somers release_fd_lock(elem, mask);
5398360efbdSAlfred Perlstein return (TRUE);
5408360efbdSAlfred Perlstein default:
5418360efbdSAlfred Perlstein break;
5428360efbdSAlfred Perlstein }
5438360efbdSAlfred Perlstein
5448360efbdSAlfred Perlstein /* for other requests which use info */
5458360efbdSAlfred Perlstein if (info == NULL) {
546*24938f93SAlan Somers release_fd_lock(elem, mask);
5478360efbdSAlfred Perlstein return (FALSE);
5488360efbdSAlfred Perlstein }
5498360efbdSAlfred Perlstein switch (request) {
5508360efbdSAlfred Perlstein case CLSET_TIMEOUT:
551cffc0b57SAlfred Perlstein if (time_not_ok((struct timeval *)info)) {
552*24938f93SAlan Somers release_fd_lock(elem, mask);
5538360efbdSAlfred Perlstein return (FALSE);
5548360efbdSAlfred Perlstein }
5558360efbdSAlfred Perlstein ct->ct_wait = *(struct timeval *)infop;
5568360efbdSAlfred Perlstein ct->ct_waitset = TRUE;
5578360efbdSAlfred Perlstein break;
5588360efbdSAlfred Perlstein case CLGET_TIMEOUT:
5598360efbdSAlfred Perlstein *(struct timeval *)infop = ct->ct_wait;
5608360efbdSAlfred Perlstein break;
5618360efbdSAlfred Perlstein case CLGET_SERVER_ADDR:
5628360efbdSAlfred Perlstein (void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len);
5638360efbdSAlfred Perlstein break;
5648360efbdSAlfred Perlstein case CLGET_FD:
565cffc0b57SAlfred Perlstein *(int *)info = ct->ct_fd;
5668360efbdSAlfred Perlstein break;
5678360efbdSAlfred Perlstein case CLGET_SVC_ADDR:
5688360efbdSAlfred Perlstein /* The caller should not free this memory area */
569cffc0b57SAlfred Perlstein *(struct netbuf *)info = ct->ct_addr;
5708360efbdSAlfred Perlstein break;
5718360efbdSAlfred Perlstein case CLSET_SVC_ADDR: /* set to new address */
572*24938f93SAlan Somers release_fd_lock(elem, mask);
5738360efbdSAlfred Perlstein return (FALSE);
5748360efbdSAlfred Perlstein case CLGET_XID:
5758360efbdSAlfred Perlstein /*
5768360efbdSAlfred Perlstein * use the knowledge that xid is the
5778360efbdSAlfred Perlstein * first element in the call structure
5788360efbdSAlfred Perlstein * This will get the xid of the PREVIOUS call
5798360efbdSAlfred Perlstein */
580ef2c4faeSPedro F. Giffuni ntohlp(info, &ct->ct_u.ct_mcalli);
5818360efbdSAlfred Perlstein break;
5828360efbdSAlfred Perlstein case CLSET_XID:
5838360efbdSAlfred Perlstein /* This will set the xid of the NEXT call */
5848360efbdSAlfred Perlstein /* increment by 1 as clnt_vc_call() decrements once */
585ef2c4faeSPedro F. Giffuni htonlp(&ct->ct_u.ct_mcalli, info, 1);
5868360efbdSAlfred Perlstein break;
5878360efbdSAlfred Perlstein case CLGET_VERS:
5888360efbdSAlfred Perlstein /*
5898360efbdSAlfred Perlstein * This RELIES on the information that, in the call body,
5908360efbdSAlfred Perlstein * the version number field is the fifth field from the
59132223c1bSPedro F. Giffuni * beginning of the RPC header. MUST be changed if the
5928360efbdSAlfred Perlstein * call_struct is changed
5938360efbdSAlfred Perlstein */
594ef2c4faeSPedro F. Giffuni ntohlp(info, ct->ct_u.ct_mcallc + 4 * BYTES_PER_XDR_UNIT);
5958360efbdSAlfred Perlstein break;
5968360efbdSAlfred Perlstein
5978360efbdSAlfred Perlstein case CLSET_VERS:
598ef2c4faeSPedro F. Giffuni htonlp(ct->ct_u.ct_mcallc + 4 * BYTES_PER_XDR_UNIT, info, 0);
5998360efbdSAlfred Perlstein break;
6008360efbdSAlfred Perlstein
6018360efbdSAlfred Perlstein case CLGET_PROG:
6028360efbdSAlfred Perlstein /*
6038360efbdSAlfred Perlstein * This RELIES on the information that, in the call body,
6048360efbdSAlfred Perlstein * the program number field is the fourth field from the
60532223c1bSPedro F. Giffuni * beginning of the RPC header. MUST be changed if the
6068360efbdSAlfred Perlstein * call_struct is changed
6078360efbdSAlfred Perlstein */
608ef2c4faeSPedro F. Giffuni ntohlp(info, ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT);
6098360efbdSAlfred Perlstein break;
6108360efbdSAlfred Perlstein
6118360efbdSAlfred Perlstein case CLSET_PROG:
612ef2c4faeSPedro F. Giffuni htonlp(ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT, info, 0);
6138360efbdSAlfred Perlstein break;
6148360efbdSAlfred Perlstein
6158360efbdSAlfred Perlstein default:
616*24938f93SAlan Somers release_fd_lock(elem, mask);
6178360efbdSAlfred Perlstein return (FALSE);
6188360efbdSAlfred Perlstein }
619*24938f93SAlan Somers release_fd_lock(elem, mask);
6208360efbdSAlfred Perlstein return (TRUE);
6218360efbdSAlfred Perlstein }
6228360efbdSAlfred Perlstein
6238360efbdSAlfred Perlstein
6248360efbdSAlfred Perlstein static void
clnt_vc_destroy(CLIENT * cl)625587cf682SCraig Rodrigues clnt_vc_destroy(CLIENT *cl)
6268360efbdSAlfred Perlstein {
6278360efbdSAlfred Perlstein struct ct_data *ct = (struct ct_data *) cl->cl_private;
628*24938f93SAlan Somers struct vc_fd *elem;
6298360efbdSAlfred Perlstein int ct_fd = ct->ct_fd;
6308360efbdSAlfred Perlstein sigset_t mask;
6318360efbdSAlfred Perlstein sigset_t newmask;
6328360efbdSAlfred Perlstein
6338360efbdSAlfred Perlstein assert(cl != NULL);
6348360efbdSAlfred Perlstein
6358360efbdSAlfred Perlstein ct = (struct ct_data *) cl->cl_private;
6368360efbdSAlfred Perlstein
6378360efbdSAlfred Perlstein sigfillset(&newmask);
6388360efbdSAlfred Perlstein thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
6398360efbdSAlfred Perlstein mutex_lock(&clnt_fd_lock);
640*24938f93SAlan Somers elem = vc_fd_find(ct_fd);
641*24938f93SAlan Somers mutex_lock(&elem->mtx);
6428360efbdSAlfred Perlstein if (ct->ct_closeit && ct->ct_fd != -1) {
6438360efbdSAlfred Perlstein (void)_close(ct->ct_fd);
6448360efbdSAlfred Perlstein }
6458360efbdSAlfred Perlstein XDR_DESTROY(&(ct->ct_xdrs));
6468360efbdSAlfred Perlstein free(ct->ct_addr.buf);
6478360efbdSAlfred Perlstein mem_free(ct, sizeof(struct ct_data));
6480c2222baSPedro F. Giffuni if (cl->cl_netid && cl->cl_netid[0])
6490c2222baSPedro F. Giffuni mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
6500c2222baSPedro F. Giffuni if (cl->cl_tp && cl->cl_tp[0])
6510c2222baSPedro F. Giffuni mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
6528360efbdSAlfred Perlstein mem_free(cl, sizeof(CLIENT));
6538360efbdSAlfred Perlstein mutex_unlock(&clnt_fd_lock);
654*24938f93SAlan Somers release_fd_lock(elem, mask);
6558360efbdSAlfred Perlstein }
6568360efbdSAlfred Perlstein
6578360efbdSAlfred Perlstein /*
6588360efbdSAlfred Perlstein * Interface between xdr serializer and tcp connection.
6598360efbdSAlfred Perlstein * Behaves like the system calls, read & write, but keeps some error state
6608360efbdSAlfred Perlstein * around for the rpc level.
6618360efbdSAlfred Perlstein */
6628360efbdSAlfred Perlstein static int
read_vc(void * ctp,void * buf,int len)663587cf682SCraig Rodrigues read_vc(void *ctp, void *buf, int len)
6648360efbdSAlfred Perlstein {
6658360efbdSAlfred Perlstein struct sockaddr sa;
6668360efbdSAlfred Perlstein socklen_t sal;
667f249dbccSDag-Erling Smørgrav struct ct_data *ct = (struct ct_data *)ctp;
6688360efbdSAlfred Perlstein struct pollfd fd;
6698360efbdSAlfred Perlstein int milliseconds = (int)((ct->ct_wait.tv_sec * 1000) +
6708360efbdSAlfred Perlstein (ct->ct_wait.tv_usec / 1000));
6718360efbdSAlfred Perlstein
6728360efbdSAlfred Perlstein if (len == 0)
6738360efbdSAlfred Perlstein return (0);
6748360efbdSAlfred Perlstein fd.fd = ct->ct_fd;
6758360efbdSAlfred Perlstein fd.events = POLLIN;
6768360efbdSAlfred Perlstein for (;;) {
6778360efbdSAlfred Perlstein switch (_poll(&fd, 1, milliseconds)) {
6788360efbdSAlfred Perlstein case 0:
6798360efbdSAlfred Perlstein ct->ct_error.re_status = RPC_TIMEDOUT;
6808360efbdSAlfred Perlstein return (-1);
6818360efbdSAlfred Perlstein
6828360efbdSAlfred Perlstein case -1:
6838360efbdSAlfred Perlstein if (errno == EINTR)
6848360efbdSAlfred Perlstein continue;
6858360efbdSAlfred Perlstein ct->ct_error.re_status = RPC_CANTRECV;
6868360efbdSAlfred Perlstein ct->ct_error.re_errno = errno;
6878360efbdSAlfred Perlstein return (-1);
6888360efbdSAlfred Perlstein }
6898360efbdSAlfred Perlstein break;
6908360efbdSAlfred Perlstein }
6918360efbdSAlfred Perlstein
6928360efbdSAlfred Perlstein sal = sizeof(sa);
6938360efbdSAlfred Perlstein if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) &&
6948360efbdSAlfred Perlstein (sa.sa_family == AF_LOCAL)) {
6958360efbdSAlfred Perlstein len = __msgread(ct->ct_fd, buf, (size_t)len);
6968360efbdSAlfred Perlstein } else {
6978360efbdSAlfred Perlstein len = _read(ct->ct_fd, buf, (size_t)len);
6988360efbdSAlfred Perlstein }
6998360efbdSAlfred Perlstein
7008360efbdSAlfred Perlstein switch (len) {
7018360efbdSAlfred Perlstein case 0:
7028360efbdSAlfred Perlstein /* premature eof */
7038360efbdSAlfred Perlstein ct->ct_error.re_errno = ECONNRESET;
7048360efbdSAlfred Perlstein ct->ct_error.re_status = RPC_CANTRECV;
7058360efbdSAlfred Perlstein len = -1; /* it's really an error */
7068360efbdSAlfred Perlstein break;
7078360efbdSAlfred Perlstein
7088360efbdSAlfred Perlstein case -1:
7098360efbdSAlfred Perlstein ct->ct_error.re_errno = errno;
7108360efbdSAlfred Perlstein ct->ct_error.re_status = RPC_CANTRECV;
7118360efbdSAlfred Perlstein break;
7128360efbdSAlfred Perlstein }
7138360efbdSAlfred Perlstein return (len);
7148360efbdSAlfred Perlstein }
7158360efbdSAlfred Perlstein
7168360efbdSAlfred Perlstein static int
write_vc(void * ctp,void * buf,int len)717587cf682SCraig Rodrigues write_vc(void *ctp, void *buf, int len)
7188360efbdSAlfred Perlstein {
7198360efbdSAlfred Perlstein struct sockaddr sa;
7208360efbdSAlfred Perlstein socklen_t sal;
721f249dbccSDag-Erling Smørgrav struct ct_data *ct = (struct ct_data *)ctp;
7228360efbdSAlfred Perlstein int i, cnt;
7238360efbdSAlfred Perlstein
7248360efbdSAlfred Perlstein sal = sizeof(sa);
7258360efbdSAlfred Perlstein if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) &&
7268360efbdSAlfred Perlstein (sa.sa_family == AF_LOCAL)) {
7271f7d62b3SStefan Farfeleder for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
7288360efbdSAlfred Perlstein if ((i = __msgwrite(ct->ct_fd, buf,
7298360efbdSAlfred Perlstein (size_t)cnt)) == -1) {
7308360efbdSAlfred Perlstein ct->ct_error.re_errno = errno;
7318360efbdSAlfred Perlstein ct->ct_error.re_status = RPC_CANTSEND;
7328360efbdSAlfred Perlstein return (-1);
7338360efbdSAlfred Perlstein }
7348360efbdSAlfred Perlstein }
7358360efbdSAlfred Perlstein } else {
736361de173SStefan Farfeleder for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
7378360efbdSAlfred Perlstein if ((i = _write(ct->ct_fd, buf, (size_t)cnt)) == -1) {
7388360efbdSAlfred Perlstein ct->ct_error.re_errno = errno;
7398360efbdSAlfred Perlstein ct->ct_error.re_status = RPC_CANTSEND;
7408360efbdSAlfred Perlstein return (-1);
7418360efbdSAlfred Perlstein }
7428360efbdSAlfred Perlstein }
7438360efbdSAlfred Perlstein }
7448360efbdSAlfred Perlstein return (len);
7458360efbdSAlfred Perlstein }
7468360efbdSAlfred Perlstein
7478360efbdSAlfred Perlstein static struct clnt_ops *
clnt_vc_ops(void)748587cf682SCraig Rodrigues clnt_vc_ops(void)
7498360efbdSAlfred Perlstein {
7508360efbdSAlfred Perlstein static struct clnt_ops ops;
7518360efbdSAlfred Perlstein sigset_t mask, newmask;
7528360efbdSAlfred Perlstein
7538360efbdSAlfred Perlstein /* VARIABLES PROTECTED BY ops_lock: ops */
7548360efbdSAlfred Perlstein
7558360efbdSAlfred Perlstein sigfillset(&newmask);
7568360efbdSAlfred Perlstein thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
7578360efbdSAlfred Perlstein mutex_lock(&ops_lock);
7588360efbdSAlfred Perlstein if (ops.cl_call == NULL) {
7598360efbdSAlfred Perlstein ops.cl_call = clnt_vc_call;
7608360efbdSAlfred Perlstein ops.cl_abort = clnt_vc_abort;
7618360efbdSAlfred Perlstein ops.cl_geterr = clnt_vc_geterr;
7628360efbdSAlfred Perlstein ops.cl_freeres = clnt_vc_freeres;
7638360efbdSAlfred Perlstein ops.cl_destroy = clnt_vc_destroy;
7648360efbdSAlfred Perlstein ops.cl_control = clnt_vc_control;
7658360efbdSAlfred Perlstein }
7668360efbdSAlfred Perlstein mutex_unlock(&ops_lock);
7678360efbdSAlfred Perlstein thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
7688360efbdSAlfred Perlstein return (&ops);
7698360efbdSAlfred Perlstein }
7708360efbdSAlfred Perlstein
7718360efbdSAlfred Perlstein /*
7728360efbdSAlfred Perlstein * Make sure that the time is not garbage. -1 value is disallowed.
7738360efbdSAlfred Perlstein * Note this is different from time_not_ok in clnt_dg.c
7748360efbdSAlfred Perlstein */
7758360efbdSAlfred Perlstein static bool_t
time_not_ok(struct timeval * t)776587cf682SCraig Rodrigues time_not_ok(struct timeval *t)
7778360efbdSAlfred Perlstein {
7788360efbdSAlfred Perlstein return (t->tv_sec <= -1 || t->tv_sec > 100000000 ||
7798360efbdSAlfred Perlstein t->tv_usec <= -1 || t->tv_usec > 1000000);
7808360efbdSAlfred Perlstein }
7818360efbdSAlfred Perlstein
7824ed6d634SAlfred Perlstein static int
__msgread(int sock,void * buf,size_t cnt)783587cf682SCraig Rodrigues __msgread(int sock, void *buf, size_t cnt)
7848360efbdSAlfred Perlstein {
7858360efbdSAlfred Perlstein struct iovec iov[1];
7868360efbdSAlfred Perlstein struct msghdr msg;
7872bc21ed9SDavid Malone union {
7882bc21ed9SDavid Malone struct cmsghdr cmsg;
7892bc21ed9SDavid Malone char control[CMSG_SPACE(sizeof(struct cmsgcred))];
7902bc21ed9SDavid Malone } cm;
7918360efbdSAlfred Perlstein
7928360efbdSAlfred Perlstein bzero((char *)&cm, sizeof(cm));
7938360efbdSAlfred Perlstein iov[0].iov_base = buf;
7948360efbdSAlfred Perlstein iov[0].iov_len = cnt;
7958360efbdSAlfred Perlstein
7968360efbdSAlfred Perlstein msg.msg_iov = iov;
7978360efbdSAlfred Perlstein msg.msg_iovlen = 1;
7988360efbdSAlfred Perlstein msg.msg_name = NULL;
7998360efbdSAlfred Perlstein msg.msg_namelen = 0;
8008360efbdSAlfred Perlstein msg.msg_control = (caddr_t)&cm;
8012bc21ed9SDavid Malone msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
8028360efbdSAlfred Perlstein msg.msg_flags = 0;
8038360efbdSAlfred Perlstein
8048360efbdSAlfred Perlstein return(_recvmsg(sock, &msg, 0));
8058360efbdSAlfred Perlstein }
8068360efbdSAlfred Perlstein
8078360efbdSAlfred Perlstein static int
__msgwrite(int sock,void * buf,size_t cnt)808587cf682SCraig Rodrigues __msgwrite(int sock, void *buf, size_t cnt)
8098360efbdSAlfred Perlstein {
8108360efbdSAlfred Perlstein struct iovec iov[1];
8118360efbdSAlfred Perlstein struct msghdr msg;
8122bc21ed9SDavid Malone union {
8132bc21ed9SDavid Malone struct cmsghdr cmsg;
8142bc21ed9SDavid Malone char control[CMSG_SPACE(sizeof(struct cmsgcred))];
8152bc21ed9SDavid Malone } cm;
8168360efbdSAlfred Perlstein
8178360efbdSAlfred Perlstein bzero((char *)&cm, sizeof(cm));
8188360efbdSAlfred Perlstein iov[0].iov_base = buf;
8198360efbdSAlfred Perlstein iov[0].iov_len = cnt;
8208360efbdSAlfred Perlstein
8218360efbdSAlfred Perlstein cm.cmsg.cmsg_type = SCM_CREDS;
8228360efbdSAlfred Perlstein cm.cmsg.cmsg_level = SOL_SOCKET;
8232bc21ed9SDavid Malone cm.cmsg.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
8248360efbdSAlfred Perlstein
8258360efbdSAlfred Perlstein msg.msg_iov = iov;
8268360efbdSAlfred Perlstein msg.msg_iovlen = 1;
8278360efbdSAlfred Perlstein msg.msg_name = NULL;
8288360efbdSAlfred Perlstein msg.msg_namelen = 0;
8298360efbdSAlfred Perlstein msg.msg_control = (caddr_t)&cm;
8302bc21ed9SDavid Malone msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
8318360efbdSAlfred Perlstein msg.msg_flags = 0;
8328360efbdSAlfred Perlstein
8338360efbdSAlfred Perlstein return(_sendmsg(sock, &msg, 0));
8348360efbdSAlfred Perlstein }
835