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