1 /* $NetBSD: clnt_vc.c,v 1.23 2013/05/07 21:08:45 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 #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.23 2013/05/07 21:08:45 christos 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 __clnt_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 goto blooy; 209 } else 210 memset(vc_fd_locks, '\0', fd_allocsz); 211 212 _DIAGASSERT(vc_cv == NULL); 213 cv_allocsz = dtbsize * sizeof (cond_t); 214 vc_cv = mem_alloc(cv_allocsz); 215 if (vc_cv == NULL) { 216 mem_free(vc_fd_locks, fd_allocsz); 217 vc_fd_locks = NULL; 218 goto blooy; 219 } else { 220 int i; 221 222 for (i = 0; i < dtbsize; i++) 223 cond_init(&vc_cv[i], 0, (void *) 0); 224 } 225 } else 226 _DIAGASSERT(vc_cv != NULL); 227 #endif 228 229 /* 230 * XXX - fvdl connecting while holding a mutex? 231 */ 232 slen = sizeof ss; 233 if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 234 if (errno != ENOTCONN) { 235 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 236 rpc_createerr.cf_error.re_errno = errno; 237 goto blooy; 238 } 239 if (connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){ 240 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 241 rpc_createerr.cf_error.re_errno = errno; 242 goto blooy; 243 } 244 } 245 mutex_unlock(&clnt_fd_lock); 246 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 247 if (!__rpc_fd2sockinfo(fd, &si)) 248 goto fooy; 249 250 ct->ct_closeit = FALSE; 251 252 /* 253 * Set up private data struct 254 */ 255 ct->ct_fd = fd; 256 ct->ct_wait.tv_usec = 0; 257 ct->ct_waitset = FALSE; 258 ct->ct_addr.buf = malloc((size_t)raddr->maxlen); 259 if (ct->ct_addr.buf == NULL) 260 goto fooy; 261 memcpy(ct->ct_addr.buf, raddr->buf, (size_t)raddr->len); 262 ct->ct_addr.len = raddr->len; 263 ct->ct_addr.maxlen = raddr->maxlen; 264 265 /* 266 * Initialize call message 267 */ 268 call_msg.rm_xid = __RPC_GETXID(); 269 call_msg.rm_direction = CALL; 270 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 271 call_msg.rm_call.cb_prog = (u_int32_t)prog; 272 call_msg.rm_call.cb_vers = (u_int32_t)vers; 273 274 /* 275 * pre-serialize the static part of the call msg and stash it away 276 */ 277 xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE, 278 XDR_ENCODE); 279 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 280 if (ct->ct_closeit) { 281 (void)close(fd); 282 } 283 goto fooy; 284 } 285 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 286 XDR_DESTROY(&(ct->ct_xdrs)); 287 288 /* 289 * Create a client handle which uses xdrrec for serialization 290 * and authnone for authentication. 291 */ 292 h->cl_ops = clnt_vc_ops(); 293 h->cl_private = ct; 294 h->cl_auth = authnone_create(); 295 sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 296 recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 297 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 298 h->cl_private, read_vc, write_vc); 299 return (h); 300 301 blooy: 302 mutex_unlock(&clnt_fd_lock); 303 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 304 fooy: 305 /* 306 * Something goofed, free stuff and barf 307 */ 308 if (ct) 309 mem_free(ct, sizeof(struct ct_data)); 310 if (h) 311 mem_free(h, sizeof(CLIENT)); 312 return (NULL); 313 } 314 315 static enum clnt_stat 316 clnt_vc_call( 317 CLIENT *h, 318 rpcproc_t proc, 319 xdrproc_t xdr_args, 320 const char *args_ptr, 321 xdrproc_t xdr_results, 322 caddr_t results_ptr, 323 struct timeval timeout 324 ) 325 { 326 struct ct_data *ct; 327 XDR *xdrs; 328 struct rpc_msg reply_msg; 329 u_int32_t x_id; 330 u_int32_t *msg_x_id; 331 bool_t shipnow; 332 int refreshes = 2; 333 #ifdef _REENTRANT 334 sigset_t mask, newmask; 335 #endif 336 337 _DIAGASSERT(h != NULL); 338 339 ct = (struct ct_data *) h->cl_private; 340 341 #ifdef _REENTRANT 342 __clnt_sigfillset(&newmask); 343 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 344 mutex_lock(&clnt_fd_lock); 345 while (vc_fd_locks[ct->ct_fd]) 346 cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 347 vc_fd_locks[ct->ct_fd] = __rpc_lock_value; 348 mutex_unlock(&clnt_fd_lock); 349 #endif 350 351 xdrs = &(ct->ct_xdrs); 352 msg_x_id = &ct->ct_u.ct_mcalli; 353 354 if (!ct->ct_waitset) { 355 if (time_not_ok(&timeout) == FALSE) 356 ct->ct_wait = timeout; 357 } 358 359 shipnow = 360 (xdr_results == NULL && timeout.tv_sec == 0 361 && timeout.tv_usec == 0) ? FALSE : TRUE; 362 363 call_again: 364 xdrs->x_op = XDR_ENCODE; 365 ct->ct_error.re_status = RPC_SUCCESS; 366 x_id = ntohl(--(*msg_x_id)); 367 if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) || 368 (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 369 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 370 (! (*xdr_args)(xdrs, __UNCONST(args_ptr)))) { 371 if (ct->ct_error.re_status == RPC_SUCCESS) 372 ct->ct_error.re_status = RPC_CANTENCODEARGS; 373 (void)xdrrec_endofrecord(xdrs, TRUE); 374 release_fd_lock(ct->ct_fd, mask); 375 return (ct->ct_error.re_status); 376 } 377 if (! xdrrec_endofrecord(xdrs, shipnow)) { 378 release_fd_lock(ct->ct_fd, mask); 379 return (ct->ct_error.re_status = RPC_CANTSEND); 380 } 381 if (! shipnow) { 382 release_fd_lock(ct->ct_fd, mask); 383 return (RPC_SUCCESS); 384 } 385 /* 386 * Hack to provide rpc-based message passing 387 */ 388 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 389 release_fd_lock(ct->ct_fd, mask); 390 return(ct->ct_error.re_status = RPC_TIMEDOUT); 391 } 392 393 394 /* 395 * Keep receiving until we get a valid transaction id 396 */ 397 xdrs->x_op = XDR_DECODE; 398 for (;;) { 399 reply_msg.acpted_rply.ar_verf = _null_auth; 400 reply_msg.acpted_rply.ar_results.where = NULL; 401 reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 402 if (! xdrrec_skiprecord(xdrs)) { 403 release_fd_lock(ct->ct_fd, mask); 404 return (ct->ct_error.re_status); 405 } 406 /* now decode and validate the response header */ 407 if (! xdr_replymsg(xdrs, &reply_msg)) { 408 if (ct->ct_error.re_status == RPC_SUCCESS) 409 continue; 410 release_fd_lock(ct->ct_fd, mask); 411 return (ct->ct_error.re_status); 412 } 413 if (reply_msg.rm_xid == x_id) 414 break; 415 } 416 417 /* 418 * process header 419 */ 420 _seterr_reply(&reply_msg, &(ct->ct_error)); 421 if (ct->ct_error.re_status == RPC_SUCCESS) { 422 if (! AUTH_VALIDATE(h->cl_auth, 423 &reply_msg.acpted_rply.ar_verf)) { 424 ct->ct_error.re_status = RPC_AUTHERROR; 425 ct->ct_error.re_why = AUTH_INVALIDRESP; 426 } else if (! (*xdr_results)(xdrs, results_ptr)) { 427 if (ct->ct_error.re_status == RPC_SUCCESS) 428 ct->ct_error.re_status = RPC_CANTDECODERES; 429 } 430 /* free verifier ... */ 431 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 432 xdrs->x_op = XDR_FREE; 433 (void)xdr_opaque_auth(xdrs, 434 &(reply_msg.acpted_rply.ar_verf)); 435 } 436 } /* end successful completion */ 437 else { 438 /* maybe our credentials need to be refreshed ... */ 439 if (refreshes-- && AUTH_REFRESH(h->cl_auth)) 440 goto call_again; 441 } /* end of unsuccessful completion */ 442 release_fd_lock(ct->ct_fd, mask); 443 return (ct->ct_error.re_status); 444 } 445 446 static void 447 clnt_vc_geterr( 448 CLIENT *h, 449 struct rpc_err *errp 450 ) 451 { 452 struct ct_data *ct; 453 454 _DIAGASSERT(h != NULL); 455 _DIAGASSERT(errp != NULL); 456 457 ct = (struct ct_data *) h->cl_private; 458 *errp = ct->ct_error; 459 } 460 461 static bool_t 462 clnt_vc_freeres( 463 CLIENT *cl, 464 xdrproc_t xdr_res, 465 caddr_t res_ptr 466 ) 467 { 468 struct ct_data *ct; 469 XDR *xdrs; 470 bool_t dummy; 471 #ifdef _REENTRANT 472 sigset_t mask; 473 #endif 474 sigset_t newmask; 475 476 _DIAGASSERT(cl != NULL); 477 478 ct = (struct ct_data *)cl->cl_private; 479 xdrs = &(ct->ct_xdrs); 480 481 __clnt_sigfillset(&newmask); 482 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 483 mutex_lock(&clnt_fd_lock); 484 #ifdef _REENTRANT 485 while (vc_fd_locks[ct->ct_fd]) 486 cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 487 #endif 488 489 xdrs->x_op = XDR_FREE; 490 dummy = (*xdr_res)(xdrs, res_ptr); 491 mutex_unlock(&clnt_fd_lock); 492 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 493 cond_signal(&vc_cv[ct->ct_fd]); 494 495 return dummy; 496 } 497 498 /*ARGSUSED*/ 499 static void 500 clnt_vc_abort(CLIENT *cl) 501 { 502 } 503 504 static bool_t 505 clnt_vc_control( 506 CLIENT *cl, 507 u_int request, 508 char *info 509 ) 510 { 511 struct ct_data *ct; 512 void *infop = info; 513 #ifdef _REENTRANT 514 sigset_t mask; 515 #endif 516 sigset_t newmask; 517 518 _DIAGASSERT(cl != NULL); 519 520 ct = (struct ct_data *)cl->cl_private; 521 522 __clnt_sigfillset(&newmask); 523 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 524 mutex_lock(&clnt_fd_lock); 525 #ifdef _REENTRANT 526 while (vc_fd_locks[ct->ct_fd]) 527 cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 528 vc_fd_locks[ct->ct_fd] = __rpc_lock_value; 529 #endif 530 mutex_unlock(&clnt_fd_lock); 531 532 switch (request) { 533 case CLSET_FD_CLOSE: 534 ct->ct_closeit = TRUE; 535 release_fd_lock(ct->ct_fd, mask); 536 return (TRUE); 537 case CLSET_FD_NCLOSE: 538 ct->ct_closeit = FALSE; 539 release_fd_lock(ct->ct_fd, mask); 540 return (TRUE); 541 default: 542 break; 543 } 544 545 /* for other requests which use info */ 546 if (info == NULL) { 547 release_fd_lock(ct->ct_fd, mask); 548 return (FALSE); 549 } 550 switch (request) { 551 case CLSET_TIMEOUT: 552 if (time_not_ok((struct timeval *)(void *)info)) { 553 release_fd_lock(ct->ct_fd, mask); 554 return (FALSE); 555 } 556 ct->ct_wait = *(struct timeval *)infop; 557 ct->ct_waitset = TRUE; 558 break; 559 case CLGET_TIMEOUT: 560 *(struct timeval *)infop = ct->ct_wait; 561 break; 562 case CLGET_SERVER_ADDR: 563 (void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len); 564 break; 565 case CLGET_FD: 566 *(int *)(void *)info = ct->ct_fd; 567 break; 568 case CLGET_SVC_ADDR: 569 /* The caller should not free this memory area */ 570 *(struct netbuf *)(void *)info = ct->ct_addr; 571 break; 572 case CLSET_SVC_ADDR: /* set to new address */ 573 release_fd_lock(ct->ct_fd, mask); 574 return (FALSE); 575 case CLGET_XID: 576 /* 577 * use the knowledge that xid is the 578 * first element in the call structure 579 * This will get the xid of the PREVIOUS call 580 */ 581 *(u_int32_t *)(void *)info = 582 ntohl(*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli); 583 break; 584 case CLSET_XID: 585 /* This will set the xid of the NEXT call */ 586 *(u_int32_t *)(void *)&ct->ct_u.ct_mcalli = 587 htonl(*((u_int32_t *)(void *)info) + 1); 588 /* increment by 1 as clnt_vc_call() decrements once */ 589 break; 590 case CLGET_VERS: 591 /* 592 * This RELIES on the information that, in the call body, 593 * the version number field is the fifth field from the 594 * begining of the RPC header. MUST be changed if the 595 * call_struct is changed 596 */ 597 *(u_int32_t *)(void *)info = 598 ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 599 4 * BYTES_PER_XDR_UNIT)); 600 break; 601 602 case CLSET_VERS: 603 *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 604 4 * BYTES_PER_XDR_UNIT) = 605 htonl(*(u_int32_t *)(void *)info); 606 break; 607 608 case CLGET_PROG: 609 /* 610 * This RELIES on the information that, in the call body, 611 * the program number field is the fourth field from the 612 * begining of the RPC header. MUST be changed if the 613 * call_struct is changed 614 */ 615 *(u_int32_t *)(void *)info = 616 ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 617 3 * BYTES_PER_XDR_UNIT)); 618 break; 619 620 case CLSET_PROG: 621 *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 622 3 * BYTES_PER_XDR_UNIT) = 623 htonl(*(u_int32_t *)(void *)info); 624 break; 625 626 default: 627 release_fd_lock(ct->ct_fd, mask); 628 return (FALSE); 629 } 630 release_fd_lock(ct->ct_fd, mask); 631 return (TRUE); 632 } 633 634 635 static void 636 clnt_vc_destroy(CLIENT *cl) 637 { 638 struct ct_data *ct; 639 #ifdef _REENTRANT 640 int ct_fd; 641 sigset_t mask; 642 #endif 643 sigset_t newmask; 644 645 _DIAGASSERT(cl != NULL); 646 647 ct = (struct ct_data *) cl->cl_private; 648 ct_fd = ct->ct_fd; 649 650 __clnt_sigfillset(&newmask); 651 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 652 mutex_lock(&clnt_fd_lock); 653 #ifdef _REENTRANT 654 while (vc_fd_locks[ct_fd]) 655 cond_wait(&vc_cv[ct_fd], &clnt_fd_lock); 656 #endif 657 if (ct->ct_closeit && ct->ct_fd != -1) { 658 (void)close(ct->ct_fd); 659 } 660 XDR_DESTROY(&(ct->ct_xdrs)); 661 if (ct->ct_addr.buf) 662 free(ct->ct_addr.buf); 663 mem_free(ct, sizeof(struct ct_data)); 664 mem_free(cl, sizeof(CLIENT)); 665 mutex_unlock(&clnt_fd_lock); 666 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 667 668 cond_signal(&vc_cv[ct_fd]); 669 } 670 671 /* 672 * Interface between xdr serializer and tcp connection. 673 * Behaves like the system calls, read & write, but keeps some error state 674 * around for the rpc level. 675 */ 676 static int 677 read_vc(char *ctp, char *buf, int len) 678 { 679 struct ct_data *ct = (struct ct_data *)(void *)ctp; 680 struct pollfd fd; 681 struct timespec ts; 682 ssize_t nread; 683 684 if (len == 0) 685 return (0); 686 687 TIMEVAL_TO_TIMESPEC(&ct->ct_wait, &ts); 688 fd.fd = ct->ct_fd; 689 fd.events = POLLIN; 690 for (;;) { 691 switch (pollts(&fd, 1, &ts, NULL)) { 692 case 0: 693 ct->ct_error.re_status = RPC_TIMEDOUT; 694 return (-1); 695 696 case -1: 697 if (errno == EINTR) 698 continue; 699 ct->ct_error.re_status = RPC_CANTRECV; 700 ct->ct_error.re_errno = errno; 701 return (-1); 702 } 703 break; 704 } 705 switch (nread = read(ct->ct_fd, buf, (size_t)len)) { 706 707 case 0: 708 /* premature eof */ 709 ct->ct_error.re_errno = ECONNRESET; 710 ct->ct_error.re_status = RPC_CANTRECV; 711 nread = -1; /* it's really an error */ 712 break; 713 714 case -1: 715 ct->ct_error.re_errno = errno; 716 ct->ct_error.re_status = RPC_CANTRECV; 717 break; 718 } 719 return (int)nread; 720 } 721 722 static int 723 write_vc(char *ctp, char *buf, int len) 724 { 725 struct ct_data *ct = (struct ct_data *)(void *)ctp; 726 ssize_t i; 727 size_t cnt; 728 729 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 730 if ((i = write(ct->ct_fd, buf, cnt)) == -1) { 731 ct->ct_error.re_errno = errno; 732 ct->ct_error.re_status = RPC_CANTSEND; 733 return (-1); 734 } 735 } 736 return len; 737 } 738 739 static struct clnt_ops * 740 clnt_vc_ops(void) 741 { 742 static struct clnt_ops ops; 743 #ifdef _REENTRANT 744 extern mutex_t ops_lock; 745 sigset_t mask; 746 #endif 747 sigset_t newmask; 748 749 /* VARIABLES PROTECTED BY ops_lock: ops */ 750 751 __clnt_sigfillset(&newmask); 752 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 753 mutex_lock(&ops_lock); 754 if (ops.cl_call == NULL) { 755 ops.cl_call = clnt_vc_call; 756 ops.cl_abort = clnt_vc_abort; 757 ops.cl_geterr = clnt_vc_geterr; 758 ops.cl_freeres = clnt_vc_freeres; 759 ops.cl_destroy = clnt_vc_destroy; 760 ops.cl_control = clnt_vc_control; 761 } 762 mutex_unlock(&ops_lock); 763 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 764 return (&ops); 765 } 766 767 /* 768 * Make sure that the time is not garbage. -1 value is disallowed. 769 * Note this is different from time_not_ok in clnt_dg.c 770 */ 771 static bool_t 772 time_not_ok(struct timeval *t) 773 { 774 775 _DIAGASSERT(t != NULL); 776 777 return (t->tv_sec <= -1 || t->tv_sec > 100000000 || 778 t->tv_usec <= -1 || t->tv_usec > 1000000); 779 } 780