1 /* $NetBSD: clnt_dg.c,v 1.33 2024/01/23 17:24:38 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2010, Oracle America, Inc. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following 14 * disclaimer in the documentation and/or other materials 15 * provided with the distribution. 16 * * Neither the name of the "Oracle America, Inc." nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 /* 34 * Copyright (c) 1986-1991 by Sun Microsystems Inc. 35 */ 36 37 /* #ident "@(#)clnt_dg.c 1.23 94/04/22 SMI" */ 38 39 #include <sys/cdefs.h> 40 #if defined(LIBC_SCCS) && !defined(lint) 41 #if 0 42 static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 43 #else 44 __RCSID("$NetBSD: clnt_dg.c,v 1.33 2024/01/23 17:24:38 christos Exp $"); 45 #endif 46 #endif 47 48 /* 49 * Implements a connectionless client side RPC. 50 */ 51 52 #include "namespace.h" 53 #include "reentrant.h" 54 #include <sys/poll.h> 55 #include <sys/types.h> 56 #include <sys/time.h> 57 #include <sys/socket.h> 58 #include <sys/ioctl.h> 59 #include <rpc/rpc.h> 60 #include <assert.h> 61 #include <errno.h> 62 #include <stdlib.h> 63 #include <string.h> 64 #include <signal.h> 65 #include <unistd.h> 66 #include <err.h> 67 68 #include "svc_fdset.h" 69 #include "rpc_internal.h" 70 71 #ifdef __weak_alias 72 __weak_alias(clnt_dg_create,_clnt_dg_create) 73 #endif 74 75 #define RPC_MAX_BACKOFF 30 /* seconds */ 76 77 78 static struct clnt_ops *clnt_dg_ops(void); 79 static bool_t time_not_ok(struct timeval *); 80 static enum clnt_stat clnt_dg_call(CLIENT *, rpcproc_t, xdrproc_t, 81 const char *, xdrproc_t, caddr_t, struct timeval); 82 static void clnt_dg_geterr(CLIENT *, struct rpc_err *); 83 static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, caddr_t); 84 static void clnt_dg_abort(CLIENT *); 85 static bool_t clnt_dg_control(CLIENT *, u_int, char *); 86 static void clnt_dg_destroy(CLIENT *); 87 88 89 90 91 /* 92 * This machinery implements per-fd locks for MT-safety. It is not 93 * sufficient to do per-CLIENT handle locks for MT-safety because a 94 * user may create more than one CLIENT handle with the same fd behind 95 * it. Therefore, we allocate an array of flags (dg_fd_locks), protected 96 * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables 97 * similarly protected. Dg_fd_lock[fd] == 1 => a call is active on some 98 * CLIENT handle created for that fd. 99 * The current implementation holds locks across the entire RPC and reply, 100 * including retransmissions. Yes, this is silly, and as soon as this 101 * code is proven to work, this should be the first thing fixed. One step 102 * at a time. 103 */ 104 static int *dg_fd_locks; 105 #ifdef _REENTRANT 106 #define __rpc_lock_value __isthreaded; 107 static cond_t *dg_cv; 108 #define release_fd_lock(fd, mask) { \ 109 mutex_lock(&clnt_fd_lock); \ 110 dg_fd_locks[fd] = 0; \ 111 mutex_unlock(&clnt_fd_lock); \ 112 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \ 113 cond_signal(&dg_cv[fd]); \ 114 } 115 #else 116 #define release_fd_lock(fd,mask) 117 #define __rpc_lock_value 0 118 #endif 119 120 static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; 121 122 /* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */ 123 124 /* 125 * Private data kept per client handle 126 */ 127 struct cu_data { 128 int cu_fd; /* connections fd */ 129 bool_t cu_closeit; /* opened by library */ 130 struct sockaddr_storage cu_raddr; /* remote address */ 131 int cu_rlen; 132 struct timeval cu_wait; /* retransmit interval */ 133 struct timeval cu_total; /* total time for the call */ 134 struct rpc_err cu_error; 135 XDR cu_outxdrs; 136 u_int cu_xdrpos; 137 u_int cu_sendsz; /* send size */ 138 char *cu_outbuf; 139 u_int cu_recvsz; /* recv size */ 140 struct pollfd cu_pfdp; 141 char cu_inbuf[1]; 142 }; 143 144 /* 145 * Connection less client creation returns with client handle parameters. 146 * Default options are set, which the user can change using clnt_control(). 147 * fd should be open and bound. 148 * NB: The rpch->cl_auth is initialized to null authentication. 149 * Caller may wish to set this something more useful. 150 * 151 * sendsz and recvsz are the maximum allowable packet sizes that can be 152 * sent and received. Normally they are the same, but they can be 153 * changed to improve the program efficiency and buffer allocation. 154 * If they are 0, use the transport default. 155 * 156 * If svcaddr is NULL, returns NULL. 157 */ 158 CLIENT * 159 clnt_dg_create( 160 int fd, /* open file descriptor */ 161 const struct netbuf *svcaddr, /* servers address */ 162 rpcprog_t program, /* program number */ 163 rpcvers_t version, /* version number */ 164 u_int sendsz, /* buffer recv size */ 165 u_int recvsz) /* buffer send size */ 166 { 167 CLIENT *cl = NULL; /* client handle */ 168 struct cu_data *cu = NULL; /* private data */ 169 struct rpc_msg call_msg; 170 #ifdef _REENTRANT 171 sigset_t mask; 172 #endif 173 sigset_t newmask; 174 struct __rpc_sockinfo si; 175 int one = 1; 176 177 __clnt_sigfillset(&newmask); 178 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 179 mutex_lock(&clnt_fd_lock); 180 if (dg_fd_locks == NULL) { 181 #ifdef _REENTRANT 182 size_t cv_allocsz; 183 #endif 184 size_t fd_allocsz; 185 int dtbsize = __rpc_dtbsize(); 186 187 fd_allocsz = dtbsize * sizeof (int); 188 dg_fd_locks = mem_alloc(fd_allocsz); 189 if (dg_fd_locks == NULL) { 190 goto err0; 191 } else 192 memset(dg_fd_locks, '\0', fd_allocsz); 193 194 #ifdef _REENTRANT 195 cv_allocsz = dtbsize * sizeof (cond_t); 196 dg_cv = mem_alloc(cv_allocsz); 197 if (dg_cv == NULL) { 198 mem_free(dg_fd_locks, fd_allocsz); 199 dg_fd_locks = NULL; 200 goto err0; 201 } else { 202 int i; 203 204 for (i = 0; i < dtbsize; i++) 205 cond_init(&dg_cv[i], 0, (void *) 0); 206 } 207 #endif 208 } 209 210 mutex_unlock(&clnt_fd_lock); 211 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 212 213 if (svcaddr == NULL) { 214 rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 215 return (NULL); 216 } 217 218 if (!__rpc_fd2sockinfo(fd, &si)) { 219 rpc_createerr.cf_stat = RPC_TLIERROR; 220 rpc_createerr.cf_error.re_errno = 0; 221 return (NULL); 222 } 223 /* 224 * Find the receive and the send size 225 */ 226 sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 227 recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 228 if ((sendsz == 0) || (recvsz == 0)) { 229 rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ 230 rpc_createerr.cf_error.re_errno = 0; 231 return (NULL); 232 } 233 234 if ((cl = mem_alloc(sizeof (CLIENT))) == NULL) 235 goto err1; 236 /* 237 * Should be multiple of 4 for XDR. 238 */ 239 sendsz = ((sendsz + 3) / 4) * 4; 240 recvsz = ((recvsz + 3) / 4) * 4; 241 cu = malloc(sizeof (*cu) + sendsz + recvsz); 242 if (cu == NULL) 243 goto err1; 244 memset(cu, 0, sizeof(*cu)); 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 #ifdef RUMP_RPC 250 cu->cu_wait.tv_sec = 15; /* heuristically chosen */ 251 cu->cu_wait.tv_usec = 0; 252 #else 253 cu->cu_wait.tv_sec = 0; /* for testing, 10x / second */ 254 cu->cu_wait.tv_usec = 100000; 255 #endif 256 cu->cu_total.tv_sec = -1; 257 cu->cu_total.tv_usec = -1; 258 cu->cu_sendsz = sendsz; 259 cu->cu_recvsz = recvsz; 260 call_msg.rm_xid = __RPC_GETXID(); 261 call_msg.rm_call.cb_prog = program; 262 call_msg.rm_call.cb_vers = version; 263 xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); 264 if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { 265 rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ 266 rpc_createerr.cf_error.re_errno = 0; 267 goto err2; 268 } 269 cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); 270 271 /* XXX fvdl - do we still want this? */ 272 #if 0 273 (void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf); 274 #endif 275 ioctl(fd, FIONBIO, (char *)(void *)&one); 276 277 /* 278 * By default, closeit is always FALSE. It is users responsibility 279 * to do a close on it, else the user may use clnt_control 280 * to let clnt_destroy do it for him/her. 281 */ 282 cu->cu_closeit = FALSE; 283 cu->cu_fd = fd; 284 cu->cu_pfdp.fd = cu->cu_fd; 285 cu->cu_pfdp.events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND; 286 cl->cl_ops = clnt_dg_ops(); 287 cl->cl_private = (caddr_t)(void *)cu; 288 cl->cl_auth = authnone_create(); 289 cl->cl_tp = NULL; 290 cl->cl_netid = NULL; 291 return (cl); 292 err0: 293 mutex_unlock(&clnt_fd_lock); 294 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 295 err1: 296 warnx(mem_err_clnt_dg); 297 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 298 rpc_createerr.cf_error.re_errno = errno; 299 err2: 300 if (cl) { 301 mem_free(cl, sizeof (CLIENT)); 302 if (cu) 303 mem_free(cu, sizeof (*cu) + sendsz + recvsz); 304 } 305 return (NULL); 306 } 307 308 static enum clnt_stat 309 clnt_dg_call( 310 CLIENT * cl, /* client handle */ 311 rpcproc_t proc, /* procedure number */ 312 xdrproc_t xargs, /* xdr routine for args */ 313 const char * argsp, /* pointer to args */ 314 xdrproc_t xresults, /* xdr routine for results */ 315 caddr_t resultsp, /* pointer to results */ 316 struct timeval utimeout) /* seconds to wait before giving up */ 317 { 318 struct cu_data *cu; 319 XDR *xdrs; 320 size_t outlen; 321 struct rpc_msg reply_msg; 322 XDR reply_xdrs; 323 bool_t ok; 324 int nrefreshes = 2; /* number of times to refresh cred */ 325 struct timeval timeout; 326 struct timeval retransmit_time; 327 struct timeval next_sendtime, starttime, time_waited, tv; 328 #ifdef _REENTRANT 329 sigset_t mask, *maskp = &mask; 330 #else 331 sigset_t *maskp = NULL; 332 #endif 333 sigset_t newmask; 334 ssize_t recvlen = 0; 335 struct timespec ts; 336 int n; 337 338 _DIAGASSERT(cl != NULL); 339 340 cu = (struct cu_data *)cl->cl_private; 341 342 __clnt_sigfillset(&newmask); 343 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 344 mutex_lock(&clnt_fd_lock); 345 while (dg_fd_locks[cu->cu_fd]) 346 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 347 dg_fd_locks[cu->cu_fd] = __rpc_lock_value; 348 mutex_unlock(&clnt_fd_lock); 349 if (cu->cu_total.tv_usec == -1) { 350 timeout = utimeout; /* use supplied timeout */ 351 } else { 352 timeout = cu->cu_total; /* use default timeout */ 353 } 354 355 time_waited.tv_sec = 0; 356 time_waited.tv_usec = 0; 357 retransmit_time = next_sendtime = cu->cu_wait; 358 gettimeofday(&starttime, NULL); 359 360 call_again: 361 xdrs = &(cu->cu_outxdrs); 362 xdrs->x_op = XDR_ENCODE; 363 XDR_SETPOS(xdrs, cu->cu_xdrpos); 364 /* 365 * the transaction is the first thing in the out buffer 366 */ 367 (*(u_int32_t *)(void *)(cu->cu_outbuf))++; 368 if ((! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 369 (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || 370 (! (*xargs)(xdrs, __UNCONST(argsp)))) { 371 cu->cu_error.re_status = RPC_CANTENCODEARGS; 372 goto out; 373 } 374 outlen = (size_t)XDR_GETPOS(xdrs); 375 376 send_again: 377 if ((size_t)sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0, 378 (struct sockaddr *)(void *)&cu->cu_raddr, (socklen_t)cu->cu_rlen) 379 != outlen) { 380 cu->cu_error.re_errno = errno; 381 cu->cu_error.re_status = RPC_CANTSEND; 382 goto out; 383 } 384 385 /* 386 * Hack to provide rpc-based message passing 387 */ 388 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 389 cu->cu_error.re_status = RPC_TIMEDOUT; 390 goto out; 391 } 392 /* 393 * sub-optimal code appears here because we have 394 * some clock time to spare while the packets are in flight. 395 * (We assume that this is actually only executed once.) 396 */ 397 reply_msg.acpted_rply.ar_verf = _null_auth; 398 reply_msg.acpted_rply.ar_results.where = resultsp; 399 reply_msg.acpted_rply.ar_results.proc = xresults; 400 401 402 for (;;) { 403 /* Decide how long to wait. */ 404 if (timercmp(&next_sendtime, &timeout, <)) 405 timersub(&next_sendtime, &time_waited, &tv); 406 else 407 timersub(&timeout, &time_waited, &tv); 408 if (tv.tv_sec < 0 || tv.tv_usec < 0) 409 tv.tv_sec = tv.tv_usec = 0; 410 TIMEVAL_TO_TIMESPEC(&tv, &ts); 411 412 n = pollts(&cu->cu_pfdp, 1, &ts, maskp); 413 if (n == 1) { 414 /* We have some data now */ 415 do { 416 recvlen = recvfrom(cu->cu_fd, cu->cu_inbuf, 417 cu->cu_recvsz, 0, NULL, NULL); 418 } while (recvlen < 0 && errno == EINTR); 419 420 if (recvlen < 0 && errno != EWOULDBLOCK) { 421 cu->cu_error.re_errno = errno; 422 cu->cu_error.re_status = RPC_CANTRECV; 423 goto out; 424 } 425 if (recvlen >= (ssize_t)sizeof(uint32_t)) { 426 if (memcmp(cu->cu_inbuf, cu->cu_outbuf, 427 sizeof(uint32_t)) == 0) 428 /* Assume we have the proper reply. */ 429 break; 430 } 431 } 432 if (n == -1) { 433 cu->cu_error.re_errno = errno; 434 cu->cu_error.re_status = RPC_CANTRECV; 435 goto out; 436 } 437 438 gettimeofday(&tv, NULL); 439 timersub(&tv, &starttime, &time_waited); 440 441 /* Check for timeout. */ 442 if (timercmp(&time_waited, &timeout, >)) { 443 cu->cu_error.re_status = RPC_TIMEDOUT; 444 goto out; 445 } 446 447 /* Retransmit if necessary. */ 448 if (timercmp(&time_waited, &next_sendtime, >)) { 449 /* update retransmit_time */ 450 if (retransmit_time.tv_sec < RPC_MAX_BACKOFF) 451 timeradd(&retransmit_time, &retransmit_time, 452 &retransmit_time); 453 timeradd(&next_sendtime, &retransmit_time, 454 &next_sendtime); 455 goto send_again; 456 } 457 } 458 459 /* 460 * now decode and validate the response 461 */ 462 463 xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)recvlen, XDR_DECODE); 464 ok = xdr_replymsg(&reply_xdrs, &reply_msg); 465 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ 466 if (ok) { 467 if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 468 (reply_msg.acpted_rply.ar_stat == SUCCESS)) 469 cu->cu_error.re_status = RPC_SUCCESS; 470 else 471 _seterr_reply(&reply_msg, &(cu->cu_error)); 472 473 if (cu->cu_error.re_status == RPC_SUCCESS) { 474 if (! AUTH_VALIDATE(cl->cl_auth, 475 &reply_msg.acpted_rply.ar_verf)) { 476 cu->cu_error.re_status = RPC_AUTHERROR; 477 cu->cu_error.re_why = AUTH_INVALIDRESP; 478 } 479 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 480 xdrs->x_op = XDR_FREE; 481 (void) xdr_opaque_auth(xdrs, 482 &(reply_msg.acpted_rply.ar_verf)); 483 } 484 } /* end successful completion */ 485 /* 486 * If unsuccessful AND error is an authentication error 487 * then refresh credentials and try again, else break 488 */ 489 else if (cu->cu_error.re_status == RPC_AUTHERROR) 490 /* maybe our credentials need to be refreshed ... */ 491 if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) { 492 nrefreshes--; 493 goto call_again; 494 } 495 /* end of unsuccessful completion */ 496 } /* end of valid reply message */ 497 else { 498 cu->cu_error.re_status = RPC_CANTDECODERES; 499 500 } 501 out: 502 release_fd_lock(cu->cu_fd, mask); 503 return (cu->cu_error.re_status); 504 } 505 506 static void 507 clnt_dg_geterr(CLIENT *cl, struct rpc_err *errp) 508 { 509 struct cu_data *cu; 510 511 _DIAGASSERT(cl != NULL); 512 _DIAGASSERT(errp != NULL); 513 514 cu = (struct cu_data *)cl->cl_private; 515 *errp = cu->cu_error; 516 } 517 518 static bool_t 519 clnt_dg_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) 520 { 521 struct cu_data *cu; 522 XDR *xdrs; 523 bool_t dummy; 524 #ifdef _REENTRANT 525 sigset_t mask; 526 #endif 527 sigset_t newmask; 528 529 _DIAGASSERT(cl != NULL); 530 cu = (struct cu_data *)cl->cl_private; 531 xdrs = &(cu->cu_outxdrs); 532 533 __clnt_sigfillset(&newmask); 534 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 535 mutex_lock(&clnt_fd_lock); 536 while (dg_fd_locks[cu->cu_fd]) 537 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 538 xdrs->x_op = XDR_FREE; 539 dummy = (*xdr_res)(xdrs, res_ptr); 540 mutex_unlock(&clnt_fd_lock); 541 thr_sigsetmask(SIG_SETMASK, &mask, NULL); 542 cond_signal(&dg_cv[cu->cu_fd]); 543 return (dummy); 544 } 545 546 /*ARGSUSED*/ 547 static void 548 clnt_dg_abort(CLIENT *h) 549 { 550 } 551 552 static bool_t 553 clnt_dg_control(CLIENT *cl, u_int request, char *info) 554 { 555 struct cu_data *cu; 556 struct netbuf *addr; 557 #ifdef _REENTRANT 558 sigset_t mask; 559 #endif 560 sigset_t newmask; 561 562 _DIAGASSERT(cl != NULL); 563 /* info is handled below */ 564 565 cu = (struct cu_data *)cl->cl_private; 566 567 __clnt_sigfillset(&newmask); 568 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 569 mutex_lock(&clnt_fd_lock); 570 while (dg_fd_locks[cu->cu_fd]) 571 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 572 dg_fd_locks[cu->cu_fd] = __rpc_lock_value; 573 mutex_unlock(&clnt_fd_lock); 574 switch (request) { 575 case CLSET_FD_CLOSE: 576 cu->cu_closeit = TRUE; 577 release_fd_lock(cu->cu_fd, mask); 578 return (TRUE); 579 case CLSET_FD_NCLOSE: 580 cu->cu_closeit = FALSE; 581 release_fd_lock(cu->cu_fd, mask); 582 return (TRUE); 583 } 584 585 /* for other requests which use info */ 586 if (info == NULL) { 587 release_fd_lock(cu->cu_fd, mask); 588 return (FALSE); 589 } 590 switch (request) { 591 case CLSET_TIMEOUT: 592 if (time_not_ok((struct timeval *)(void *)info)) { 593 release_fd_lock(cu->cu_fd, mask); 594 return (FALSE); 595 } 596 cu->cu_total = *(struct timeval *)(void *)info; 597 break; 598 case CLGET_TIMEOUT: 599 *(struct timeval *)(void *)info = cu->cu_total; 600 break; 601 case CLGET_SERVER_ADDR: /* Give him the fd address */ 602 /* Now obsolete. Only for backward compatibility */ 603 (void) memcpy(info, &cu->cu_raddr, (size_t)cu->cu_rlen); 604 break; 605 case CLSET_RETRY_TIMEOUT: 606 if (time_not_ok((struct timeval *)(void *)info)) { 607 release_fd_lock(cu->cu_fd, mask); 608 return (FALSE); 609 } 610 cu->cu_wait = *(struct timeval *)(void *)info; 611 break; 612 case CLGET_RETRY_TIMEOUT: 613 *(struct timeval *)(void *)info = cu->cu_wait; 614 break; 615 case CLGET_FD: 616 *(int *)(void *)info = cu->cu_fd; 617 break; 618 case CLGET_SVC_ADDR: 619 addr = (struct netbuf *)(void *)info; 620 addr->buf = &cu->cu_raddr; 621 addr->len = cu->cu_rlen; 622 addr->maxlen = sizeof cu->cu_raddr; 623 break; 624 case CLSET_SVC_ADDR: /* set to new address */ 625 addr = (struct netbuf *)(void *)info; 626 if (addr->len < sizeof cu->cu_raddr) { 627 release_fd_lock(cu->cu_fd, mask); 628 return (FALSE); 629 } 630 (void) memcpy(&cu->cu_raddr, addr->buf, (size_t)addr->len); 631 cu->cu_rlen = addr->len; 632 break; 633 case CLGET_XID: 634 /* 635 * use the knowledge that xid is the 636 * first element in the call structure *. 637 * This will get the xid of the PREVIOUS call 638 */ 639 *(u_int32_t *)(void *)info = 640 ntohl(*(u_int32_t *)(void *)cu->cu_outbuf); 641 break; 642 643 case CLSET_XID: 644 /* This will set the xid of the NEXT call */ 645 *(u_int32_t *)(void *)cu->cu_outbuf = 646 htonl(*(u_int32_t *)(void *)info - 1); 647 /* decrement by 1 as clnt_dg_call() increments once */ 648 break; 649 650 case CLGET_VERS: 651 /* 652 * This RELIES on the information that, in the call body, 653 * the version number field is the fifth field from the 654 * beginning of the RPC header. MUST be changed if the 655 * call_struct is changed 656 */ 657 *(u_int32_t *)(void *)info = 658 ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + 659 4 * BYTES_PER_XDR_UNIT)); 660 break; 661 662 case CLSET_VERS: 663 *(u_int32_t *)(void *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT) 664 = htonl(*(u_int32_t *)(void *)info); 665 break; 666 667 case CLGET_PROG: 668 /* 669 * This RELIES on the information that, in the call body, 670 * the program number field is the fourth field from the 671 * beginning of the RPC header. MUST be changed if the 672 * call_struct is changed 673 */ 674 *(u_int32_t *)(void *)info = 675 ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + 676 3 * BYTES_PER_XDR_UNIT)); 677 break; 678 679 case CLSET_PROG: 680 *(u_int32_t *)(void *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT) 681 = htonl(*(u_int32_t *)(void *)info); 682 break; 683 684 default: 685 release_fd_lock(cu->cu_fd, mask); 686 return (FALSE); 687 } 688 release_fd_lock(cu->cu_fd, mask); 689 return (TRUE); 690 } 691 692 static void 693 clnt_dg_destroy(CLIENT *cl) 694 { 695 struct cu_data *cu; 696 int cu_fd; 697 #ifdef _REENTRANT 698 sigset_t mask; 699 #endif 700 sigset_t newmask; 701 702 _DIAGASSERT(cl != NULL); 703 704 cu = (struct cu_data *)cl->cl_private; 705 cu_fd = cu->cu_fd; 706 707 __clnt_sigfillset(&newmask); 708 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 709 mutex_lock(&clnt_fd_lock); 710 while (dg_fd_locks[cu_fd]) 711 cond_wait(&dg_cv[cu_fd], &clnt_fd_lock); 712 if (cu->cu_closeit) 713 (void) close(cu_fd); 714 XDR_DESTROY(&(cu->cu_outxdrs)); 715 mem_free(cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz)); 716 if (cl->cl_netid && cl->cl_netid[0]) 717 mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 718 if (cl->cl_tp && cl->cl_tp[0]) 719 mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 720 mem_free(cl, sizeof (CLIENT)); 721 mutex_unlock(&clnt_fd_lock); 722 thr_sigsetmask(SIG_SETMASK, &mask, NULL); 723 cond_signal(&dg_cv[cu_fd]); 724 } 725 726 static struct clnt_ops * 727 clnt_dg_ops(void) 728 { 729 static struct clnt_ops ops; 730 #ifdef _REENTRANT 731 sigset_t mask; 732 #endif 733 sigset_t newmask; 734 735 /* VARIABLES PROTECTED BY ops_lock: ops */ 736 737 __clnt_sigfillset(&newmask); 738 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 739 mutex_lock(&ops_lock); 740 if (ops.cl_call == NULL) { 741 ops.cl_call = clnt_dg_call; 742 ops.cl_abort = clnt_dg_abort; 743 ops.cl_geterr = clnt_dg_geterr; 744 ops.cl_freeres = clnt_dg_freeres; 745 ops.cl_destroy = clnt_dg_destroy; 746 ops.cl_control = clnt_dg_control; 747 } 748 mutex_unlock(&ops_lock); 749 thr_sigsetmask(SIG_SETMASK, &mask, NULL); 750 return (&ops); 751 } 752 753 /* 754 * Make sure that the time is not garbage. -1 value is allowed. 755 */ 756 static bool_t 757 time_not_ok(struct timeval *t) 758 { 759 760 _DIAGASSERT(t != NULL); 761 762 return (t->tv_sec < -1 || t->tv_sec > 100000000 || 763 t->tv_usec < -1 || t->tv_usec > 1000000); 764 } 765