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