1 /* $NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl Exp $ */ 2 3 /* 4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5 * unrestricted use provided that this legend is included on all tape 6 * media and as a part of the software program in whole or part. Users 7 * may copy or modify Sun RPC without charge, but are not authorized 8 * to license or distribute it to anyone else except as part of a product or 9 * program developed by the user. 10 * 11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 14 * 15 * Sun RPC is provided with no support and without any obligation on the 16 * part of Sun Microsystems, Inc. to assist in its use, correction, 17 * modification or enhancement. 18 * 19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 21 * OR ANY PART THEREOF. 22 * 23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24 * or profits or other special, indirect and consequential damages, even if 25 * Sun has been advised of the possibility of such damages. 26 * 27 * Sun Microsystems, Inc. 28 * 2550 Garcia Avenue 29 * Mountain View, California 94043 30 */ 31 /* 32 * Copyright (c) 1986-1991 by Sun Microsystems Inc. 33 */ 34 35 #if defined(LIBC_SCCS) && !defined(lint) 36 #ident "@(#)clnt_dg.c 1.23 94/04/22 SMI" 37 static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 38 #endif 39 #include <sys/cdefs.h> 40 __FBSDID("$FreeBSD$"); 41 42 /* 43 * Implements a connectionless client side RPC. 44 */ 45 46 #include "namespace.h" 47 #include "reentrant.h" 48 #include <sys/types.h> 49 #include <sys/event.h> 50 #include <sys/time.h> 51 #include <sys/socket.h> 52 #include <sys/ioctl.h> 53 #include <arpa/inet.h> 54 #include <rpc/rpc.h> 55 #include <errno.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <signal.h> 59 #include <unistd.h> 60 #include <err.h> 61 #include "un-namespace.h" 62 #include "rpc_com.h" 63 #include "mt_misc.h" 64 65 66 #ifdef _FREEFALL_CONFIG 67 /* 68 * Disable RPC exponential back-off for FreeBSD.org systems. 69 */ 70 #define RPC_MAX_BACKOFF 1 /* second */ 71 #else 72 #define RPC_MAX_BACKOFF 30 /* seconds */ 73 #endif 74 75 76 static struct clnt_ops *clnt_dg_ops(void); 77 static bool_t time_not_ok(struct timeval *); 78 static enum clnt_stat clnt_dg_call(CLIENT *, rpcproc_t, xdrproc_t, void *, 79 xdrproc_t, void *, struct timeval); 80 static void clnt_dg_geterr(CLIENT *, struct rpc_err *); 81 static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, void *); 82 static void clnt_dg_abort(CLIENT *); 83 static bool_t clnt_dg_control(CLIENT *, u_int, void *); 84 static void clnt_dg_destroy(CLIENT *); 85 86 87 88 89 /* 90 * This machinery implements per-fd locks for MT-safety. It is not 91 * sufficient to do per-CLIENT handle locks for MT-safety because a 92 * user may create more than one CLIENT handle with the same fd behind 93 * it. Therfore, we allocate an array of flags (dg_fd_locks), protected 94 * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables 95 * similarly protected. Dg_fd_lock[fd] == 1 => a call is activte on some 96 * CLIENT handle created for that fd. 97 * The current implementation holds locks across the entire RPC and reply, 98 * including retransmissions. Yes, this is silly, and as soon as this 99 * code is proven to work, this should be the first thing fixed. One step 100 * at a time. 101 */ 102 static int *dg_fd_locks; 103 static cond_t *dg_cv; 104 #define release_fd_lock(fd, mask) { \ 105 mutex_lock(&clnt_fd_lock); \ 106 dg_fd_locks[fd] = 0; \ 107 mutex_unlock(&clnt_fd_lock); \ 108 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \ 109 cond_signal(&dg_cv[fd]); \ 110 } 111 112 static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; 113 114 /* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */ 115 116 /* 117 * Private data kept per client handle 118 */ 119 struct cu_data { 120 int cu_fd; /* connections fd */ 121 bool_t cu_closeit; /* opened by library */ 122 struct sockaddr_storage cu_raddr; /* remote address */ 123 int cu_rlen; 124 struct timeval cu_wait; /* retransmit interval */ 125 struct timeval cu_total; /* total time for the call */ 126 struct rpc_err cu_error; 127 XDR cu_outxdrs; 128 u_int cu_xdrpos; 129 u_int cu_sendsz; /* send size */ 130 char *cu_outbuf; 131 u_int cu_recvsz; /* recv size */ 132 int cu_async; 133 int cu_connect; /* Use connect(). */ 134 int cu_connected; /* Have done connect(). */ 135 struct kevent cu_kin; 136 int cu_kq; 137 char cu_inbuf[1]; 138 }; 139 140 /* 141 * Connection less client creation returns with client handle parameters. 142 * Default options are set, which the user can change using clnt_control(). 143 * fd should be open and bound. 144 * NB: The rpch->cl_auth is initialized to null authentication. 145 * Caller may wish to set this something more useful. 146 * 147 * sendsz and recvsz are the maximum allowable packet sizes that can be 148 * sent and received. Normally they are the same, but they can be 149 * changed to improve the program efficiency and buffer allocation. 150 * If they are 0, use the transport default. 151 * 152 * If svcaddr is NULL, returns NULL. 153 */ 154 CLIENT * 155 clnt_dg_create(fd, svcaddr, program, version, sendsz, recvsz) 156 int fd; /* open file descriptor */ 157 const struct netbuf *svcaddr; /* servers address */ 158 rpcprog_t program; /* program number */ 159 rpcvers_t version; /* version number */ 160 u_int sendsz; /* buffer recv size */ 161 u_int recvsz; /* buffer send size */ 162 { 163 CLIENT *cl = NULL; /* client handle */ 164 struct cu_data *cu = NULL; /* private data */ 165 struct timeval now; 166 struct rpc_msg call_msg; 167 sigset_t mask; 168 sigset_t newmask; 169 struct __rpc_sockinfo si; 170 int one = 1; 171 172 sigfillset(&newmask); 173 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 174 mutex_lock(&clnt_fd_lock); 175 if (dg_fd_locks == (int *) NULL) { 176 int cv_allocsz; 177 size_t fd_allocsz; 178 int dtbsize = __rpc_dtbsize(); 179 180 fd_allocsz = dtbsize * sizeof (int); 181 dg_fd_locks = (int *) mem_alloc(fd_allocsz); 182 if (dg_fd_locks == (int *) NULL) { 183 mutex_unlock(&clnt_fd_lock); 184 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 185 goto err1; 186 } else 187 memset(dg_fd_locks, '\0', fd_allocsz); 188 189 cv_allocsz = dtbsize * sizeof (cond_t); 190 dg_cv = (cond_t *) mem_alloc(cv_allocsz); 191 if (dg_cv == (cond_t *) NULL) { 192 mem_free(dg_fd_locks, fd_allocsz); 193 dg_fd_locks = (int *) NULL; 194 mutex_unlock(&clnt_fd_lock); 195 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 196 goto err1; 197 } else { 198 int i; 199 200 for (i = 0; i < dtbsize; i++) 201 cond_init(&dg_cv[i], 0, (void *) 0); 202 } 203 } 204 205 mutex_unlock(&clnt_fd_lock); 206 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 207 208 if (svcaddr == NULL) { 209 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 210 return (NULL); 211 } 212 213 if (!__rpc_fd2sockinfo(fd, &si)) { 214 rpc_createerr.cf_stat = RPC_TLIERROR; 215 rpc_createerr.cf_error.re_errno = 0; 216 return (NULL); 217 } 218 /* 219 * Find the receive and the send size 220 */ 221 sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 222 recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 223 if ((sendsz == 0) || (recvsz == 0)) { 224 rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ 225 rpc_createerr.cf_error.re_errno = 0; 226 return (NULL); 227 } 228 229 if ((cl = mem_alloc(sizeof (CLIENT))) == NULL) 230 goto err1; 231 /* 232 * Should be multiple of 4 for XDR. 233 */ 234 sendsz = ((sendsz + 3) / 4) * 4; 235 recvsz = ((recvsz + 3) / 4) * 4; 236 cu = mem_alloc(sizeof (*cu) + sendsz + recvsz); 237 if (cu == NULL) 238 goto err1; 239 (void) memcpy(&cu->cu_raddr, svcaddr->buf, (size_t)svcaddr->len); 240 cu->cu_rlen = svcaddr->len; 241 cu->cu_outbuf = &cu->cu_inbuf[recvsz]; 242 /* Other values can also be set through clnt_control() */ 243 cu->cu_wait.tv_sec = 15; /* heuristically chosen */ 244 cu->cu_wait.tv_usec = 0; 245 cu->cu_total.tv_sec = -1; 246 cu->cu_total.tv_usec = -1; 247 cu->cu_sendsz = sendsz; 248 cu->cu_recvsz = recvsz; 249 cu->cu_async = FALSE; 250 cu->cu_connect = FALSE; 251 cu->cu_connected = FALSE; 252 (void) gettimeofday(&now, NULL); 253 call_msg.rm_xid = __RPC_GETXID(&now); 254 call_msg.rm_call.cb_prog = program; 255 call_msg.rm_call.cb_vers = version; 256 xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); 257 if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { 258 rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ 259 rpc_createerr.cf_error.re_errno = 0; 260 goto err2; 261 } 262 cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); 263 264 /* XXX fvdl - do we still want this? */ 265 #if 0 266 (void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf); 267 #endif 268 _ioctl(fd, FIONBIO, (char *)(void *)&one); 269 270 /* 271 * By default, closeit is always FALSE. It is users responsibility 272 * to do a close on it, else the user may use clnt_control 273 * to let clnt_destroy do it for him/her. 274 */ 275 cu->cu_closeit = FALSE; 276 cu->cu_fd = fd; 277 cl->cl_ops = clnt_dg_ops(); 278 cl->cl_private = (caddr_t)(void *)cu; 279 cl->cl_auth = authnone_create(); 280 cl->cl_tp = NULL; 281 cl->cl_netid = NULL; 282 cu->cu_kq = -1; 283 EV_SET(&cu->cu_kin, cu->cu_fd, EVFILT_READ, EV_ADD, 0, 0, 0); 284 return (cl); 285 err1: 286 warnx(mem_err_clnt_dg); 287 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 288 rpc_createerr.cf_error.re_errno = errno; 289 err2: 290 if (cl) { 291 mem_free(cl, sizeof (CLIENT)); 292 if (cu) 293 mem_free(cu, sizeof (*cu) + sendsz + recvsz); 294 } 295 return (NULL); 296 } 297 298 static enum clnt_stat 299 clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) 300 CLIENT *cl; /* client handle */ 301 rpcproc_t proc; /* procedure number */ 302 xdrproc_t xargs; /* xdr routine for args */ 303 void *argsp; /* pointer to args */ 304 xdrproc_t xresults; /* xdr routine for results */ 305 void *resultsp; /* pointer to results */ 306 struct timeval utimeout; /* seconds to wait before giving up */ 307 { 308 struct cu_data *cu = (struct cu_data *)cl->cl_private; 309 XDR *xdrs; 310 size_t outlen = 0; 311 struct rpc_msg reply_msg; 312 XDR reply_xdrs; 313 bool_t ok; 314 int nrefreshes = 2; /* number of times to refresh cred */ 315 struct timeval timeout; 316 struct timeval retransmit_time; 317 struct timeval next_sendtime, starttime, time_waited, tv; 318 struct timespec ts; 319 struct kevent kv; 320 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 377 call_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 400 send_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 415 get_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 } 534 out: 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 542 static void 543 clnt_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 552 static bool_t 553 clnt_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*/ 578 static void 579 clnt_dg_abort(h) 580 CLIENT *h; 581 { 582 } 583 584 static bool_t 585 clnt_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 730 static void 731 clnt_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 760 static struct clnt_ops * 761 clnt_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 */ 788 static bool_t 789 time_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