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