1 /* $NetBSD: clnt_dg.c,v 1.10 2003/06/06 00:48:45 yamt 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 /* #ident "@(#)clnt_dg.c 1.23 94/04/22 SMI" */ 36 37 #if 0 38 #if !defined(lint) && defined(SCCSIDS) 39 static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 40 #endif 41 #endif 42 43 /* 44 * Implements a connectionless client side RPC. 45 */ 46 47 #include "namespace.h" 48 #include "reentrant.h" 49 #include <sys/poll.h> 50 #include <sys/types.h> 51 #include <sys/time.h> 52 #include <sys/socket.h> 53 #include <sys/ioctl.h> 54 #include <rpc/rpc.h> 55 #include <assert.h> 56 #include <errno.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <signal.h> 60 #include <unistd.h> 61 #include <err.h> 62 #include "rpc_internal.h" 63 64 #ifdef __weak_alias 65 __weak_alias(clnt_dg_create,_clnt_dg_create) 66 #endif 67 68 #define RPC_MAX_BACKOFF 30 /* seconds */ 69 70 71 static struct clnt_ops *clnt_dg_ops __P((void)); 72 static bool_t time_not_ok __P((struct timeval *)); 73 static enum clnt_stat clnt_dg_call __P((CLIENT *, rpcproc_t, xdrproc_t, caddr_t, 74 xdrproc_t, caddr_t, struct timeval)); 75 static void clnt_dg_geterr __P((CLIENT *, struct rpc_err *)); 76 static bool_t clnt_dg_freeres __P((CLIENT *, xdrproc_t, caddr_t)); 77 static void clnt_dg_abort __P((CLIENT *)); 78 static bool_t clnt_dg_control __P((CLIENT *, u_int, char *)); 79 static void clnt_dg_destroy __P((CLIENT *)); 80 static int __rpc_timeval_to_msec __P((struct timeval *)); 81 82 83 84 85 /* 86 * This machinery implements per-fd locks for MT-safety. It is not 87 * sufficient to do per-CLIENT handle locks for MT-safety because a 88 * user may create more than one CLIENT handle with the same fd behind 89 * it. Therfore, we allocate an array of flags (dg_fd_locks), protected 90 * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables 91 * similarly protected. Dg_fd_lock[fd] == 1 => a call is activte on some 92 * CLIENT handle created for that fd. 93 * The current implementation holds locks across the entire RPC and reply, 94 * including retransmissions. Yes, this is silly, and as soon as this 95 * code is proven to work, this should be the first thing fixed. One step 96 * at a time. 97 */ 98 static int *dg_fd_locks; 99 #ifdef _REENTRANT 100 extern int __isthreaded; 101 #define __rpc_lock_value __isthreaded; 102 extern mutex_t clnt_fd_lock; 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), (sigset_t *) NULL); \ 109 cond_signal(&dg_cv[fd]); \ 110 } 111 #else 112 #define release_fd_lock(fd,mask) 113 #define __rpc_lock_value 0 114 #endif 115 116 static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; 117 118 /* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */ 119 120 /* 121 * Private data kept per client handle 122 */ 123 struct cu_data { 124 int cu_fd; /* connections fd */ 125 bool_t cu_closeit; /* opened by library */ 126 struct sockaddr_storage cu_raddr; /* remote address */ 127 int cu_rlen; 128 struct timeval cu_wait; /* retransmit interval */ 129 struct timeval cu_total; /* total time for the call */ 130 struct rpc_err cu_error; 131 XDR cu_outxdrs; 132 u_int cu_xdrpos; 133 u_int cu_sendsz; /* send size */ 134 char *cu_outbuf; 135 u_int cu_recvsz; /* recv size */ 136 struct pollfd pfdp; 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 #ifdef _REENTRANT 168 sigset_t mask; 169 #endif 170 sigset_t newmask; 171 struct __rpc_sockinfo si; 172 int one = 1; 173 174 sigfillset(&newmask); 175 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 176 mutex_lock(&clnt_fd_lock); 177 if (dg_fd_locks == (int *) NULL) { 178 #ifdef _REENTRANT 179 size_t cv_allocsz; 180 #endif 181 size_t fd_allocsz; 182 int dtbsize = __rpc_dtbsize(); 183 184 fd_allocsz = dtbsize * sizeof (int); 185 dg_fd_locks = (int *) mem_alloc(fd_allocsz); 186 if (dg_fd_locks == (int *) NULL) { 187 mutex_unlock(&clnt_fd_lock); 188 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 189 goto err1; 190 } else 191 memset(dg_fd_locks, '\0', fd_allocsz); 192 193 #ifdef _REENTRANT 194 cv_allocsz = dtbsize * sizeof (cond_t); 195 dg_cv = (cond_t *) mem_alloc(cv_allocsz); 196 if (dg_cv == (cond_t *) NULL) { 197 mem_free(dg_fd_locks, fd_allocsz); 198 dg_fd_locks = (int *) NULL; 199 mutex_unlock(&clnt_fd_lock); 200 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 201 goto err1; 202 } else { 203 int i; 204 205 for (i = 0; i < dtbsize; i++) 206 cond_init(&dg_cv[i], 0, (void *) 0); 207 } 208 #endif 209 } 210 211 mutex_unlock(&clnt_fd_lock); 212 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 213 214 if (svcaddr == NULL) { 215 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 216 return (NULL); 217 } 218 219 if (!__rpc_fd2sockinfo(fd, &si)) { 220 rpc_createerr.cf_stat = RPC_TLIERROR; 221 rpc_createerr.cf_error.re_errno = 0; 222 return (NULL); 223 } 224 /* 225 * Find the receive and the send size 226 */ 227 sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 228 recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 229 if ((sendsz == 0) || (recvsz == 0)) { 230 rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ 231 rpc_createerr.cf_error.re_errno = 0; 232 return (NULL); 233 } 234 235 if ((cl = mem_alloc(sizeof (CLIENT))) == NULL) 236 goto err1; 237 /* 238 * Should be multiple of 4 for XDR. 239 */ 240 sendsz = ((sendsz + 3) / 4) * 4; 241 recvsz = ((recvsz + 3) / 4) * 4; 242 cu = mem_alloc(sizeof (*cu) + sendsz + recvsz); 243 if (cu == NULL) 244 goto err1; 245 (void) memcpy(&cu->cu_raddr, svcaddr->buf, (size_t)svcaddr->len); 246 cu->cu_rlen = svcaddr->len; 247 cu->cu_outbuf = &cu->cu_inbuf[recvsz]; 248 /* Other values can also be set through clnt_control() */ 249 cu->cu_wait.tv_sec = 15; /* heuristically chosen */ 250 cu->cu_wait.tv_usec = 0; 251 cu->cu_total.tv_sec = -1; 252 cu->cu_total.tv_usec = -1; 253 cu->cu_sendsz = sendsz; 254 cu->cu_recvsz = recvsz; 255 (void) gettimeofday(&now, NULL); 256 call_msg.rm_xid = __RPC_GETXID(&now); 257 call_msg.rm_call.cb_prog = program; 258 call_msg.rm_call.cb_vers = version; 259 xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); 260 if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { 261 rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ 262 rpc_createerr.cf_error.re_errno = 0; 263 goto err2; 264 } 265 cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); 266 267 /* XXX fvdl - do we still want this? */ 268 #if 0 269 (void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf); 270 #endif 271 ioctl(fd, FIONBIO, (char *)(void *)&one); 272 273 /* 274 * By default, closeit is always FALSE. It is users responsibility 275 * to do a close on it, else the user may use clnt_control 276 * to let clnt_destroy do it for him/her. 277 */ 278 cu->cu_closeit = FALSE; 279 cu->cu_fd = fd; 280 cl->cl_ops = clnt_dg_ops(); 281 cl->cl_private = (caddr_t)(void *)cu; 282 cl->cl_auth = authnone_create(); 283 cl->cl_tp = NULL; 284 cl->cl_netid = NULL; 285 cu->pfdp.fd = cu->cu_fd; 286 cu->pfdp.events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND; 287 return (cl); 288 err1: 289 warnx(mem_err_clnt_dg); 290 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 291 rpc_createerr.cf_error.re_errno = errno; 292 err2: 293 if (cl) { 294 mem_free(cl, sizeof (CLIENT)); 295 if (cu) 296 mem_free(cu, sizeof (*cu) + sendsz + recvsz); 297 } 298 return (NULL); 299 } 300 301 static enum clnt_stat 302 clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) 303 CLIENT *cl; /* client handle */ 304 rpcproc_t proc; /* procedure number */ 305 xdrproc_t xargs; /* xdr routine for args */ 306 caddr_t argsp; /* pointer to args */ 307 xdrproc_t xresults; /* xdr routine for results */ 308 caddr_t resultsp; /* pointer to results */ 309 struct timeval utimeout; /* seconds to wait before giving up */ 310 { 311 struct cu_data *cu; 312 XDR *xdrs; 313 size_t outlen; 314 struct rpc_msg reply_msg; 315 XDR reply_xdrs; 316 struct timeval time_waited; 317 bool_t ok; 318 int nrefreshes = 2; /* number of times to refresh cred */ 319 struct timeval timeout; 320 struct timeval retransmit_time; 321 struct timeval startime, curtime; 322 int firsttimeout = 1; 323 #ifdef _REENTRANT 324 sigset_t mask; 325 #endif 326 sigset_t newmask; 327 socklen_t fromlen, inlen; 328 ssize_t recvlen = 0; 329 330 _DIAGASSERT(cl != NULL); 331 332 cu = (struct cu_data *)cl->cl_private; 333 334 sigfillset(&newmask); 335 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 336 mutex_lock(&clnt_fd_lock); 337 while (dg_fd_locks[cu->cu_fd]) 338 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 339 dg_fd_locks[cu->cu_fd] = __rpc_lock_value; 340 mutex_unlock(&clnt_fd_lock); 341 if (cu->cu_total.tv_usec == -1) { 342 timeout = utimeout; /* use supplied timeout */ 343 } else { 344 timeout = cu->cu_total; /* use default timeout */ 345 } 346 347 time_waited.tv_sec = 0; 348 time_waited.tv_usec = 0; 349 retransmit_time = cu->cu_wait; 350 351 call_again: 352 xdrs = &(cu->cu_outxdrs); 353 xdrs->x_op = XDR_ENCODE; 354 XDR_SETPOS(xdrs, cu->cu_xdrpos); 355 /* 356 * the transaction is the first thing in the out buffer 357 */ 358 (*(u_int32_t *)(void *)(cu->cu_outbuf))++; 359 if ((! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 360 (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || 361 (! (*xargs)(xdrs, argsp))) { 362 release_fd_lock(cu->cu_fd, mask); 363 return (cu->cu_error.re_status = RPC_CANTENCODEARGS); 364 } 365 outlen = (size_t)XDR_GETPOS(xdrs); 366 367 send_again: 368 if (sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0, 369 (struct sockaddr *)(void *)&cu->cu_raddr, (socklen_t)cu->cu_rlen) 370 != outlen) { 371 cu->cu_error.re_errno = errno; 372 release_fd_lock(cu->cu_fd, mask); 373 return (cu->cu_error.re_status = RPC_CANTSEND); 374 } 375 376 /* 377 * Hack to provide rpc-based message passing 378 */ 379 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 380 release_fd_lock(cu->cu_fd, mask); 381 return (cu->cu_error.re_status = RPC_TIMEDOUT); 382 } 383 /* 384 * sub-optimal code appears here because we have 385 * some clock time to spare while the packets are in flight. 386 * (We assume that this is actually only executed once.) 387 */ 388 reply_msg.acpted_rply.ar_verf = _null_auth; 389 reply_msg.acpted_rply.ar_results.where = resultsp; 390 reply_msg.acpted_rply.ar_results.proc = xresults; 391 392 393 for (;;) { 394 switch (poll(&cu->pfdp, 1, 395 __rpc_timeval_to_msec(&retransmit_time))) { 396 case 0: 397 time_waited.tv_sec += retransmit_time.tv_sec; 398 time_waited.tv_usec += retransmit_time.tv_usec; 399 while (time_waited.tv_usec >= 1000000) { 400 time_waited.tv_sec++; 401 time_waited.tv_usec -= 1000000; 402 } 403 /* update retransmit_time */ 404 if (retransmit_time.tv_sec < RPC_MAX_BACKOFF) { 405 retransmit_time.tv_usec *= 2; 406 retransmit_time.tv_sec *= 2; 407 while (retransmit_time.tv_usec >= 1000000) { 408 retransmit_time.tv_sec++; 409 retransmit_time.tv_usec -= 1000000; 410 } 411 } 412 413 if ((time_waited.tv_sec < timeout.tv_sec) || 414 ((time_waited.tv_sec == timeout.tv_sec) && 415 (time_waited.tv_usec < timeout.tv_usec))) 416 goto send_again; 417 release_fd_lock(cu->cu_fd, mask); 418 return (cu->cu_error.re_status = RPC_TIMEDOUT); 419 420 case -1: 421 if (errno == EBADF) { 422 cu->cu_error.re_errno = errno; 423 release_fd_lock(cu->cu_fd, mask); 424 return (cu->cu_error.re_status = RPC_CANTRECV); 425 } 426 if (errno != EINTR) { 427 errno = 0; /* reset it */ 428 continue; 429 } 430 /* interrupted by another signal, update time_waited */ 431 if (firsttimeout) { 432 /* 433 * Could have done gettimeofday before clnt_call 434 * but that means 1 more system call per each 435 * clnt_call, so do it after first time out 436 */ 437 if (gettimeofday(&startime, 438 (struct timezone *) NULL) == -1) { 439 errno = 0; 440 continue; 441 } 442 firsttimeout = 0; 443 errno = 0; 444 continue; 445 }; 446 if (gettimeofday(&curtime, 447 (struct timezone *) NULL) == -1) { 448 errno = 0; 449 continue; 450 }; 451 time_waited.tv_sec += curtime.tv_sec - startime.tv_sec; 452 time_waited.tv_usec += curtime.tv_usec - 453 startime.tv_usec; 454 while (time_waited.tv_usec < 0) { 455 time_waited.tv_sec--; 456 time_waited.tv_usec += 1000000; 457 }; 458 while (time_waited.tv_usec >= 1000000) { 459 time_waited.tv_sec++; 460 time_waited.tv_usec -= 1000000; 461 } 462 startime.tv_sec = curtime.tv_sec; 463 startime.tv_usec = curtime.tv_usec; 464 if ((time_waited.tv_sec > timeout.tv_sec) || 465 ((time_waited.tv_sec == timeout.tv_sec) && 466 (time_waited.tv_usec > timeout.tv_usec))) { 467 release_fd_lock(cu->cu_fd, mask); 468 return (cu->cu_error.re_status = RPC_TIMEDOUT); 469 } 470 errno = 0; /* reset it */ 471 continue; 472 }; 473 474 if (cu->pfdp.revents & POLLNVAL || (cu->pfdp.revents == 0)) { 475 cu->cu_error.re_status = RPC_CANTRECV; 476 /* 477 * Note: we're faking errno here because we 478 * previously would have expected poll() to 479 * return -1 with errno EBADF. Poll(BA_OS) 480 * returns 0 and sets the POLLNVAL revents flag 481 * instead. 482 */ 483 cu->cu_error.re_errno = errno = EBADF; 484 release_fd_lock(cu->cu_fd, mask); 485 return (-1); 486 } 487 488 /* We have some data now */ 489 do { 490 if (errno == EINTR) { 491 /* 492 * Must make sure errno was not already 493 * EINTR in case recvfrom() returns -1. 494 */ 495 errno = 0; 496 } 497 fromlen = sizeof (struct sockaddr_storage); 498 recvlen = recvfrom(cu->cu_fd, cu->cu_inbuf, 499 cu->cu_recvsz, 0, (struct sockaddr *)(void *)&cu->cu_raddr, 500 &fromlen); 501 } while (recvlen < 0 && errno == EINTR); 502 if (recvlen < 0) { 503 if (errno == EWOULDBLOCK) 504 continue; 505 cu->cu_error.re_errno = errno; 506 release_fd_lock(cu->cu_fd, mask); 507 return (cu->cu_error.re_status = RPC_CANTRECV); 508 } 509 if (recvlen < sizeof (u_int32_t)) 510 continue; 511 /* see if reply transaction id matches sent id */ 512 if (*((u_int32_t *)(void *)(cu->cu_inbuf)) != 513 *((u_int32_t *)(void *)(cu->cu_outbuf))) 514 continue; 515 /* we now assume we have the proper reply */ 516 break; 517 } 518 inlen = (socklen_t)recvlen; 519 520 /* 521 * now decode and validate the response 522 */ 523 524 xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE); 525 ok = xdr_replymsg(&reply_xdrs, &reply_msg); 526 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ 527 if (ok) { 528 if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 529 (reply_msg.acpted_rply.ar_stat == SUCCESS)) 530 cu->cu_error.re_status = RPC_SUCCESS; 531 else 532 _seterr_reply(&reply_msg, &(cu->cu_error)); 533 534 if (cu->cu_error.re_status == RPC_SUCCESS) { 535 if (! AUTH_VALIDATE(cl->cl_auth, 536 &reply_msg.acpted_rply.ar_verf)) { 537 cu->cu_error.re_status = RPC_AUTHERROR; 538 cu->cu_error.re_why = AUTH_INVALIDRESP; 539 } 540 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 541 xdrs->x_op = XDR_FREE; 542 (void) xdr_opaque_auth(xdrs, 543 &(reply_msg.acpted_rply.ar_verf)); 544 } 545 } /* end successful completion */ 546 /* 547 * If unsuccesful AND error is an authentication error 548 * then refresh credentials and try again, else break 549 */ 550 else if (cu->cu_error.re_status == RPC_AUTHERROR) 551 /* maybe our credentials need to be refreshed ... */ 552 if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) { 553 nrefreshes--; 554 goto call_again; 555 } 556 /* end of unsuccessful completion */ 557 } /* end of valid reply message */ 558 else { 559 cu->cu_error.re_status = RPC_CANTDECODERES; 560 561 } 562 release_fd_lock(cu->cu_fd, mask); 563 return (cu->cu_error.re_status); 564 } 565 566 static void 567 clnt_dg_geterr(cl, errp) 568 CLIENT *cl; 569 struct rpc_err *errp; 570 { 571 struct cu_data *cu; 572 573 _DIAGASSERT(cl != NULL); 574 _DIAGASSERT(errp != NULL); 575 576 cu = (struct cu_data *)cl->cl_private; 577 *errp = cu->cu_error; 578 } 579 580 static bool_t 581 clnt_dg_freeres(cl, xdr_res, res_ptr) 582 CLIENT *cl; 583 xdrproc_t xdr_res; 584 caddr_t res_ptr; 585 { 586 struct cu_data *cu; 587 XDR *xdrs; 588 bool_t dummy; 589 #ifdef _REENTRANT 590 sigset_t mask; 591 #endif 592 sigset_t newmask; 593 594 _DIAGASSERT(cl != NULL); 595 cu = (struct cu_data *)cl->cl_private; 596 xdrs = &(cu->cu_outxdrs); 597 598 sigfillset(&newmask); 599 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 600 mutex_lock(&clnt_fd_lock); 601 while (dg_fd_locks[cu->cu_fd]) 602 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 603 xdrs->x_op = XDR_FREE; 604 dummy = (*xdr_res)(xdrs, res_ptr); 605 mutex_unlock(&clnt_fd_lock); 606 thr_sigsetmask(SIG_SETMASK, &mask, NULL); 607 cond_signal(&dg_cv[cu->cu_fd]); 608 return (dummy); 609 } 610 611 /*ARGSUSED*/ 612 static void 613 clnt_dg_abort(h) 614 CLIENT *h; 615 { 616 } 617 618 static bool_t 619 clnt_dg_control(cl, request, info) 620 CLIENT *cl; 621 u_int request; 622 char *info; 623 { 624 struct cu_data *cu; 625 struct netbuf *addr; 626 #ifdef _REENTRANT 627 sigset_t mask; 628 #endif 629 sigset_t newmask; 630 631 _DIAGASSERT(cl != NULL); 632 /* info is handled below */ 633 634 cu = (struct cu_data *)cl->cl_private; 635 636 sigfillset(&newmask); 637 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 638 mutex_lock(&clnt_fd_lock); 639 while (dg_fd_locks[cu->cu_fd]) 640 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 641 dg_fd_locks[cu->cu_fd] = __rpc_lock_value; 642 mutex_unlock(&clnt_fd_lock); 643 switch (request) { 644 case CLSET_FD_CLOSE: 645 cu->cu_closeit = TRUE; 646 release_fd_lock(cu->cu_fd, mask); 647 return (TRUE); 648 case CLSET_FD_NCLOSE: 649 cu->cu_closeit = FALSE; 650 release_fd_lock(cu->cu_fd, mask); 651 return (TRUE); 652 } 653 654 /* for other requests which use info */ 655 if (info == NULL) { 656 release_fd_lock(cu->cu_fd, mask); 657 return (FALSE); 658 } 659 switch (request) { 660 case CLSET_TIMEOUT: 661 if (time_not_ok((struct timeval *)(void *)info)) { 662 release_fd_lock(cu->cu_fd, mask); 663 return (FALSE); 664 } 665 cu->cu_total = *(struct timeval *)(void *)info; 666 break; 667 case CLGET_TIMEOUT: 668 *(struct timeval *)(void *)info = cu->cu_total; 669 break; 670 case CLGET_SERVER_ADDR: /* Give him the fd address */ 671 /* Now obsolete. Only for backward compatibility */ 672 (void) memcpy(info, &cu->cu_raddr, (size_t)cu->cu_rlen); 673 break; 674 case CLSET_RETRY_TIMEOUT: 675 if (time_not_ok((struct timeval *)(void *)info)) { 676 release_fd_lock(cu->cu_fd, mask); 677 return (FALSE); 678 } 679 cu->cu_wait = *(struct timeval *)(void *)info; 680 break; 681 case CLGET_RETRY_TIMEOUT: 682 *(struct timeval *)(void *)info = cu->cu_wait; 683 break; 684 case CLGET_FD: 685 *(int *)(void *)info = cu->cu_fd; 686 break; 687 case CLGET_SVC_ADDR: 688 addr = (struct netbuf *)(void *)info; 689 addr->buf = &cu->cu_raddr; 690 addr->len = cu->cu_rlen; 691 addr->maxlen = sizeof cu->cu_raddr; 692 break; 693 case CLSET_SVC_ADDR: /* set to new address */ 694 addr = (struct netbuf *)(void *)info; 695 if (addr->len < sizeof cu->cu_raddr) { 696 release_fd_lock(cu->cu_fd, mask); 697 return (FALSE); 698 } 699 (void) memcpy(&cu->cu_raddr, addr->buf, addr->len); 700 cu->cu_rlen = addr->len; 701 break; 702 case CLGET_XID: 703 /* 704 * use the knowledge that xid is the 705 * first element in the call structure *. 706 * This will get the xid of the PREVIOUS call 707 */ 708 *(u_int32_t *)(void *)info = 709 ntohl(*(u_int32_t *)(void *)cu->cu_outbuf); 710 break; 711 712 case CLSET_XID: 713 /* This will set the xid of the NEXT call */ 714 *(u_int32_t *)(void *)cu->cu_outbuf = 715 htonl(*(u_int32_t *)(void *)info - 1); 716 /* decrement by 1 as clnt_dg_call() increments once */ 717 break; 718 719 case CLGET_VERS: 720 /* 721 * This RELIES on the information that, in the call body, 722 * the version number field is the fifth field from the 723 * begining of the RPC header. MUST be changed if the 724 * call_struct is changed 725 */ 726 *(u_int32_t *)(void *)info = 727 ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + 728 4 * BYTES_PER_XDR_UNIT)); 729 break; 730 731 case CLSET_VERS: 732 *(u_int32_t *)(void *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT) 733 = htonl(*(u_int32_t *)(void *)info); 734 break; 735 736 case CLGET_PROG: 737 /* 738 * This RELIES on the information that, in the call body, 739 * the program number field is the fourth field from the 740 * begining of the RPC header. MUST be changed if the 741 * call_struct is changed 742 */ 743 *(u_int32_t *)(void *)info = 744 ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + 745 3 * BYTES_PER_XDR_UNIT)); 746 break; 747 748 case CLSET_PROG: 749 *(u_int32_t *)(void *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT) 750 = htonl(*(u_int32_t *)(void *)info); 751 break; 752 753 default: 754 release_fd_lock(cu->cu_fd, mask); 755 return (FALSE); 756 } 757 release_fd_lock(cu->cu_fd, mask); 758 return (TRUE); 759 } 760 761 static void 762 clnt_dg_destroy(cl) 763 CLIENT *cl; 764 { 765 struct cu_data *cu; 766 int cu_fd; 767 #ifdef _REENTRANT 768 sigset_t mask; 769 #endif 770 sigset_t newmask; 771 772 _DIAGASSERT(cl != NULL); 773 774 cu = (struct cu_data *)cl->cl_private; 775 cu_fd = cu->cu_fd; 776 777 sigfillset(&newmask); 778 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 779 mutex_lock(&clnt_fd_lock); 780 while (dg_fd_locks[cu_fd]) 781 cond_wait(&dg_cv[cu_fd], &clnt_fd_lock); 782 if (cu->cu_closeit) 783 (void) close(cu_fd); 784 XDR_DESTROY(&(cu->cu_outxdrs)); 785 mem_free(cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz)); 786 if (cl->cl_netid && cl->cl_netid[0]) 787 mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 788 if (cl->cl_tp && cl->cl_tp[0]) 789 mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 790 mem_free(cl, sizeof (CLIENT)); 791 mutex_unlock(&clnt_fd_lock); 792 thr_sigsetmask(SIG_SETMASK, &mask, NULL); 793 cond_signal(&dg_cv[cu_fd]); 794 } 795 796 static struct clnt_ops * 797 clnt_dg_ops() 798 { 799 static struct clnt_ops ops; 800 #ifdef _REENTRANT 801 extern mutex_t ops_lock; 802 sigset_t mask; 803 #endif 804 sigset_t newmask; 805 806 /* VARIABLES PROTECTED BY ops_lock: ops */ 807 808 sigfillset(&newmask); 809 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 810 mutex_lock(&ops_lock); 811 if (ops.cl_call == NULL) { 812 ops.cl_call = clnt_dg_call; 813 ops.cl_abort = clnt_dg_abort; 814 ops.cl_geterr = clnt_dg_geterr; 815 ops.cl_freeres = clnt_dg_freeres; 816 ops.cl_destroy = clnt_dg_destroy; 817 ops.cl_control = clnt_dg_control; 818 } 819 mutex_unlock(&ops_lock); 820 thr_sigsetmask(SIG_SETMASK, &mask, NULL); 821 return (&ops); 822 } 823 824 /* 825 * Make sure that the time is not garbage. -1 value is allowed. 826 */ 827 static bool_t 828 time_not_ok(t) 829 struct timeval *t; 830 { 831 832 _DIAGASSERT(t != NULL); 833 834 return (t->tv_sec < -1 || t->tv_sec > 100000000 || 835 t->tv_usec < -1 || t->tv_usec > 1000000); 836 } 837 838 839 /* 840 * Convert from timevals (used by select) to milliseconds (used by poll). 841 */ 842 static int 843 __rpc_timeval_to_msec(t) 844 struct timeval *t; 845 { 846 int t1, tmp; 847 848 _DIAGASSERT(t != NULL); 849 850 /* 851 * We're really returning t->tv_sec * 1000 + (t->tv_usec / 1000) 852 * but try to do so efficiently. Note: 1000 = 1024 - 16 - 8. 853 */ 854 tmp = (int)t->tv_sec << 3; 855 t1 = -tmp; 856 t1 += t1 << 1; 857 t1 += tmp << 7; 858 if (t->tv_usec) 859 t1 += (int)(t->tv_usec / 1000); 860 861 return (t1); 862 } 863