1 1.33 christos /* $NetBSD: clnt_dg.c,v 1.33 2024/01/23 17:24:38 christos Exp $ */ 2 1.1 fvdl 3 1.1 fvdl /* 4 1.28 tron * Copyright (c) 2010, Oracle America, Inc. 5 1.28 tron * 6 1.28 tron * Redistribution and use in source and binary forms, with or without 7 1.28 tron * modification, are permitted provided that the following conditions are 8 1.28 tron * met: 9 1.28 tron * 10 1.28 tron * * Redistributions of source code must retain the above copyright 11 1.28 tron * notice, this list of conditions and the following disclaimer. 12 1.28 tron * * Redistributions in binary form must reproduce the above 13 1.28 tron * copyright notice, this list of conditions and the following 14 1.28 tron * disclaimer in the documentation and/or other materials 15 1.28 tron * provided with the distribution. 16 1.28 tron * * Neither the name of the "Oracle America, Inc." nor the names of its 17 1.28 tron * contributors may be used to endorse or promote products derived 18 1.28 tron * from this software without specific prior written permission. 19 1.28 tron * 20 1.28 tron * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 1.28 tron * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 1.28 tron * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 1.28 tron * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 1.28 tron * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 1.28 tron * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 1.28 tron * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 27 1.28 tron * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 1.28 tron * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 1.28 tron * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 1.28 tron * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 1.28 tron * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 1.1 fvdl */ 33 1.1 fvdl /* 34 1.1 fvdl * Copyright (c) 1986-1991 by Sun Microsystems Inc. 35 1.1 fvdl */ 36 1.1 fvdl 37 1.1 fvdl /* #ident "@(#)clnt_dg.c 1.23 94/04/22 SMI" */ 38 1.1 fvdl 39 1.12 itojun #include <sys/cdefs.h> 40 1.12 itojun #if defined(LIBC_SCCS) && !defined(lint) 41 1.1 fvdl #if 0 42 1.1 fvdl static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 43 1.12 itojun #else 44 1.33 christos __RCSID("$NetBSD: clnt_dg.c,v 1.33 2024/01/23 17:24:38 christos Exp $"); 45 1.1 fvdl #endif 46 1.1 fvdl #endif 47 1.1 fvdl 48 1.1 fvdl /* 49 1.1 fvdl * Implements a connectionless client side RPC. 50 1.1 fvdl */ 51 1.1 fvdl 52 1.1 fvdl #include "namespace.h" 53 1.1 fvdl #include "reentrant.h" 54 1.21 chs #include <sys/poll.h> 55 1.1 fvdl #include <sys/types.h> 56 1.1 fvdl #include <sys/time.h> 57 1.1 fvdl #include <sys/socket.h> 58 1.1 fvdl #include <sys/ioctl.h> 59 1.1 fvdl #include <rpc/rpc.h> 60 1.7 lukem #include <assert.h> 61 1.1 fvdl #include <errno.h> 62 1.1 fvdl #include <stdlib.h> 63 1.2 thorpej #include <string.h> 64 1.1 fvdl #include <signal.h> 65 1.1 fvdl #include <unistd.h> 66 1.1 fvdl #include <err.h> 67 1.27 christos 68 1.27 christos #include "svc_fdset.h" 69 1.8 fvdl #include "rpc_internal.h" 70 1.1 fvdl 71 1.1 fvdl #ifdef __weak_alias 72 1.1 fvdl __weak_alias(clnt_dg_create,_clnt_dg_create) 73 1.1 fvdl #endif 74 1.1 fvdl 75 1.1 fvdl #define RPC_MAX_BACKOFF 30 /* seconds */ 76 1.1 fvdl 77 1.1 fvdl 78 1.26 matt static struct clnt_ops *clnt_dg_ops(void); 79 1.26 matt static bool_t time_not_ok(struct timeval *); 80 1.26 matt static enum clnt_stat clnt_dg_call(CLIENT *, rpcproc_t, xdrproc_t, 81 1.26 matt const char *, xdrproc_t, caddr_t, struct timeval); 82 1.26 matt static void clnt_dg_geterr(CLIENT *, struct rpc_err *); 83 1.26 matt static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, caddr_t); 84 1.26 matt static void clnt_dg_abort(CLIENT *); 85 1.26 matt static bool_t clnt_dg_control(CLIENT *, u_int, char *); 86 1.26 matt static void clnt_dg_destroy(CLIENT *); 87 1.1 fvdl 88 1.1 fvdl 89 1.1 fvdl 90 1.1 fvdl 91 1.1 fvdl /* 92 1.1 fvdl * This machinery implements per-fd locks for MT-safety. It is not 93 1.1 fvdl * sufficient to do per-CLIENT handle locks for MT-safety because a 94 1.1 fvdl * user may create more than one CLIENT handle with the same fd behind 95 1.30 andvar * it. Therefore, we allocate an array of flags (dg_fd_locks), protected 96 1.1 fvdl * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables 97 1.30 andvar * similarly protected. Dg_fd_lock[fd] == 1 => a call is active on some 98 1.1 fvdl * CLIENT handle created for that fd. 99 1.1 fvdl * The current implementation holds locks across the entire RPC and reply, 100 1.1 fvdl * including retransmissions. Yes, this is silly, and as soon as this 101 1.1 fvdl * code is proven to work, this should be the first thing fixed. One step 102 1.1 fvdl * at a time. 103 1.1 fvdl */ 104 1.1 fvdl static int *dg_fd_locks; 105 1.9 thorpej #ifdef _REENTRANT 106 1.9 thorpej #define __rpc_lock_value __isthreaded; 107 1.1 fvdl static cond_t *dg_cv; 108 1.1 fvdl #define release_fd_lock(fd, mask) { \ 109 1.1 fvdl mutex_lock(&clnt_fd_lock); \ 110 1.1 fvdl dg_fd_locks[fd] = 0; \ 111 1.1 fvdl mutex_unlock(&clnt_fd_lock); \ 112 1.22 christos thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \ 113 1.1 fvdl cond_signal(&dg_cv[fd]); \ 114 1.1 fvdl } 115 1.1 fvdl #else 116 1.1 fvdl #define release_fd_lock(fd,mask) 117 1.1 fvdl #define __rpc_lock_value 0 118 1.1 fvdl #endif 119 1.1 fvdl 120 1.1 fvdl static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; 121 1.1 fvdl 122 1.1 fvdl /* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */ 123 1.1 fvdl 124 1.1 fvdl /* 125 1.1 fvdl * Private data kept per client handle 126 1.1 fvdl */ 127 1.1 fvdl struct cu_data { 128 1.1 fvdl int cu_fd; /* connections fd */ 129 1.1 fvdl bool_t cu_closeit; /* opened by library */ 130 1.1 fvdl struct sockaddr_storage cu_raddr; /* remote address */ 131 1.1 fvdl int cu_rlen; 132 1.1 fvdl struct timeval cu_wait; /* retransmit interval */ 133 1.1 fvdl struct timeval cu_total; /* total time for the call */ 134 1.1 fvdl struct rpc_err cu_error; 135 1.1 fvdl XDR cu_outxdrs; 136 1.1 fvdl u_int cu_xdrpos; 137 1.1 fvdl u_int cu_sendsz; /* send size */ 138 1.1 fvdl char *cu_outbuf; 139 1.1 fvdl u_int cu_recvsz; /* recv size */ 140 1.21 chs struct pollfd cu_pfdp; 141 1.1 fvdl char cu_inbuf[1]; 142 1.1 fvdl }; 143 1.1 fvdl 144 1.1 fvdl /* 145 1.1 fvdl * Connection less client creation returns with client handle parameters. 146 1.1 fvdl * Default options are set, which the user can change using clnt_control(). 147 1.1 fvdl * fd should be open and bound. 148 1.1 fvdl * NB: The rpch->cl_auth is initialized to null authentication. 149 1.1 fvdl * Caller may wish to set this something more useful. 150 1.1 fvdl * 151 1.1 fvdl * sendsz and recvsz are the maximum allowable packet sizes that can be 152 1.1 fvdl * sent and received. Normally they are the same, but they can be 153 1.1 fvdl * changed to improve the program efficiency and buffer allocation. 154 1.1 fvdl * If they are 0, use the transport default. 155 1.1 fvdl * 156 1.1 fvdl * If svcaddr is NULL, returns NULL. 157 1.1 fvdl */ 158 1.1 fvdl CLIENT * 159 1.26 matt clnt_dg_create( 160 1.26 matt int fd, /* open file descriptor */ 161 1.26 matt const struct netbuf *svcaddr, /* servers address */ 162 1.26 matt rpcprog_t program, /* program number */ 163 1.26 matt rpcvers_t version, /* version number */ 164 1.26 matt u_int sendsz, /* buffer recv size */ 165 1.26 matt u_int recvsz) /* buffer send size */ 166 1.1 fvdl { 167 1.3 christos CLIENT *cl = NULL; /* client handle */ 168 1.3 christos struct cu_data *cu = NULL; /* private data */ 169 1.1 fvdl struct rpc_msg call_msg; 170 1.9 thorpej #ifdef _REENTRANT 171 1.1 fvdl sigset_t mask; 172 1.1 fvdl #endif 173 1.1 fvdl sigset_t newmask; 174 1.1 fvdl struct __rpc_sockinfo si; 175 1.1 fvdl int one = 1; 176 1.1 fvdl 177 1.29 christos __clnt_sigfillset(&newmask); 178 1.1 fvdl thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 179 1.1 fvdl mutex_lock(&clnt_fd_lock); 180 1.22 christos if (dg_fd_locks == NULL) { 181 1.9 thorpej #ifdef _REENTRANT 182 1.9 thorpej size_t cv_allocsz; 183 1.1 fvdl #endif 184 1.3 christos size_t fd_allocsz; 185 1.1 fvdl int dtbsize = __rpc_dtbsize(); 186 1.1 fvdl 187 1.1 fvdl fd_allocsz = dtbsize * sizeof (int); 188 1.22 christos dg_fd_locks = mem_alloc(fd_allocsz); 189 1.22 christos if (dg_fd_locks == NULL) { 190 1.29 christos goto err0; 191 1.1 fvdl } else 192 1.1 fvdl memset(dg_fd_locks, '\0', fd_allocsz); 193 1.1 fvdl 194 1.9 thorpej #ifdef _REENTRANT 195 1.1 fvdl cv_allocsz = dtbsize * sizeof (cond_t); 196 1.22 christos dg_cv = mem_alloc(cv_allocsz); 197 1.22 christos if (dg_cv == NULL) { 198 1.1 fvdl mem_free(dg_fd_locks, fd_allocsz); 199 1.22 christos dg_fd_locks = NULL; 200 1.29 christos goto err0; 201 1.1 fvdl } else { 202 1.1 fvdl int i; 203 1.1 fvdl 204 1.1 fvdl for (i = 0; i < dtbsize; i++) 205 1.1 fvdl cond_init(&dg_cv[i], 0, (void *) 0); 206 1.1 fvdl } 207 1.1 fvdl #endif 208 1.1 fvdl } 209 1.1 fvdl 210 1.1 fvdl mutex_unlock(&clnt_fd_lock); 211 1.1 fvdl thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 212 1.1 fvdl 213 1.3 christos if (svcaddr == NULL) { 214 1.1 fvdl rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 215 1.3 christos return (NULL); 216 1.1 fvdl } 217 1.1 fvdl 218 1.1 fvdl if (!__rpc_fd2sockinfo(fd, &si)) { 219 1.1 fvdl rpc_createerr.cf_stat = RPC_TLIERROR; 220 1.1 fvdl rpc_createerr.cf_error.re_errno = 0; 221 1.3 christos return (NULL); 222 1.1 fvdl } 223 1.1 fvdl /* 224 1.1 fvdl * Find the receive and the send size 225 1.1 fvdl */ 226 1.1 fvdl sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 227 1.1 fvdl recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 228 1.1 fvdl if ((sendsz == 0) || (recvsz == 0)) { 229 1.1 fvdl rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ 230 1.1 fvdl rpc_createerr.cf_error.re_errno = 0; 231 1.3 christos return (NULL); 232 1.1 fvdl } 233 1.1 fvdl 234 1.3 christos if ((cl = mem_alloc(sizeof (CLIENT))) == NULL) 235 1.1 fvdl goto err1; 236 1.1 fvdl /* 237 1.1 fvdl * Should be multiple of 4 for XDR. 238 1.1 fvdl */ 239 1.1 fvdl sendsz = ((sendsz + 3) / 4) * 4; 240 1.1 fvdl recvsz = ((recvsz + 3) / 4) * 4; 241 1.15 yamt cu = malloc(sizeof (*cu) + sendsz + recvsz); 242 1.3 christos if (cu == NULL) 243 1.1 fvdl goto err1; 244 1.15 yamt memset(cu, 0, sizeof(*cu)); 245 1.3 christos (void) memcpy(&cu->cu_raddr, svcaddr->buf, (size_t)svcaddr->len); 246 1.1 fvdl cu->cu_rlen = svcaddr->len; 247 1.1 fvdl cu->cu_outbuf = &cu->cu_inbuf[recvsz]; 248 1.1 fvdl /* Other values can also be set through clnt_control() */ 249 1.27 christos #ifdef RUMP_RPC 250 1.1 fvdl cu->cu_wait.tv_sec = 15; /* heuristically chosen */ 251 1.1 fvdl cu->cu_wait.tv_usec = 0; 252 1.27 christos #else 253 1.27 christos cu->cu_wait.tv_sec = 0; /* for testing, 10x / second */ 254 1.27 christos cu->cu_wait.tv_usec = 100000; 255 1.27 christos #endif 256 1.1 fvdl cu->cu_total.tv_sec = -1; 257 1.1 fvdl cu->cu_total.tv_usec = -1; 258 1.1 fvdl cu->cu_sendsz = sendsz; 259 1.1 fvdl cu->cu_recvsz = recvsz; 260 1.11 itojun call_msg.rm_xid = __RPC_GETXID(); 261 1.1 fvdl call_msg.rm_call.cb_prog = program; 262 1.1 fvdl call_msg.rm_call.cb_vers = version; 263 1.1 fvdl xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); 264 1.1 fvdl if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { 265 1.1 fvdl rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ 266 1.1 fvdl rpc_createerr.cf_error.re_errno = 0; 267 1.1 fvdl goto err2; 268 1.1 fvdl } 269 1.1 fvdl cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); 270 1.1 fvdl 271 1.1 fvdl /* XXX fvdl - do we still want this? */ 272 1.1 fvdl #if 0 273 1.1 fvdl (void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf); 274 1.1 fvdl #endif 275 1.1 fvdl ioctl(fd, FIONBIO, (char *)(void *)&one); 276 1.1 fvdl 277 1.1 fvdl /* 278 1.1 fvdl * By default, closeit is always FALSE. It is users responsibility 279 1.1 fvdl * to do a close on it, else the user may use clnt_control 280 1.1 fvdl * to let clnt_destroy do it for him/her. 281 1.1 fvdl */ 282 1.1 fvdl cu->cu_closeit = FALSE; 283 1.1 fvdl cu->cu_fd = fd; 284 1.21 chs cu->cu_pfdp.fd = cu->cu_fd; 285 1.21 chs cu->cu_pfdp.events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND; 286 1.1 fvdl cl->cl_ops = clnt_dg_ops(); 287 1.3 christos cl->cl_private = (caddr_t)(void *)cu; 288 1.1 fvdl cl->cl_auth = authnone_create(); 289 1.3 christos cl->cl_tp = NULL; 290 1.3 christos cl->cl_netid = NULL; 291 1.1 fvdl return (cl); 292 1.29 christos err0: 293 1.29 christos mutex_unlock(&clnt_fd_lock); 294 1.29 christos thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 295 1.1 fvdl err1: 296 1.1 fvdl warnx(mem_err_clnt_dg); 297 1.1 fvdl rpc_createerr.cf_stat = RPC_SYSTEMERROR; 298 1.1 fvdl rpc_createerr.cf_error.re_errno = errno; 299 1.1 fvdl err2: 300 1.1 fvdl if (cl) { 301 1.3 christos mem_free(cl, sizeof (CLIENT)); 302 1.1 fvdl if (cu) 303 1.3 christos mem_free(cu, sizeof (*cu) + sendsz + recvsz); 304 1.1 fvdl } 305 1.3 christos return (NULL); 306 1.1 fvdl } 307 1.1 fvdl 308 1.1 fvdl static enum clnt_stat 309 1.26 matt clnt_dg_call( 310 1.26 matt CLIENT * cl, /* client handle */ 311 1.26 matt rpcproc_t proc, /* procedure number */ 312 1.26 matt xdrproc_t xargs, /* xdr routine for args */ 313 1.26 matt const char * argsp, /* pointer to args */ 314 1.26 matt xdrproc_t xresults, /* xdr routine for results */ 315 1.26 matt caddr_t resultsp, /* pointer to results */ 316 1.26 matt struct timeval utimeout) /* seconds to wait before giving up */ 317 1.1 fvdl { 318 1.7 lukem struct cu_data *cu; 319 1.3 christos XDR *xdrs; 320 1.3 christos size_t outlen; 321 1.1 fvdl struct rpc_msg reply_msg; 322 1.1 fvdl XDR reply_xdrs; 323 1.1 fvdl bool_t ok; 324 1.1 fvdl int nrefreshes = 2; /* number of times to refresh cred */ 325 1.1 fvdl struct timeval timeout; 326 1.1 fvdl struct timeval retransmit_time; 327 1.18 rpaulo struct timeval next_sendtime, starttime, time_waited, tv; 328 1.9 thorpej #ifdef _REENTRANT 329 1.21 chs sigset_t mask, *maskp = &mask; 330 1.21 chs #else 331 1.21 chs sigset_t *maskp = NULL; 332 1.1 fvdl #endif 333 1.1 fvdl sigset_t newmask; 334 1.3 christos ssize_t recvlen = 0; 335 1.16 christos struct timespec ts; 336 1.18 rpaulo int n; 337 1.1 fvdl 338 1.7 lukem _DIAGASSERT(cl != NULL); 339 1.7 lukem 340 1.7 lukem cu = (struct cu_data *)cl->cl_private; 341 1.7 lukem 342 1.29 christos __clnt_sigfillset(&newmask); 343 1.1 fvdl thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 344 1.1 fvdl mutex_lock(&clnt_fd_lock); 345 1.1 fvdl while (dg_fd_locks[cu->cu_fd]) 346 1.1 fvdl cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 347 1.1 fvdl dg_fd_locks[cu->cu_fd] = __rpc_lock_value; 348 1.1 fvdl mutex_unlock(&clnt_fd_lock); 349 1.1 fvdl if (cu->cu_total.tv_usec == -1) { 350 1.1 fvdl timeout = utimeout; /* use supplied timeout */ 351 1.1 fvdl } else { 352 1.1 fvdl timeout = cu->cu_total; /* use default timeout */ 353 1.1 fvdl } 354 1.1 fvdl 355 1.1 fvdl time_waited.tv_sec = 0; 356 1.1 fvdl time_waited.tv_usec = 0; 357 1.18 rpaulo retransmit_time = next_sendtime = cu->cu_wait; 358 1.18 rpaulo gettimeofday(&starttime, NULL); 359 1.18 rpaulo 360 1.1 fvdl call_again: 361 1.1 fvdl xdrs = &(cu->cu_outxdrs); 362 1.1 fvdl xdrs->x_op = XDR_ENCODE; 363 1.1 fvdl XDR_SETPOS(xdrs, cu->cu_xdrpos); 364 1.1 fvdl /* 365 1.1 fvdl * the transaction is the first thing in the out buffer 366 1.1 fvdl */ 367 1.3 christos (*(u_int32_t *)(void *)(cu->cu_outbuf))++; 368 1.6 christos if ((! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 369 1.1 fvdl (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || 370 1.20 yamt (! (*xargs)(xdrs, __UNCONST(argsp)))) { 371 1.18 rpaulo cu->cu_error.re_status = RPC_CANTENCODEARGS; 372 1.18 rpaulo goto out; 373 1.1 fvdl } 374 1.3 christos outlen = (size_t)XDR_GETPOS(xdrs); 375 1.1 fvdl 376 1.1 fvdl send_again: 377 1.23 lukem if ((size_t)sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0, 378 1.3 christos (struct sockaddr *)(void *)&cu->cu_raddr, (socklen_t)cu->cu_rlen) 379 1.1 fvdl != outlen) { 380 1.1 fvdl cu->cu_error.re_errno = errno; 381 1.18 rpaulo cu->cu_error.re_status = RPC_CANTSEND; 382 1.18 rpaulo goto out; 383 1.1 fvdl } 384 1.1 fvdl 385 1.1 fvdl /* 386 1.1 fvdl * Hack to provide rpc-based message passing 387 1.1 fvdl */ 388 1.1 fvdl if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 389 1.18 rpaulo cu->cu_error.re_status = RPC_TIMEDOUT; 390 1.18 rpaulo goto out; 391 1.1 fvdl } 392 1.1 fvdl /* 393 1.1 fvdl * sub-optimal code appears here because we have 394 1.1 fvdl * some clock time to spare while the packets are in flight. 395 1.1 fvdl * (We assume that this is actually only executed once.) 396 1.1 fvdl */ 397 1.1 fvdl reply_msg.acpted_rply.ar_verf = _null_auth; 398 1.1 fvdl reply_msg.acpted_rply.ar_results.where = resultsp; 399 1.1 fvdl reply_msg.acpted_rply.ar_results.proc = xresults; 400 1.1 fvdl 401 1.1 fvdl 402 1.1 fvdl for (;;) { 403 1.18 rpaulo /* Decide how long to wait. */ 404 1.18 rpaulo if (timercmp(&next_sendtime, &timeout, <)) 405 1.18 rpaulo timersub(&next_sendtime, &time_waited, &tv); 406 1.18 rpaulo else 407 1.18 rpaulo timersub(&timeout, &time_waited, &tv); 408 1.18 rpaulo if (tv.tv_sec < 0 || tv.tv_usec < 0) 409 1.18 rpaulo tv.tv_sec = tv.tv_usec = 0; 410 1.18 rpaulo TIMEVAL_TO_TIMESPEC(&tv, &ts); 411 1.18 rpaulo 412 1.21 chs n = pollts(&cu->cu_pfdp, 1, &ts, maskp); 413 1.18 rpaulo if (n == 1) { 414 1.18 rpaulo /* We have some data now */ 415 1.18 rpaulo do { 416 1.18 rpaulo recvlen = recvfrom(cu->cu_fd, cu->cu_inbuf, 417 1.18 rpaulo cu->cu_recvsz, 0, NULL, NULL); 418 1.18 rpaulo } while (recvlen < 0 && errno == EINTR); 419 1.18 rpaulo 420 1.18 rpaulo if (recvlen < 0 && errno != EWOULDBLOCK) { 421 1.1 fvdl cu->cu_error.re_errno = errno; 422 1.18 rpaulo cu->cu_error.re_status = RPC_CANTRECV; 423 1.18 rpaulo goto out; 424 1.1 fvdl } 425 1.25 mrg if (recvlen >= (ssize_t)sizeof(uint32_t)) { 426 1.25 mrg if (memcmp(cu->cu_inbuf, cu->cu_outbuf, 427 1.25 mrg sizeof(uint32_t)) == 0) 428 1.25 mrg /* Assume we have the proper reply. */ 429 1.25 mrg break; 430 1.25 mrg } 431 1.18 rpaulo } 432 1.18 rpaulo if (n == -1) { 433 1.19 christos cu->cu_error.re_errno = errno; 434 1.19 christos cu->cu_error.re_status = RPC_CANTRECV; 435 1.19 christos goto out; 436 1.1 fvdl } 437 1.1 fvdl 438 1.18 rpaulo gettimeofday(&tv, NULL); 439 1.18 rpaulo timersub(&tv, &starttime, &time_waited); 440 1.18 rpaulo 441 1.18 rpaulo /* Check for timeout. */ 442 1.18 rpaulo if (timercmp(&time_waited, &timeout, >)) { 443 1.18 rpaulo cu->cu_error.re_status = RPC_TIMEDOUT; 444 1.18 rpaulo goto out; 445 1.18 rpaulo } 446 1.18 rpaulo 447 1.18 rpaulo /* Retransmit if necessary. */ 448 1.18 rpaulo if (timercmp(&time_waited, &next_sendtime, >)) { 449 1.18 rpaulo /* update retransmit_time */ 450 1.18 rpaulo if (retransmit_time.tv_sec < RPC_MAX_BACKOFF) 451 1.18 rpaulo timeradd(&retransmit_time, &retransmit_time, 452 1.18 rpaulo &retransmit_time); 453 1.18 rpaulo timeradd(&next_sendtime, &retransmit_time, 454 1.18 rpaulo &next_sendtime); 455 1.18 rpaulo goto send_again; 456 1.1 fvdl } 457 1.1 fvdl } 458 1.1 fvdl 459 1.1 fvdl /* 460 1.1 fvdl * now decode and validate the response 461 1.1 fvdl */ 462 1.1 fvdl 463 1.13 drochner xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)recvlen, XDR_DECODE); 464 1.1 fvdl ok = xdr_replymsg(&reply_xdrs, &reply_msg); 465 1.1 fvdl /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ 466 1.1 fvdl if (ok) { 467 1.1 fvdl if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 468 1.1 fvdl (reply_msg.acpted_rply.ar_stat == SUCCESS)) 469 1.1 fvdl cu->cu_error.re_status = RPC_SUCCESS; 470 1.1 fvdl else 471 1.1 fvdl _seterr_reply(&reply_msg, &(cu->cu_error)); 472 1.1 fvdl 473 1.1 fvdl if (cu->cu_error.re_status == RPC_SUCCESS) { 474 1.1 fvdl if (! AUTH_VALIDATE(cl->cl_auth, 475 1.1 fvdl &reply_msg.acpted_rply.ar_verf)) { 476 1.1 fvdl cu->cu_error.re_status = RPC_AUTHERROR; 477 1.1 fvdl cu->cu_error.re_why = AUTH_INVALIDRESP; 478 1.1 fvdl } 479 1.1 fvdl if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 480 1.1 fvdl xdrs->x_op = XDR_FREE; 481 1.1 fvdl (void) xdr_opaque_auth(xdrs, 482 1.1 fvdl &(reply_msg.acpted_rply.ar_verf)); 483 1.1 fvdl } 484 1.1 fvdl } /* end successful completion */ 485 1.1 fvdl /* 486 1.31 msaitoh * If unsuccessful AND error is an authentication error 487 1.1 fvdl * then refresh credentials and try again, else break 488 1.1 fvdl */ 489 1.1 fvdl else if (cu->cu_error.re_status == RPC_AUTHERROR) 490 1.1 fvdl /* maybe our credentials need to be refreshed ... */ 491 1.1 fvdl if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) { 492 1.1 fvdl nrefreshes--; 493 1.1 fvdl goto call_again; 494 1.1 fvdl } 495 1.1 fvdl /* end of unsuccessful completion */ 496 1.1 fvdl } /* end of valid reply message */ 497 1.1 fvdl else { 498 1.1 fvdl cu->cu_error.re_status = RPC_CANTDECODERES; 499 1.1 fvdl 500 1.1 fvdl } 501 1.18 rpaulo out: 502 1.1 fvdl release_fd_lock(cu->cu_fd, mask); 503 1.1 fvdl return (cu->cu_error.re_status); 504 1.1 fvdl } 505 1.1 fvdl 506 1.1 fvdl static void 507 1.26 matt clnt_dg_geterr(CLIENT *cl, struct rpc_err *errp) 508 1.1 fvdl { 509 1.7 lukem struct cu_data *cu; 510 1.1 fvdl 511 1.7 lukem _DIAGASSERT(cl != NULL); 512 1.7 lukem _DIAGASSERT(errp != NULL); 513 1.7 lukem 514 1.7 lukem cu = (struct cu_data *)cl->cl_private; 515 1.1 fvdl *errp = cu->cu_error; 516 1.1 fvdl } 517 1.1 fvdl 518 1.1 fvdl static bool_t 519 1.26 matt clnt_dg_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) 520 1.1 fvdl { 521 1.7 lukem struct cu_data *cu; 522 1.7 lukem XDR *xdrs; 523 1.1 fvdl bool_t dummy; 524 1.9 thorpej #ifdef _REENTRANT 525 1.1 fvdl sigset_t mask; 526 1.1 fvdl #endif 527 1.1 fvdl sigset_t newmask; 528 1.1 fvdl 529 1.7 lukem _DIAGASSERT(cl != NULL); 530 1.7 lukem cu = (struct cu_data *)cl->cl_private; 531 1.7 lukem xdrs = &(cu->cu_outxdrs); 532 1.7 lukem 533 1.29 christos __clnt_sigfillset(&newmask); 534 1.1 fvdl thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 535 1.1 fvdl mutex_lock(&clnt_fd_lock); 536 1.1 fvdl while (dg_fd_locks[cu->cu_fd]) 537 1.1 fvdl cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 538 1.1 fvdl xdrs->x_op = XDR_FREE; 539 1.1 fvdl dummy = (*xdr_res)(xdrs, res_ptr); 540 1.1 fvdl mutex_unlock(&clnt_fd_lock); 541 1.1 fvdl thr_sigsetmask(SIG_SETMASK, &mask, NULL); 542 1.1 fvdl cond_signal(&dg_cv[cu->cu_fd]); 543 1.1 fvdl return (dummy); 544 1.1 fvdl } 545 1.1 fvdl 546 1.1 fvdl /*ARGSUSED*/ 547 1.1 fvdl static void 548 1.26 matt clnt_dg_abort(CLIENT *h) 549 1.1 fvdl { 550 1.1 fvdl } 551 1.1 fvdl 552 1.1 fvdl static bool_t 553 1.26 matt clnt_dg_control(CLIENT *cl, u_int request, char *info) 554 1.1 fvdl { 555 1.7 lukem struct cu_data *cu; 556 1.1 fvdl struct netbuf *addr; 557 1.9 thorpej #ifdef _REENTRANT 558 1.1 fvdl sigset_t mask; 559 1.1 fvdl #endif 560 1.1 fvdl sigset_t newmask; 561 1.1 fvdl 562 1.7 lukem _DIAGASSERT(cl != NULL); 563 1.7 lukem /* info is handled below */ 564 1.7 lukem 565 1.7 lukem cu = (struct cu_data *)cl->cl_private; 566 1.7 lukem 567 1.29 christos __clnt_sigfillset(&newmask); 568 1.1 fvdl thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 569 1.1 fvdl mutex_lock(&clnt_fd_lock); 570 1.1 fvdl while (dg_fd_locks[cu->cu_fd]) 571 1.1 fvdl cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 572 1.1 fvdl dg_fd_locks[cu->cu_fd] = __rpc_lock_value; 573 1.1 fvdl mutex_unlock(&clnt_fd_lock); 574 1.1 fvdl switch (request) { 575 1.1 fvdl case CLSET_FD_CLOSE: 576 1.1 fvdl cu->cu_closeit = TRUE; 577 1.1 fvdl release_fd_lock(cu->cu_fd, mask); 578 1.1 fvdl return (TRUE); 579 1.1 fvdl case CLSET_FD_NCLOSE: 580 1.1 fvdl cu->cu_closeit = FALSE; 581 1.1 fvdl release_fd_lock(cu->cu_fd, mask); 582 1.1 fvdl return (TRUE); 583 1.1 fvdl } 584 1.1 fvdl 585 1.1 fvdl /* for other requests which use info */ 586 1.1 fvdl if (info == NULL) { 587 1.1 fvdl release_fd_lock(cu->cu_fd, mask); 588 1.1 fvdl return (FALSE); 589 1.1 fvdl } 590 1.1 fvdl switch (request) { 591 1.1 fvdl case CLSET_TIMEOUT: 592 1.3 christos if (time_not_ok((struct timeval *)(void *)info)) { 593 1.1 fvdl release_fd_lock(cu->cu_fd, mask); 594 1.1 fvdl return (FALSE); 595 1.1 fvdl } 596 1.3 christos cu->cu_total = *(struct timeval *)(void *)info; 597 1.1 fvdl break; 598 1.1 fvdl case CLGET_TIMEOUT: 599 1.3 christos *(struct timeval *)(void *)info = cu->cu_total; 600 1.1 fvdl break; 601 1.1 fvdl case CLGET_SERVER_ADDR: /* Give him the fd address */ 602 1.1 fvdl /* Now obsolete. Only for backward compatibility */ 603 1.3 christos (void) memcpy(info, &cu->cu_raddr, (size_t)cu->cu_rlen); 604 1.1 fvdl break; 605 1.1 fvdl case CLSET_RETRY_TIMEOUT: 606 1.3 christos if (time_not_ok((struct timeval *)(void *)info)) { 607 1.1 fvdl release_fd_lock(cu->cu_fd, mask); 608 1.1 fvdl return (FALSE); 609 1.1 fvdl } 610 1.3 christos cu->cu_wait = *(struct timeval *)(void *)info; 611 1.1 fvdl break; 612 1.1 fvdl case CLGET_RETRY_TIMEOUT: 613 1.3 christos *(struct timeval *)(void *)info = cu->cu_wait; 614 1.1 fvdl break; 615 1.1 fvdl case CLGET_FD: 616 1.3 christos *(int *)(void *)info = cu->cu_fd; 617 1.1 fvdl break; 618 1.1 fvdl case CLGET_SVC_ADDR: 619 1.3 christos addr = (struct netbuf *)(void *)info; 620 1.1 fvdl addr->buf = &cu->cu_raddr; 621 1.1 fvdl addr->len = cu->cu_rlen; 622 1.1 fvdl addr->maxlen = sizeof cu->cu_raddr; 623 1.1 fvdl break; 624 1.1 fvdl case CLSET_SVC_ADDR: /* set to new address */ 625 1.3 christos addr = (struct netbuf *)(void *)info; 626 1.10 yamt if (addr->len < sizeof cu->cu_raddr) { 627 1.10 yamt release_fd_lock(cu->cu_fd, mask); 628 1.1 fvdl return (FALSE); 629 1.10 yamt } 630 1.14 christos (void) memcpy(&cu->cu_raddr, addr->buf, (size_t)addr->len); 631 1.1 fvdl cu->cu_rlen = addr->len; 632 1.1 fvdl break; 633 1.1 fvdl case CLGET_XID: 634 1.1 fvdl /* 635 1.1 fvdl * use the knowledge that xid is the 636 1.1 fvdl * first element in the call structure *. 637 1.1 fvdl * This will get the xid of the PREVIOUS call 638 1.1 fvdl */ 639 1.3 christos *(u_int32_t *)(void *)info = 640 1.3 christos ntohl(*(u_int32_t *)(void *)cu->cu_outbuf); 641 1.1 fvdl break; 642 1.1 fvdl 643 1.1 fvdl case CLSET_XID: 644 1.1 fvdl /* This will set the xid of the NEXT call */ 645 1.3 christos *(u_int32_t *)(void *)cu->cu_outbuf = 646 1.3 christos htonl(*(u_int32_t *)(void *)info - 1); 647 1.1 fvdl /* decrement by 1 as clnt_dg_call() increments once */ 648 1.1 fvdl break; 649 1.1 fvdl 650 1.1 fvdl case CLGET_VERS: 651 1.1 fvdl /* 652 1.1 fvdl * This RELIES on the information that, in the call body, 653 1.1 fvdl * the version number field is the fifth field from the 654 1.32 andvar * beginning of the RPC header. MUST be changed if the 655 1.1 fvdl * call_struct is changed 656 1.1 fvdl */ 657 1.3 christos *(u_int32_t *)(void *)info = 658 1.3 christos ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + 659 1.3 christos 4 * BYTES_PER_XDR_UNIT)); 660 1.1 fvdl break; 661 1.1 fvdl 662 1.1 fvdl case CLSET_VERS: 663 1.3 christos *(u_int32_t *)(void *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT) 664 1.3 christos = htonl(*(u_int32_t *)(void *)info); 665 1.1 fvdl break; 666 1.1 fvdl 667 1.1 fvdl case CLGET_PROG: 668 1.1 fvdl /* 669 1.1 fvdl * This RELIES on the information that, in the call body, 670 1.1 fvdl * the program number field is the fourth field from the 671 1.32 andvar * beginning of the RPC header. MUST be changed if the 672 1.1 fvdl * call_struct is changed 673 1.1 fvdl */ 674 1.3 christos *(u_int32_t *)(void *)info = 675 1.3 christos ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + 676 1.3 christos 3 * BYTES_PER_XDR_UNIT)); 677 1.1 fvdl break; 678 1.1 fvdl 679 1.1 fvdl case CLSET_PROG: 680 1.3 christos *(u_int32_t *)(void *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT) 681 1.3 christos = htonl(*(u_int32_t *)(void *)info); 682 1.1 fvdl break; 683 1.1 fvdl 684 1.1 fvdl default: 685 1.1 fvdl release_fd_lock(cu->cu_fd, mask); 686 1.1 fvdl return (FALSE); 687 1.1 fvdl } 688 1.1 fvdl release_fd_lock(cu->cu_fd, mask); 689 1.1 fvdl return (TRUE); 690 1.1 fvdl } 691 1.1 fvdl 692 1.1 fvdl static void 693 1.26 matt clnt_dg_destroy(CLIENT *cl) 694 1.1 fvdl { 695 1.7 lukem struct cu_data *cu; 696 1.7 lukem int cu_fd; 697 1.9 thorpej #ifdef _REENTRANT 698 1.1 fvdl sigset_t mask; 699 1.1 fvdl #endif 700 1.1 fvdl sigset_t newmask; 701 1.1 fvdl 702 1.7 lukem _DIAGASSERT(cl != NULL); 703 1.7 lukem 704 1.7 lukem cu = (struct cu_data *)cl->cl_private; 705 1.7 lukem cu_fd = cu->cu_fd; 706 1.7 lukem 707 1.29 christos __clnt_sigfillset(&newmask); 708 1.1 fvdl thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 709 1.1 fvdl mutex_lock(&clnt_fd_lock); 710 1.1 fvdl while (dg_fd_locks[cu_fd]) 711 1.1 fvdl cond_wait(&dg_cv[cu_fd], &clnt_fd_lock); 712 1.1 fvdl if (cu->cu_closeit) 713 1.1 fvdl (void) close(cu_fd); 714 1.1 fvdl XDR_DESTROY(&(cu->cu_outxdrs)); 715 1.3 christos mem_free(cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz)); 716 1.1 fvdl if (cl->cl_netid && cl->cl_netid[0]) 717 1.1 fvdl mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 718 1.1 fvdl if (cl->cl_tp && cl->cl_tp[0]) 719 1.1 fvdl mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 720 1.3 christos mem_free(cl, sizeof (CLIENT)); 721 1.1 fvdl mutex_unlock(&clnt_fd_lock); 722 1.1 fvdl thr_sigsetmask(SIG_SETMASK, &mask, NULL); 723 1.1 fvdl cond_signal(&dg_cv[cu_fd]); 724 1.1 fvdl } 725 1.1 fvdl 726 1.1 fvdl static struct clnt_ops * 727 1.26 matt clnt_dg_ops(void) 728 1.1 fvdl { 729 1.1 fvdl static struct clnt_ops ops; 730 1.9 thorpej #ifdef _REENTRANT 731 1.1 fvdl sigset_t mask; 732 1.1 fvdl #endif 733 1.1 fvdl sigset_t newmask; 734 1.1 fvdl 735 1.1 fvdl /* VARIABLES PROTECTED BY ops_lock: ops */ 736 1.1 fvdl 737 1.29 christos __clnt_sigfillset(&newmask); 738 1.1 fvdl thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 739 1.1 fvdl mutex_lock(&ops_lock); 740 1.1 fvdl if (ops.cl_call == NULL) { 741 1.1 fvdl ops.cl_call = clnt_dg_call; 742 1.1 fvdl ops.cl_abort = clnt_dg_abort; 743 1.1 fvdl ops.cl_geterr = clnt_dg_geterr; 744 1.1 fvdl ops.cl_freeres = clnt_dg_freeres; 745 1.1 fvdl ops.cl_destroy = clnt_dg_destroy; 746 1.1 fvdl ops.cl_control = clnt_dg_control; 747 1.1 fvdl } 748 1.1 fvdl mutex_unlock(&ops_lock); 749 1.1 fvdl thr_sigsetmask(SIG_SETMASK, &mask, NULL); 750 1.1 fvdl return (&ops); 751 1.1 fvdl } 752 1.1 fvdl 753 1.1 fvdl /* 754 1.1 fvdl * Make sure that the time is not garbage. -1 value is allowed. 755 1.1 fvdl */ 756 1.1 fvdl static bool_t 757 1.26 matt time_not_ok(struct timeval *t) 758 1.1 fvdl { 759 1.7 lukem 760 1.7 lukem _DIAGASSERT(t != NULL); 761 1.7 lukem 762 1.1 fvdl return (t->tv_sec < -1 || t->tv_sec > 100000000 || 763 1.1 fvdl t->tv_usec < -1 || t->tv_usec > 1000000); 764 1.1 fvdl } 765