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