clnt_dg.c revision 167199
1127668Sbms/* $NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl Exp $ */ 256893Sfenner 356893Sfenner/* 456893Sfenner * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 575115Sfenner * unrestricted use provided that this legend is included on all tape 656893Sfenner * media and as a part of the software program in whole or part. Users 756893Sfenner * may copy or modify Sun RPC without charge, but are not authorized 856893Sfenner * to license or distribute it to anyone else except as part of a product or 956893Sfenner * program developed by the user. 1056893Sfenner * 1156893Sfenner * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 1256893Sfenner * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 1356893Sfenner * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 1456893Sfenner * 1556893Sfenner * Sun RPC is provided with no support and without any obligation on the 1656893Sfenner * part of Sun Microsystems, Inc. to assist in its use, correction, 1756893Sfenner * modification or enhancement. 1856893Sfenner * 1956893Sfenner * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 2056893Sfenner * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 2156893Sfenner * OR ANY PART THEREOF. 2256893Sfenner * 23127668Sbms * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24127668Sbms * or profits or other special, indirect and consequential damages, even if 25127668Sbms * Sun has been advised of the possibility of such damages. 2698524Sfenner * 2798524Sfenner * Sun Microsystems, Inc. 2875115Sfenner * 2550 Garcia Avenue 29127668Sbms * Mountain View, California 94043 30127668Sbms */ 31127668Sbms/* 32127668Sbms * Copyright (c) 1986-1991 by Sun Microsystems Inc. 33127668Sbms */ 34127668Sbms 35127668Sbms#if defined(LIBC_SCCS) && !defined(lint) 36127668Sbms#ident "@(#)clnt_dg.c 1.23 94/04/22 SMI" 37127668Sbmsstatic char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 38127668Sbms#endif 39127668Sbms#include <sys/cdefs.h> 40127668Sbms__FBSDID("$FreeBSD: head/lib/libc/rpc/clnt_dg.c 167199 2007-03-04 12:25:03Z simon $"); 41127668Sbms 42127668Sbms/* 43127668Sbms * Implements a connectionless client side RPC. 44127668Sbms */ 45127668Sbms 46127668Sbms#include "namespace.h" 47127668Sbms#include "reentrant.h" 48127668Sbms#include <sys/types.h> 49127668Sbms#include <sys/event.h> 50147899Ssam#include <sys/time.h> 51147899Ssam#include <sys/socket.h> 52147899Ssam#include <sys/ioctl.h> 53146773Ssam#include <arpa/inet.h> 54146773Ssam#include <rpc/rpc.h> 55146773Ssam#include <errno.h> 56146773Ssam#include <stdlib.h> 57146773Ssam#include <string.h> 58146773Ssam#include <signal.h> 59146773Ssam#include <unistd.h> 60146773Ssam#include <err.h> 61146773Ssam#include "un-namespace.h" 6298524Sfenner#include "rpc_com.h" 6398524Sfenner#include "mt_misc.h" 6498524Sfenner 65127668Sbms 66127668Sbms#ifdef _FREEFALL_CONFIG 6756893Sfenner/* 68127668Sbms * Disable RPC exponential back-off for FreeBSD.org systems. 69127668Sbms */ 7056893Sfenner#define RPC_MAX_BACKOFF 1 /* second */ 71146773Ssam#else 72146773Ssam#define RPC_MAX_BACKOFF 30 /* seconds */ 73146773Ssam#endif 74146773Ssam 75146773Ssam 76146773Ssamstatic struct clnt_ops *clnt_dg_ops(void); 77146773Ssamstatic bool_t time_not_ok(struct timeval *); 78146773Ssamstatic enum clnt_stat clnt_dg_call(CLIENT *, rpcproc_t, xdrproc_t, void *, 79146773Ssam xdrproc_t, void *, struct timeval); 80127668Sbmsstatic void clnt_dg_geterr(CLIENT *, struct rpc_err *); 8175115Sfennerstatic bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, void *); 8275115Sfennerstatic void clnt_dg_abort(CLIENT *); 83146773Ssamstatic bool_t clnt_dg_control(CLIENT *, u_int, void *); 84146773Ssamstatic void clnt_dg_destroy(CLIENT *); 85146773Ssam 86146773Ssam 87127668Sbms 8856893Sfenner 8956893Sfenner/* 90127668Sbms * This machinery implements per-fd locks for MT-safety. It is not 91127668Sbms * sufficient to do per-CLIENT handle locks for MT-safety because a 92127668Sbms * user may create more than one CLIENT handle with the same fd behind 93235530Sdelphij * it. Therfore, we allocate an array of flags (dg_fd_locks), protected 94235530Sdelphij * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables 95235530Sdelphij * similarly protected. Dg_fd_lock[fd] == 1 => a call is activte on some 96127668Sbms * CLIENT handle created for that fd. 9756893Sfenner * The current implementation holds locks across the entire RPC and reply, 9856893Sfenner * including retransmissions. Yes, this is silly, and as soon as this 99127668Sbms * code is proven to work, this should be the first thing fixed. One step 100127668Sbms * at a time. 10156893Sfenner */ 102127668Sbmsstatic int *dg_fd_locks; 103127668Sbmsstatic cond_t *dg_cv; 10456893Sfenner#define release_fd_lock(fd, mask) { \ 105127668Sbms mutex_lock(&clnt_fd_lock); \ 106127668Sbms dg_fd_locks[fd] = 0; \ 10756893Sfenner mutex_unlock(&clnt_fd_lock); \ 108127668Sbms thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \ 109127668Sbms cond_signal(&dg_cv[fd]); \ 110127668Sbms} 111127668Sbms 112127668Sbmsstatic const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; 113127668Sbms 114127668Sbms/* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */ 115127668Sbms 116127668Sbms/* 117127668Sbms * Private data kept per client handle 118127668Sbms */ 119127668Sbmsstruct cu_data { 120127668Sbms int cu_fd; /* connections fd */ 121127668Sbms bool_t cu_closeit; /* opened by library */ 122127668Sbms struct sockaddr_storage cu_raddr; /* remote address */ 123172683Smlaier int cu_rlen; 124172683Smlaier struct timeval cu_wait; /* retransmit interval */ 125172683Smlaier struct timeval cu_total; /* total time for the call */ 126127668Sbms struct rpc_err cu_error; 127127668Sbms XDR cu_outxdrs; 128127668Sbms u_int cu_xdrpos; 129214478Srpaulo u_int cu_sendsz; /* send size */ 130214478Srpaulo char *cu_outbuf; 131214478Srpaulo u_int cu_recvsz; /* recv size */ 132190207Srpaulo int cu_async; 133190207Srpaulo int cu_connect; /* Use connect(). */ 134190207Srpaulo int cu_connected; /* Have done connect(). */ 135127668Sbms struct kevent cu_kin; 136127668Sbms int cu_kq; 137127668Sbms char cu_inbuf[1]; 138190207Srpaulo}; 139190207Srpaulo 140190207Srpaulo/* 141127668Sbms * Connection less client creation returns with client handle parameters. 142127668Sbms * Default options are set, which the user can change using clnt_control(). 143127668Sbms * fd should be open and bound. 144127668Sbms * NB: The rpch->cl_auth is initialized to null authentication. 145127668Sbms * Caller may wish to set this something more useful. 146127668Sbms * 147127668Sbms * sendsz and recvsz are the maximum allowable packet sizes that can be 148127668Sbms * sent and received. Normally they are the same, but they can be 149127668Sbms * changed to improve the program efficiency and buffer allocation. 150127668Sbms * If they are 0, use the transport default. 151127668Sbms * 152127668Sbms * If svcaddr is NULL, returns NULL. 153235530Sdelphij */ 154235530SdelphijCLIENT * 155235530Sdelphijclnt_dg_create(fd, svcaddr, program, version, sendsz, recvsz) 156214478Srpaulo int fd; /* open file descriptor */ 157214478Srpaulo const struct netbuf *svcaddr; /* servers address */ 158214478Srpaulo rpcprog_t program; /* program number */ 159127668Sbms rpcvers_t version; /* version number */ 16056893Sfenner u_int sendsz; /* buffer recv size */ 16156893Sfenner u_int recvsz; /* buffer send size */ 162127668Sbms{ 163127668Sbms CLIENT *cl = NULL; /* client handle */ 164127668Sbms struct cu_data *cu = NULL; /* private data */ 165235530Sdelphij struct timeval now; 166235530Sdelphij struct rpc_msg call_msg; 167235530Sdelphij sigset_t mask; 168127668Sbms sigset_t newmask; 16956893Sfenner struct __rpc_sockinfo si; 17056893Sfenner int one = 1; 171127668Sbms 17256893Sfenner sigfillset(&newmask); 17356893Sfenner thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 174127668Sbms mutex_lock(&clnt_fd_lock); 17556893Sfenner if (dg_fd_locks == (int *) NULL) { 17656893Sfenner int cv_allocsz; 177127668Sbms size_t fd_allocsz; 178127668Sbms int dtbsize = __rpc_dtbsize(); 179127668Sbms 180127668Sbms fd_allocsz = dtbsize * sizeof (int); 18175115Sfenner dg_fd_locks = (int *) mem_alloc(fd_allocsz); 18275115Sfenner if (dg_fd_locks == (int *) NULL) { 183214478Srpaulo mutex_unlock(&clnt_fd_lock); 184214478Srpaulo thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 185214478Srpaulo goto err1; 186127668Sbms } else 187127668Sbms memset(dg_fd_locks, '\0', fd_allocsz); 188127668Sbms 189127668Sbms cv_allocsz = dtbsize * sizeof (cond_t); 190127668Sbms dg_cv = (cond_t *) mem_alloc(cv_allocsz); 191127668Sbms if (dg_cv == (cond_t *) NULL) { 192127668Sbms mem_free(dg_fd_locks, fd_allocsz); 19356893Sfenner dg_fd_locks = (int *) NULL; 19456893Sfenner mutex_unlock(&clnt_fd_lock); 195127668Sbms thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 19698524Sfenner goto err1; 19798524Sfenner } else { 198127668Sbms int i; 199127668Sbms 200127668Sbms for (i = 0; i < dtbsize; i++) 201127668Sbms cond_init(&dg_cv[i], 0, (void *) 0); 202127668Sbms } 203127668Sbms } 204127668Sbms 205127668Sbms mutex_unlock(&clnt_fd_lock); 206127668Sbms thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 207127668Sbms 20875115Sfenner if (svcaddr == NULL) { 20975115Sfenner rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 210127668Sbms return (NULL); 21175115Sfenner } 21275115Sfenner 213127668Sbms if (!__rpc_fd2sockinfo(fd, &si)) { 214127668Sbms rpc_createerr.cf_stat = RPC_TLIERROR; 215127668Sbms rpc_createerr.cf_error.re_errno = 0; 216147899Ssam return (NULL); 217147899Ssam } 218147899Ssam /* 219147899Ssam * Find the receive and the send size 220147899Ssam */ 221147899Ssam sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 222127668Sbms recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 223127668Sbms if ((sendsz == 0) || (recvsz == 0)) { 224127668Sbms rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ 225127668Sbms rpc_createerr.cf_error.re_errno = 0; 226127668Sbms return (NULL); 227127668Sbms } 228127668Sbms 229127668Sbms if ((cl = mem_alloc(sizeof (CLIENT))) == NULL) 230127668Sbms goto err1; 231235530Sdelphij /* 232235530Sdelphij * Should be multiple of 4 for XDR. 233235530Sdelphij */ 234127668Sbms sendsz = ((sendsz + 3) / 4) * 4; 23556893Sfenner recvsz = ((recvsz + 3) / 4) * 4; 23656893Sfenner cu = mem_alloc(sizeof (*cu) + sendsz + recvsz); 237127668Sbms if (cu == NULL) 23875115Sfenner goto err1; 23975115Sfenner (void) memcpy(&cu->cu_raddr, svcaddr->buf, (size_t)svcaddr->len); 240127668Sbms cu->cu_rlen = svcaddr->len; 241127668Sbms cu->cu_outbuf = &cu->cu_inbuf[recvsz]; 24256893Sfenner /* Other values can also be set through clnt_control() */ 243214478Srpaulo cu->cu_wait.tv_sec = 15; /* heuristically chosen */ 244214478Srpaulo cu->cu_wait.tv_usec = 0; 245214478Srpaulo cu->cu_total.tv_sec = -1; 246146773Ssam cu->cu_total.tv_usec = -1; 247146773Ssam cu->cu_sendsz = sendsz; 248146773Ssam cu->cu_recvsz = recvsz; 249146773Ssam cu->cu_async = FALSE; 250146773Ssam cu->cu_connect = FALSE; 251146773Ssam cu->cu_connected = FALSE; 252127668Sbms (void) gettimeofday(&now, NULL); 253127668Sbms call_msg.rm_xid = __RPC_GETXID(&now); 25456893Sfenner call_msg.rm_call.cb_prog = program; 255127668Sbms call_msg.rm_call.cb_vers = version; 256127668Sbms xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); 25756893Sfenner if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { 258127668Sbms rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ 259127668Sbms rpc_createerr.cf_error.re_errno = 0; 26056893Sfenner goto err2; 261127668Sbms } 262127668Sbms cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); 26356893Sfenner 264127668Sbms /* XXX fvdl - do we still want this? */ 265127668Sbms#if 0 26656893Sfenner (void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf); 267127668Sbms#endif 268127668Sbms _ioctl(fd, FIONBIO, (char *)(void *)&one); 26956893Sfenner 270214478Srpaulo /* 271214478Srpaulo * By default, closeit is always FALSE. It is users responsibility 272214478Srpaulo * to do a close on it, else the user may use clnt_control 273127668Sbms * to let clnt_destroy do it for him/her. 274127668Sbms */ 275127668Sbms cu->cu_closeit = FALSE; 276127668Sbms cu->cu_fd = fd; 277127668Sbms cl->cl_ops = clnt_dg_ops(); 278127668Sbms cl->cl_private = (caddr_t)(void *)cu; 279214478Srpaulo cl->cl_auth = authnone_create(); 280214478Srpaulo cl->cl_tp = NULL; 281214478Srpaulo cl->cl_netid = NULL; 282214478Srpaulo cu->cu_kq = -1; 283214478Srpaulo EV_SET(&cu->cu_kin, cu->cu_fd, EVFILT_READ, EV_ADD, 0, 0, 0); 284214478Srpaulo return (cl); 285235530Sdelphijerr1: 286235530Sdelphij warnx(mem_err_clnt_dg); 287235530Sdelphij rpc_createerr.cf_stat = RPC_SYSTEMERROR; 288214478Srpaulo rpc_createerr.cf_error.re_errno = errno; 289214478Srpauloerr2: 290214478Srpaulo if (cl) { 291214478Srpaulo mem_free(cl, sizeof (CLIENT)); 292214478Srpaulo if (cu) 293214478Srpaulo mem_free(cu, sizeof (*cu) + sendsz + recvsz); 294214478Srpaulo } 295111726Sfenner return (NULL); 296111726Sfenner} 297147899Ssam 298147899Ssamstatic enum clnt_stat 299147899Ssamclnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) 300147899Ssam CLIENT *cl; /* client handle */ 301147899Ssam rpcproc_t proc; /* procedure number */ 302147899Ssam xdrproc_t xargs; /* xdr routine for args */ 303147899Ssam void *argsp; /* pointer to args */ 304147899Ssam xdrproc_t xresults; /* xdr routine for results */ 305147899Ssam void *resultsp; /* pointer to results */ 306147899Ssam struct timeval utimeout; /* seconds to wait before giving up */ 307147899Ssam{ 308147899Ssam struct cu_data *cu = (struct cu_data *)cl->cl_private; 309147899Ssam XDR *xdrs; 310147899Ssam size_t outlen = 0; 311147899Ssam struct rpc_msg reply_msg; 312147899Ssam XDR reply_xdrs; 313147899Ssam bool_t ok; 314147899Ssam int nrefreshes = 2; /* number of times to refresh cred */ 315147899Ssam struct timeval timeout; 316147899Ssam struct timeval retransmit_time; 317147899Ssam struct timeval next_sendtime, starttime, time_waited, tv; 318147899Ssam struct timespec ts; 319147899Ssam struct kevent kv; 320147899Ssam struct sockaddr *sa; 321 sigset_t mask; 322 sigset_t newmask; 323 socklen_t inlen, salen; 324 ssize_t recvlen = 0; 325 int kin_len, n, rpc_lock_value; 326 u_int32_t xid; 327 328 outlen = 0; 329 sigfillset(&newmask); 330 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 331 mutex_lock(&clnt_fd_lock); 332 while (dg_fd_locks[cu->cu_fd]) 333 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 334 if (__isthreaded) 335 rpc_lock_value = 1; 336 else 337 rpc_lock_value = 0; 338 dg_fd_locks[cu->cu_fd] = rpc_lock_value; 339 mutex_unlock(&clnt_fd_lock); 340 if (cu->cu_total.tv_usec == -1) { 341 timeout = utimeout; /* use supplied timeout */ 342 } else { 343 timeout = cu->cu_total; /* use default timeout */ 344 } 345 346 if (cu->cu_connect && !cu->cu_connected) { 347 if (_connect(cu->cu_fd, (struct sockaddr *)&cu->cu_raddr, 348 cu->cu_rlen) < 0) { 349 cu->cu_error.re_errno = errno; 350 cu->cu_error.re_status = RPC_CANTSEND; 351 goto out; 352 } 353 cu->cu_connected = 1; 354 } 355 if (cu->cu_connected) { 356 sa = NULL; 357 salen = 0; 358 } else { 359 sa = (struct sockaddr *)&cu->cu_raddr; 360 salen = cu->cu_rlen; 361 } 362 time_waited.tv_sec = 0; 363 time_waited.tv_usec = 0; 364 retransmit_time = next_sendtime = cu->cu_wait; 365 gettimeofday(&starttime, NULL); 366 367 /* Clean up in case the last call ended in a longjmp(3) call. */ 368 if (cu->cu_kq >= 0) 369 _close(cu->cu_kq); 370 if ((cu->cu_kq = kqueue()) < 0) { 371 cu->cu_error.re_errno = errno; 372 cu->cu_error.re_status = RPC_CANTSEND; 373 goto out; 374 } 375 kin_len = 1; 376 377call_again: 378 xdrs = &(cu->cu_outxdrs); 379 if (cu->cu_async == TRUE && xargs == NULL) 380 goto get_reply; 381 xdrs->x_op = XDR_ENCODE; 382 XDR_SETPOS(xdrs, cu->cu_xdrpos); 383 /* 384 * the transaction is the first thing in the out buffer 385 * XXX Yes, and it's in network byte order, so we should to 386 * be careful when we increment it, shouldn't we. 387 */ 388 xid = ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf)); 389 xid++; 390 *(u_int32_t *)(void *)(cu->cu_outbuf) = htonl(xid); 391 392 if ((! XDR_PUTINT32(xdrs, &proc)) || 393 (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || 394 (! (*xargs)(xdrs, argsp))) { 395 cu->cu_error.re_status = RPC_CANTENCODEARGS; 396 goto out; 397 } 398 outlen = (size_t)XDR_GETPOS(xdrs); 399 400send_again: 401 if (_sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0, sa, salen) != outlen) { 402 cu->cu_error.re_errno = errno; 403 cu->cu_error.re_status = RPC_CANTSEND; 404 goto out; 405 } 406 407 /* 408 * Hack to provide rpc-based message passing 409 */ 410 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 411 cu->cu_error.re_status = RPC_TIMEDOUT; 412 goto out; 413 } 414 415get_reply: 416 417 /* 418 * sub-optimal code appears here because we have 419 * some clock time to spare while the packets are in flight. 420 * (We assume that this is actually only executed once.) 421 */ 422 reply_msg.acpted_rply.ar_verf = _null_auth; 423 reply_msg.acpted_rply.ar_results.where = resultsp; 424 reply_msg.acpted_rply.ar_results.proc = xresults; 425 426 for (;;) { 427 /* Decide how long to wait. */ 428 if (timercmp(&next_sendtime, &timeout, <)) 429 timersub(&next_sendtime, &time_waited, &tv); 430 else 431 timersub(&timeout, &time_waited, &tv); 432 if (tv.tv_sec < 0 || tv.tv_usec < 0) 433 tv.tv_sec = tv.tv_usec = 0; 434 TIMEVAL_TO_TIMESPEC(&tv, &ts); 435 436 n = _kevent(cu->cu_kq, &cu->cu_kin, kin_len, &kv, 1, &ts); 437 /* We don't need to register the event again. */ 438 kin_len = 0; 439 440 if (n == 1) { 441 if (kv.flags & EV_ERROR) { 442 cu->cu_error.re_errno = kv.data; 443 cu->cu_error.re_status = RPC_CANTRECV; 444 goto out; 445 } 446 /* We have some data now */ 447 do { 448 recvlen = _recvfrom(cu->cu_fd, cu->cu_inbuf, 449 cu->cu_recvsz, 0, NULL, NULL); 450 } while (recvlen < 0 && errno == EINTR); 451 if (recvlen < 0 && errno != EWOULDBLOCK) { 452 cu->cu_error.re_errno = errno; 453 cu->cu_error.re_status = RPC_CANTRECV; 454 goto out; 455 } 456 if (recvlen >= sizeof(u_int32_t) && 457 (cu->cu_async == TRUE || 458 *((u_int32_t *)(void *)(cu->cu_inbuf)) == 459 *((u_int32_t *)(void *)(cu->cu_outbuf)))) { 460 /* We now assume we have the proper reply. */ 461 break; 462 } 463 } 464 if (n == -1 && errno != EINTR) { 465 cu->cu_error.re_errno = errno; 466 cu->cu_error.re_status = RPC_CANTRECV; 467 goto out; 468 } 469 gettimeofday(&tv, NULL); 470 timersub(&tv, &starttime, &time_waited); 471 472 /* Check for timeout. */ 473 if (timercmp(&time_waited, &timeout, >)) { 474 cu->cu_error.re_status = RPC_TIMEDOUT; 475 goto out; 476 } 477 478 /* Retransmit if necessary. */ 479 if (timercmp(&time_waited, &next_sendtime, >)) { 480 /* update retransmit_time */ 481 if (retransmit_time.tv_sec < RPC_MAX_BACKOFF) 482 timeradd(&retransmit_time, &retransmit_time, 483 &retransmit_time); 484 timeradd(&next_sendtime, &retransmit_time, 485 &next_sendtime); 486 goto send_again; 487 } 488 } 489 inlen = (socklen_t)recvlen; 490 491 /* 492 * now decode and validate the response 493 */ 494 495 xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)recvlen, XDR_DECODE); 496 ok = xdr_replymsg(&reply_xdrs, &reply_msg); 497 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ 498 if (ok) { 499 if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 500 (reply_msg.acpted_rply.ar_stat == SUCCESS)) 501 cu->cu_error.re_status = RPC_SUCCESS; 502 else 503 _seterr_reply(&reply_msg, &(cu->cu_error)); 504 505 if (cu->cu_error.re_status == RPC_SUCCESS) { 506 if (! AUTH_VALIDATE(cl->cl_auth, 507 &reply_msg.acpted_rply.ar_verf)) { 508 cu->cu_error.re_status = RPC_AUTHERROR; 509 cu->cu_error.re_why = AUTH_INVALIDRESP; 510 } 511 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 512 xdrs->x_op = XDR_FREE; 513 (void) xdr_opaque_auth(xdrs, 514 &(reply_msg.acpted_rply.ar_verf)); 515 } 516 } /* end successful completion */ 517 /* 518 * If unsuccesful AND error is an authentication error 519 * then refresh credentials and try again, else break 520 */ 521 else if (cu->cu_error.re_status == RPC_AUTHERROR) 522 /* maybe our credentials need to be refreshed ... */ 523 if (nrefreshes > 0 && 524 AUTH_REFRESH(cl->cl_auth, &reply_msg)) { 525 nrefreshes--; 526 goto call_again; 527 } 528 /* end of unsuccessful completion */ 529 } /* end of valid reply message */ 530 else { 531 cu->cu_error.re_status = RPC_CANTDECODERES; 532 533 } 534out: 535 if (cu->cu_kq >= 0) 536 _close(cu->cu_kq); 537 cu->cu_kq = -1; 538 release_fd_lock(cu->cu_fd, mask); 539 return (cu->cu_error.re_status); 540} 541 542static void 543clnt_dg_geterr(cl, errp) 544 CLIENT *cl; 545 struct rpc_err *errp; 546{ 547 struct cu_data *cu = (struct cu_data *)cl->cl_private; 548 549 *errp = cu->cu_error; 550} 551 552static bool_t 553clnt_dg_freeres(cl, xdr_res, res_ptr) 554 CLIENT *cl; 555 xdrproc_t xdr_res; 556 void *res_ptr; 557{ 558 struct cu_data *cu = (struct cu_data *)cl->cl_private; 559 XDR *xdrs = &(cu->cu_outxdrs); 560 bool_t dummy; 561 sigset_t mask; 562 sigset_t newmask; 563 564 sigfillset(&newmask); 565 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 566 mutex_lock(&clnt_fd_lock); 567 while (dg_fd_locks[cu->cu_fd]) 568 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 569 xdrs->x_op = XDR_FREE; 570 dummy = (*xdr_res)(xdrs, res_ptr); 571 mutex_unlock(&clnt_fd_lock); 572 thr_sigsetmask(SIG_SETMASK, &mask, NULL); 573 cond_signal(&dg_cv[cu->cu_fd]); 574 return (dummy); 575} 576 577/*ARGSUSED*/ 578static void 579clnt_dg_abort(h) 580 CLIENT *h; 581{ 582} 583 584static bool_t 585clnt_dg_control(cl, request, info) 586 CLIENT *cl; 587 u_int request; 588 void *info; 589{ 590 struct cu_data *cu = (struct cu_data *)cl->cl_private; 591 struct netbuf *addr; 592 sigset_t mask; 593 sigset_t newmask; 594 int rpc_lock_value; 595 596 sigfillset(&newmask); 597 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 598 mutex_lock(&clnt_fd_lock); 599 while (dg_fd_locks[cu->cu_fd]) 600 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 601 if (__isthreaded) 602 rpc_lock_value = 1; 603 else 604 rpc_lock_value = 0; 605 dg_fd_locks[cu->cu_fd] = rpc_lock_value; 606 mutex_unlock(&clnt_fd_lock); 607 switch (request) { 608 case CLSET_FD_CLOSE: 609 cu->cu_closeit = TRUE; 610 release_fd_lock(cu->cu_fd, mask); 611 return (TRUE); 612 case CLSET_FD_NCLOSE: 613 cu->cu_closeit = FALSE; 614 release_fd_lock(cu->cu_fd, mask); 615 return (TRUE); 616 } 617 618 /* for other requests which use info */ 619 if (info == NULL) { 620 release_fd_lock(cu->cu_fd, mask); 621 return (FALSE); 622 } 623 switch (request) { 624 case CLSET_TIMEOUT: 625 if (time_not_ok((struct timeval *)info)) { 626 release_fd_lock(cu->cu_fd, mask); 627 return (FALSE); 628 } 629 cu->cu_total = *(struct timeval *)info; 630 break; 631 case CLGET_TIMEOUT: 632 *(struct timeval *)info = cu->cu_total; 633 break; 634 case CLGET_SERVER_ADDR: /* Give him the fd address */ 635 /* Now obsolete. Only for backward compatibility */ 636 (void) memcpy(info, &cu->cu_raddr, (size_t)cu->cu_rlen); 637 break; 638 case CLSET_RETRY_TIMEOUT: 639 if (time_not_ok((struct timeval *)info)) { 640 release_fd_lock(cu->cu_fd, mask); 641 return (FALSE); 642 } 643 cu->cu_wait = *(struct timeval *)info; 644 break; 645 case CLGET_RETRY_TIMEOUT: 646 *(struct timeval *)info = cu->cu_wait; 647 break; 648 case CLGET_FD: 649 *(int *)info = cu->cu_fd; 650 break; 651 case CLGET_SVC_ADDR: 652 addr = (struct netbuf *)info; 653 addr->buf = &cu->cu_raddr; 654 addr->len = cu->cu_rlen; 655 addr->maxlen = sizeof cu->cu_raddr; 656 break; 657 case CLSET_SVC_ADDR: /* set to new address */ 658 addr = (struct netbuf *)info; 659 if (addr->len < sizeof cu->cu_raddr) { 660 release_fd_lock(cu->cu_fd, mask); 661 return (FALSE); 662 } 663 (void) memcpy(&cu->cu_raddr, addr->buf, addr->len); 664 cu->cu_rlen = addr->len; 665 break; 666 case CLGET_XID: 667 /* 668 * use the knowledge that xid is the 669 * first element in the call structure *. 670 * This will get the xid of the PREVIOUS call 671 */ 672 *(u_int32_t *)info = 673 ntohl(*(u_int32_t *)(void *)cu->cu_outbuf); 674 break; 675 676 case CLSET_XID: 677 /* This will set the xid of the NEXT call */ 678 *(u_int32_t *)(void *)cu->cu_outbuf = 679 htonl(*(u_int32_t *)info - 1); 680 /* decrement by 1 as clnt_dg_call() increments once */ 681 break; 682 683 case CLGET_VERS: 684 /* 685 * This RELIES on the information that, in the call body, 686 * the version number field is the fifth field from the 687 * begining of the RPC header. MUST be changed if the 688 * call_struct is changed 689 */ 690 *(u_int32_t *)info = 691 ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + 692 4 * BYTES_PER_XDR_UNIT)); 693 break; 694 695 case CLSET_VERS: 696 *(u_int32_t *)(void *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT) 697 = htonl(*(u_int32_t *)info); 698 break; 699 700 case CLGET_PROG: 701 /* 702 * This RELIES on the information that, in the call body, 703 * the program number field is the fourth field from the 704 * begining of the RPC header. MUST be changed if the 705 * call_struct is changed 706 */ 707 *(u_int32_t *)info = 708 ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + 709 3 * BYTES_PER_XDR_UNIT)); 710 break; 711 712 case CLSET_PROG: 713 *(u_int32_t *)(void *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT) 714 = htonl(*(u_int32_t *)info); 715 break; 716 case CLSET_ASYNC: 717 cu->cu_async = *(int *)info; 718 break; 719 case CLSET_CONNECT: 720 cu->cu_connect = *(int *)info; 721 break; 722 default: 723 release_fd_lock(cu->cu_fd, mask); 724 return (FALSE); 725 } 726 release_fd_lock(cu->cu_fd, mask); 727 return (TRUE); 728} 729 730static void 731clnt_dg_destroy(cl) 732 CLIENT *cl; 733{ 734 struct cu_data *cu = (struct cu_data *)cl->cl_private; 735 int cu_fd = cu->cu_fd; 736 sigset_t mask; 737 sigset_t newmask; 738 739 sigfillset(&newmask); 740 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 741 mutex_lock(&clnt_fd_lock); 742 while (dg_fd_locks[cu_fd]) 743 cond_wait(&dg_cv[cu_fd], &clnt_fd_lock); 744 if (cu->cu_closeit) 745 (void)_close(cu_fd); 746 if (cu->cu_kq >= 0) 747 _close(cu->cu_kq); 748 XDR_DESTROY(&(cu->cu_outxdrs)); 749 mem_free(cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz)); 750 if (cl->cl_netid && cl->cl_netid[0]) 751 mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 752 if (cl->cl_tp && cl->cl_tp[0]) 753 mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 754 mem_free(cl, sizeof (CLIENT)); 755 mutex_unlock(&clnt_fd_lock); 756 thr_sigsetmask(SIG_SETMASK, &mask, NULL); 757 cond_signal(&dg_cv[cu_fd]); 758} 759 760static struct clnt_ops * 761clnt_dg_ops() 762{ 763 static struct clnt_ops ops; 764 sigset_t mask; 765 sigset_t newmask; 766 767/* VARIABLES PROTECTED BY ops_lock: ops */ 768 769 sigfillset(&newmask); 770 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 771 mutex_lock(&ops_lock); 772 if (ops.cl_call == NULL) { 773 ops.cl_call = clnt_dg_call; 774 ops.cl_abort = clnt_dg_abort; 775 ops.cl_geterr = clnt_dg_geterr; 776 ops.cl_freeres = clnt_dg_freeres; 777 ops.cl_destroy = clnt_dg_destroy; 778 ops.cl_control = clnt_dg_control; 779 } 780 mutex_unlock(&ops_lock); 781 thr_sigsetmask(SIG_SETMASK, &mask, NULL); 782 return (&ops); 783} 784 785/* 786 * Make sure that the time is not garbage. -1 value is allowed. 787 */ 788static bool_t 789time_not_ok(t) 790 struct timeval *t; 791{ 792 return (t->tv_sec < -1 || t->tv_sec > 100000000 || 793 t->tv_usec < -1 || t->tv_usec > 1000000); 794} 795 796