1 /* $NetBSD: clnt_vc.c,v 1.21 2013/03/11 20:19:29 tron 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 #include <sys/cdefs.h> 35 #if defined(LIBC_SCCS) && !defined(lint) 36 #if 0 37 static char *sccsid = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro"; 38 static char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 39 static char sccsid[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 40 #else 41 __RCSID("$NetBSD: clnt_vc.c,v 1.21 2013/03/11 20:19:29 tron Exp $"); 42 #endif 43 #endif 44 45 /* 46 * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 47 * 48 * Copyright (C) 1984, Sun Microsystems, Inc. 49 * 50 * TCP based RPC supports 'batched calls'. 51 * A sequence of calls may be batched-up in a send buffer. The rpc call 52 * return immediately to the client even though the call was not necessarily 53 * sent. The batching occurs if the results' xdr routine is NULL (0) AND 54 * the rpc timeout value is zero (see clnt.h, rpc). 55 * 56 * Clients should NOT casually batch calls that in fact return results; that is, 57 * the server side should be aware that a call is batched and not produce any 58 * return message. Batched calls that produce many result messages can 59 * deadlock (netlock) the client and the server.... 60 * 61 * Now go hang yourself. 62 */ 63 64 #include "namespace.h" 65 #include "reentrant.h" 66 #include <sys/types.h> 67 #include <sys/poll.h> 68 #include <sys/socket.h> 69 70 #include <assert.h> 71 #include <err.h> 72 #include <errno.h> 73 #include <netdb.h> 74 #include <stdio.h> 75 #include <stdlib.h> 76 #include <string.h> 77 #include <unistd.h> 78 #include <signal.h> 79 80 #include <rpc/rpc.h> 81 82 #include "svc_fdset.h" 83 #include "rpc_internal.h" 84 85 #ifdef __weak_alias 86 __weak_alias(clnt_vc_create,_clnt_vc_create) 87 #endif 88 89 #define MCALL_MSG_SIZE 24 90 91 static enum clnt_stat clnt_vc_call(CLIENT *, rpcproc_t, xdrproc_t, 92 const char *, xdrproc_t, caddr_t, struct timeval); 93 static void clnt_vc_geterr(CLIENT *, struct rpc_err *); 94 static bool_t clnt_vc_freeres(CLIENT *, xdrproc_t, caddr_t); 95 static void clnt_vc_abort(CLIENT *); 96 static bool_t clnt_vc_control(CLIENT *, u_int, char *); 97 static void clnt_vc_destroy(CLIENT *); 98 static struct clnt_ops *clnt_vc_ops(void); 99 static bool_t time_not_ok(struct timeval *); 100 static int read_vc(caddr_t, caddr_t, int); 101 static int write_vc(caddr_t, caddr_t, int); 102 103 struct ct_data { 104 int ct_fd; 105 bool_t ct_closeit; 106 struct timeval ct_wait; 107 bool_t ct_waitset; /* wait set by clnt_control? */ 108 struct netbuf ct_addr; 109 struct rpc_err ct_error; 110 union { 111 char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */ 112 u_int32_t ct_mcalli; 113 } ct_u; 114 u_int ct_mpos; /* pos after marshal */ 115 XDR ct_xdrs; 116 }; 117 118 /* 119 * This machinery implements per-fd locks for MT-safety. It is not 120 * sufficient to do per-CLIENT handle locks for MT-safety because a 121 * user may create more than one CLIENT handle with the same fd behind 122 * it. Therfore, we allocate an array of flags (vc_fd_locks), protected 123 * by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables 124 * similarly protected. Vc_fd_lock[fd] == 1 => a call is activte on some 125 * CLIENT handle created for that fd. 126 * The current implementation holds locks across the entire RPC and reply. 127 * Yes, this is silly, and as soon as this code is proven to work, this 128 * should be the first thing fixed. One step at a time. 129 */ 130 #ifdef _REENTRANT 131 static int *vc_fd_locks; 132 #define __rpc_lock_value __isthreaded; 133 extern mutex_t clnt_fd_lock; 134 static cond_t *vc_cv; 135 #define release_fd_lock(fd, mask) { \ 136 mutex_lock(&clnt_fd_lock); \ 137 vc_fd_locks[fd] = 0; \ 138 mutex_unlock(&clnt_fd_lock); \ 139 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \ 140 cond_signal(&vc_cv[fd]); \ 141 } 142 #else 143 #define release_fd_lock(fd,mask) 144 #define __rpc_lock_value 0 145 #endif 146 147 148 /* 149 * Create a client handle for a connection. 150 * Default options are set, which the user can change using clnt_control()'s. 151 * The rpc/vc package does buffering similar to stdio, so the client 152 * must pick send and receive buffer sizes, 0 => use the default. 153 * NB: fd is copied into a private area. 154 * NB: The rpch->cl_auth is set null authentication. Caller may wish to 155 * set this something more useful. 156 * 157 * fd should be an open socket 158 */ 159 CLIENT * 160 clnt_vc_create( 161 int fd, 162 const struct netbuf *raddr, 163 rpcprog_t prog, 164 rpcvers_t vers, 165 u_int sendsz, 166 u_int recvsz 167 ) 168 { 169 CLIENT *h; 170 struct ct_data *ct = NULL; 171 struct rpc_msg call_msg; 172 #ifdef _REENTRANT 173 sigset_t mask; 174 #endif 175 sigset_t newmask; 176 struct sockaddr_storage ss; 177 socklen_t slen; 178 struct __rpc_sockinfo si; 179 180 _DIAGASSERT(raddr != NULL); 181 182 h = mem_alloc(sizeof(*h)); 183 if (h == NULL) { 184 warnx("clnt_vc_create: out of memory"); 185 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 186 rpc_createerr.cf_error.re_errno = errno; 187 goto fooy; 188 } 189 ct = mem_alloc(sizeof(*ct)); 190 if (ct == NULL) { 191 warnx("clnt_vc_create: out of memory"); 192 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 193 rpc_createerr.cf_error.re_errno = errno; 194 goto fooy; 195 } 196 197 sigfillset(&newmask); 198 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 199 #ifdef _REENTRANT 200 mutex_lock(&clnt_fd_lock); 201 if (vc_fd_locks == NULL) { 202 size_t cv_allocsz, fd_allocsz; 203 int dtbsize = __rpc_dtbsize(); 204 205 fd_allocsz = dtbsize * sizeof (int); 206 vc_fd_locks = mem_alloc(fd_allocsz); 207 if (vc_fd_locks == NULL) { 208 mutex_unlock(&clnt_fd_lock); 209 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 210 goto fooy; 211 } else 212 memset(vc_fd_locks, '\0', fd_allocsz); 213 214 _DIAGASSERT(vc_cv == NULL); 215 cv_allocsz = dtbsize * sizeof (cond_t); 216 vc_cv = mem_alloc(cv_allocsz); 217 if (vc_cv == NULL) { 218 mem_free(vc_fd_locks, fd_allocsz); 219 vc_fd_locks = NULL; 220 mutex_unlock(&clnt_fd_lock); 221 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 222 goto fooy; 223 } else { 224 int i; 225 226 for (i = 0; i < dtbsize; i++) 227 cond_init(&vc_cv[i], 0, (void *) 0); 228 } 229 } else 230 _DIAGASSERT(vc_cv != NULL); 231 #endif 232 233 /* 234 * XXX - fvdl connecting while holding a mutex? 235 */ 236 slen = sizeof ss; 237 if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 238 if (errno != ENOTCONN) { 239 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 240 rpc_createerr.cf_error.re_errno = errno; 241 mutex_unlock(&clnt_fd_lock); 242 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 243 goto fooy; 244 } 245 if (connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){ 246 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 247 rpc_createerr.cf_error.re_errno = errno; 248 mutex_unlock(&clnt_fd_lock); 249 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 250 goto fooy; 251 } 252 } 253 mutex_unlock(&clnt_fd_lock); 254 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 255 if (!__rpc_fd2sockinfo(fd, &si)) 256 goto fooy; 257 258 ct->ct_closeit = FALSE; 259 260 /* 261 * Set up private data struct 262 */ 263 ct->ct_fd = fd; 264 ct->ct_wait.tv_usec = 0; 265 ct->ct_waitset = FALSE; 266 ct->ct_addr.buf = malloc((size_t)raddr->maxlen); 267 if (ct->ct_addr.buf == NULL) 268 goto fooy; 269 memcpy(ct->ct_addr.buf, raddr->buf, (size_t)raddr->len); 270 ct->ct_addr.len = raddr->len; 271 ct->ct_addr.maxlen = raddr->maxlen; 272 273 /* 274 * Initialize call message 275 */ 276 call_msg.rm_xid = __RPC_GETXID(); 277 call_msg.rm_direction = CALL; 278 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 279 call_msg.rm_call.cb_prog = (u_int32_t)prog; 280 call_msg.rm_call.cb_vers = (u_int32_t)vers; 281 282 /* 283 * pre-serialize the static part of the call msg and stash it away 284 */ 285 xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE, 286 XDR_ENCODE); 287 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 288 if (ct->ct_closeit) { 289 (void)close(fd); 290 } 291 goto fooy; 292 } 293 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 294 XDR_DESTROY(&(ct->ct_xdrs)); 295 296 /* 297 * Create a client handle which uses xdrrec for serialization 298 * and authnone for authentication. 299 */ 300 h->cl_ops = clnt_vc_ops(); 301 h->cl_private = ct; 302 h->cl_auth = authnone_create(); 303 sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 304 recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 305 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 306 h->cl_private, read_vc, write_vc); 307 return (h); 308 309 fooy: 310 /* 311 * Something goofed, free stuff and barf 312 */ 313 if (ct) 314 mem_free(ct, sizeof(struct ct_data)); 315 if (h) 316 mem_free(h, sizeof(CLIENT)); 317 return (NULL); 318 } 319 320 static enum clnt_stat 321 clnt_vc_call( 322 CLIENT *h, 323 rpcproc_t proc, 324 xdrproc_t xdr_args, 325 const char *args_ptr, 326 xdrproc_t xdr_results, 327 caddr_t results_ptr, 328 struct timeval timeout 329 ) 330 { 331 struct ct_data *ct; 332 XDR *xdrs; 333 struct rpc_msg reply_msg; 334 u_int32_t x_id; 335 u_int32_t *msg_x_id; 336 bool_t shipnow; 337 int refreshes = 2; 338 #ifdef _REENTRANT 339 sigset_t mask, newmask; 340 #endif 341 342 _DIAGASSERT(h != NULL); 343 344 ct = (struct ct_data *) h->cl_private; 345 346 #ifdef _REENTRANT 347 sigfillset(&newmask); 348 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 349 mutex_lock(&clnt_fd_lock); 350 while (vc_fd_locks[ct->ct_fd]) 351 cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 352 vc_fd_locks[ct->ct_fd] = __rpc_lock_value; 353 mutex_unlock(&clnt_fd_lock); 354 #endif 355 356 xdrs = &(ct->ct_xdrs); 357 msg_x_id = &ct->ct_u.ct_mcalli; 358 359 if (!ct->ct_waitset) { 360 if (time_not_ok(&timeout) == FALSE) 361 ct->ct_wait = timeout; 362 } 363 364 shipnow = 365 (xdr_results == NULL && timeout.tv_sec == 0 366 && timeout.tv_usec == 0) ? FALSE : TRUE; 367 368 call_again: 369 xdrs->x_op = XDR_ENCODE; 370 ct->ct_error.re_status = RPC_SUCCESS; 371 x_id = ntohl(--(*msg_x_id)); 372 if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) || 373 (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 374 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 375 (! (*xdr_args)(xdrs, __UNCONST(args_ptr)))) { 376 if (ct->ct_error.re_status == RPC_SUCCESS) 377 ct->ct_error.re_status = RPC_CANTENCODEARGS; 378 (void)xdrrec_endofrecord(xdrs, TRUE); 379 release_fd_lock(ct->ct_fd, mask); 380 return (ct->ct_error.re_status); 381 } 382 if (! xdrrec_endofrecord(xdrs, shipnow)) { 383 release_fd_lock(ct->ct_fd, mask); 384 return (ct->ct_error.re_status = RPC_CANTSEND); 385 } 386 if (! shipnow) { 387 release_fd_lock(ct->ct_fd, mask); 388 return (RPC_SUCCESS); 389 } 390 /* 391 * Hack to provide rpc-based message passing 392 */ 393 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 394 release_fd_lock(ct->ct_fd, mask); 395 return(ct->ct_error.re_status = RPC_TIMEDOUT); 396 } 397 398 399 /* 400 * Keep receiving until we get a valid transaction id 401 */ 402 xdrs->x_op = XDR_DECODE; 403 for (;;) { 404 reply_msg.acpted_rply.ar_verf = _null_auth; 405 reply_msg.acpted_rply.ar_results.where = NULL; 406 reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 407 if (! xdrrec_skiprecord(xdrs)) { 408 release_fd_lock(ct->ct_fd, mask); 409 return (ct->ct_error.re_status); 410 } 411 /* now decode and validate the response header */ 412 if (! xdr_replymsg(xdrs, &reply_msg)) { 413 if (ct->ct_error.re_status == RPC_SUCCESS) 414 continue; 415 release_fd_lock(ct->ct_fd, mask); 416 return (ct->ct_error.re_status); 417 } 418 if (reply_msg.rm_xid == x_id) 419 break; 420 } 421 422 /* 423 * process header 424 */ 425 _seterr_reply(&reply_msg, &(ct->ct_error)); 426 if (ct->ct_error.re_status == RPC_SUCCESS) { 427 if (! AUTH_VALIDATE(h->cl_auth, 428 &reply_msg.acpted_rply.ar_verf)) { 429 ct->ct_error.re_status = RPC_AUTHERROR; 430 ct->ct_error.re_why = AUTH_INVALIDRESP; 431 } else if (! (*xdr_results)(xdrs, results_ptr)) { 432 if (ct->ct_error.re_status == RPC_SUCCESS) 433 ct->ct_error.re_status = RPC_CANTDECODERES; 434 } 435 /* free verifier ... */ 436 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 437 xdrs->x_op = XDR_FREE; 438 (void)xdr_opaque_auth(xdrs, 439 &(reply_msg.acpted_rply.ar_verf)); 440 } 441 } /* end successful completion */ 442 else { 443 /* maybe our credentials need to be refreshed ... */ 444 if (refreshes-- && AUTH_REFRESH(h->cl_auth)) 445 goto call_again; 446 } /* end of unsuccessful completion */ 447 release_fd_lock(ct->ct_fd, mask); 448 return (ct->ct_error.re_status); 449 } 450 451 static void 452 clnt_vc_geterr( 453 CLIENT *h, 454 struct rpc_err *errp 455 ) 456 { 457 struct ct_data *ct; 458 459 _DIAGASSERT(h != NULL); 460 _DIAGASSERT(errp != NULL); 461 462 ct = (struct ct_data *) h->cl_private; 463 *errp = ct->ct_error; 464 } 465 466 static bool_t 467 clnt_vc_freeres( 468 CLIENT *cl, 469 xdrproc_t xdr_res, 470 caddr_t res_ptr 471 ) 472 { 473 struct ct_data *ct; 474 XDR *xdrs; 475 bool_t dummy; 476 #ifdef _REENTRANT 477 sigset_t mask; 478 #endif 479 sigset_t newmask; 480 481 _DIAGASSERT(cl != NULL); 482 483 ct = (struct ct_data *)cl->cl_private; 484 xdrs = &(ct->ct_xdrs); 485 486 sigfillset(&newmask); 487 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 488 mutex_lock(&clnt_fd_lock); 489 #ifdef _REENTRANT 490 while (vc_fd_locks[ct->ct_fd]) 491 cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 492 #endif 493 494 xdrs->x_op = XDR_FREE; 495 dummy = (*xdr_res)(xdrs, res_ptr); 496 mutex_unlock(&clnt_fd_lock); 497 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 498 cond_signal(&vc_cv[ct->ct_fd]); 499 500 return dummy; 501 } 502 503 /*ARGSUSED*/ 504 static void 505 clnt_vc_abort(CLIENT *cl) 506 { 507 } 508 509 static bool_t 510 clnt_vc_control( 511 CLIENT *cl, 512 u_int request, 513 char *info 514 ) 515 { 516 struct ct_data *ct; 517 void *infop = info; 518 #ifdef _REENTRANT 519 sigset_t mask; 520 #endif 521 sigset_t newmask; 522 523 _DIAGASSERT(cl != NULL); 524 525 ct = (struct ct_data *)cl->cl_private; 526 527 sigfillset(&newmask); 528 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 529 mutex_lock(&clnt_fd_lock); 530 #ifdef _REENTRANT 531 while (vc_fd_locks[ct->ct_fd]) 532 cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 533 vc_fd_locks[ct->ct_fd] = __rpc_lock_value; 534 #endif 535 mutex_unlock(&clnt_fd_lock); 536 537 switch (request) { 538 case CLSET_FD_CLOSE: 539 ct->ct_closeit = TRUE; 540 release_fd_lock(ct->ct_fd, mask); 541 return (TRUE); 542 case CLSET_FD_NCLOSE: 543 ct->ct_closeit = FALSE; 544 release_fd_lock(ct->ct_fd, mask); 545 return (TRUE); 546 default: 547 break; 548 } 549 550 /* for other requests which use info */ 551 if (info == NULL) { 552 release_fd_lock(ct->ct_fd, mask); 553 return (FALSE); 554 } 555 switch (request) { 556 case CLSET_TIMEOUT: 557 if (time_not_ok((struct timeval *)(void *)info)) { 558 release_fd_lock(ct->ct_fd, mask); 559 return (FALSE); 560 } 561 ct->ct_wait = *(struct timeval *)infop; 562 ct->ct_waitset = TRUE; 563 break; 564 case CLGET_TIMEOUT: 565 *(struct timeval *)infop = ct->ct_wait; 566 break; 567 case CLGET_SERVER_ADDR: 568 (void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len); 569 break; 570 case CLGET_FD: 571 *(int *)(void *)info = ct->ct_fd; 572 break; 573 case CLGET_SVC_ADDR: 574 /* The caller should not free this memory area */ 575 *(struct netbuf *)(void *)info = ct->ct_addr; 576 break; 577 case CLSET_SVC_ADDR: /* set to new address */ 578 release_fd_lock(ct->ct_fd, mask); 579 return (FALSE); 580 case CLGET_XID: 581 /* 582 * use the knowledge that xid is the 583 * first element in the call structure 584 * This will get the xid of the PREVIOUS call 585 */ 586 *(u_int32_t *)(void *)info = 587 ntohl(*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli); 588 break; 589 case CLSET_XID: 590 /* This will set the xid of the NEXT call */ 591 *(u_int32_t *)(void *)&ct->ct_u.ct_mcalli = 592 htonl(*((u_int32_t *)(void *)info) + 1); 593 /* increment by 1 as clnt_vc_call() decrements once */ 594 break; 595 case CLGET_VERS: 596 /* 597 * This RELIES on the information that, in the call body, 598 * the version number field is the fifth field from the 599 * begining of the RPC header. MUST be changed if the 600 * call_struct is changed 601 */ 602 *(u_int32_t *)(void *)info = 603 ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 604 4 * BYTES_PER_XDR_UNIT)); 605 break; 606 607 case CLSET_VERS: 608 *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 609 4 * BYTES_PER_XDR_UNIT) = 610 htonl(*(u_int32_t *)(void *)info); 611 break; 612 613 case CLGET_PROG: 614 /* 615 * This RELIES on the information that, in the call body, 616 * the program number field is the fourth field from the 617 * begining of the RPC header. MUST be changed if the 618 * call_struct is changed 619 */ 620 *(u_int32_t *)(void *)info = 621 ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 622 3 * BYTES_PER_XDR_UNIT)); 623 break; 624 625 case CLSET_PROG: 626 *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 627 3 * BYTES_PER_XDR_UNIT) = 628 htonl(*(u_int32_t *)(void *)info); 629 break; 630 631 default: 632 release_fd_lock(ct->ct_fd, mask); 633 return (FALSE); 634 } 635 release_fd_lock(ct->ct_fd, mask); 636 return (TRUE); 637 } 638 639 640 static void 641 clnt_vc_destroy(CLIENT *cl) 642 { 643 struct ct_data *ct; 644 #ifdef _REENTRANT 645 int ct_fd; 646 sigset_t mask; 647 #endif 648 sigset_t newmask; 649 650 _DIAGASSERT(cl != NULL); 651 652 ct = (struct ct_data *) cl->cl_private; 653 ct_fd = ct->ct_fd; 654 655 sigfillset(&newmask); 656 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 657 mutex_lock(&clnt_fd_lock); 658 #ifdef _REENTRANT 659 while (vc_fd_locks[ct_fd]) 660 cond_wait(&vc_cv[ct_fd], &clnt_fd_lock); 661 #endif 662 if (ct->ct_closeit && ct->ct_fd != -1) { 663 (void)close(ct->ct_fd); 664 } 665 XDR_DESTROY(&(ct->ct_xdrs)); 666 if (ct->ct_addr.buf) 667 free(ct->ct_addr.buf); 668 mem_free(ct, sizeof(struct ct_data)); 669 mem_free(cl, sizeof(CLIENT)); 670 mutex_unlock(&clnt_fd_lock); 671 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 672 673 cond_signal(&vc_cv[ct_fd]); 674 } 675 676 /* 677 * Interface between xdr serializer and tcp connection. 678 * Behaves like the system calls, read & write, but keeps some error state 679 * around for the rpc level. 680 */ 681 static int 682 read_vc(char *ctp, char *buf, int len) 683 { 684 struct ct_data *ct = (struct ct_data *)(void *)ctp; 685 struct pollfd fd; 686 struct timespec ts; 687 ssize_t nread; 688 689 if (len == 0) 690 return (0); 691 692 TIMEVAL_TO_TIMESPEC(&ct->ct_wait, &ts); 693 fd.fd = ct->ct_fd; 694 fd.events = POLLIN; 695 for (;;) { 696 switch (pollts(&fd, 1, &ts, NULL)) { 697 case 0: 698 ct->ct_error.re_status = RPC_TIMEDOUT; 699 return (-1); 700 701 case -1: 702 if (errno == EINTR) 703 continue; 704 ct->ct_error.re_status = RPC_CANTRECV; 705 ct->ct_error.re_errno = errno; 706 return (-1); 707 } 708 break; 709 } 710 switch (nread = read(ct->ct_fd, buf, (size_t)len)) { 711 712 case 0: 713 /* premature eof */ 714 ct->ct_error.re_errno = ECONNRESET; 715 ct->ct_error.re_status = RPC_CANTRECV; 716 len = -1; /* it's really an error */ 717 break; 718 719 case -1: 720 ct->ct_error.re_errno = errno; 721 ct->ct_error.re_status = RPC_CANTRECV; 722 break; 723 } 724 return (int)nread; 725 } 726 727 static int 728 write_vc(char *ctp, char *buf, int len) 729 { 730 struct ct_data *ct = (struct ct_data *)(void *)ctp; 731 ssize_t i; 732 size_t cnt; 733 734 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 735 if ((i = write(ct->ct_fd, buf, cnt)) == -1) { 736 ct->ct_error.re_errno = errno; 737 ct->ct_error.re_status = RPC_CANTSEND; 738 return (-1); 739 } 740 } 741 return len; 742 } 743 744 static struct clnt_ops * 745 clnt_vc_ops(void) 746 { 747 static struct clnt_ops ops; 748 #ifdef _REENTRANT 749 extern mutex_t ops_lock; 750 sigset_t mask; 751 #endif 752 sigset_t newmask; 753 754 /* VARIABLES PROTECTED BY ops_lock: ops */ 755 756 sigfillset(&newmask); 757 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 758 mutex_lock(&ops_lock); 759 if (ops.cl_call == NULL) { 760 ops.cl_call = clnt_vc_call; 761 ops.cl_abort = clnt_vc_abort; 762 ops.cl_geterr = clnt_vc_geterr; 763 ops.cl_freeres = clnt_vc_freeres; 764 ops.cl_destroy = clnt_vc_destroy; 765 ops.cl_control = clnt_vc_control; 766 } 767 mutex_unlock(&ops_lock); 768 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 769 return (&ops); 770 } 771 772 /* 773 * Make sure that the time is not garbage. -1 value is disallowed. 774 * Note this is different from time_not_ok in clnt_dg.c 775 */ 776 static bool_t 777 time_not_ok(struct timeval *t) 778 { 779 780 _DIAGASSERT(t != NULL); 781 782 return (t->tv_sec <= -1 || t->tv_sec > 100000000 || 783 t->tv_usec <= -1 || t->tv_usec > 1000000); 784 } 785