1 /* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */ 2 /* $FreeBSD$ */ 3 4 /* 5 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 6 * unrestricted use provided that this legend is included on all tape 7 * media and as a part of the software program in whole or part. Users 8 * may copy or modify Sun RPC without charge, but are not authorized 9 * to license or distribute it to anyone else except as part of a product or 10 * program developed by the user. 11 * 12 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 13 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 14 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 15 * 16 * Sun RPC is provided with no support and without any obligation on the 17 * part of Sun Microsystems, Inc. to assist in its use, correction, 18 * modification or enhancement. 19 * 20 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 21 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 22 * OR ANY PART THEREOF. 23 * 24 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 25 * or profits or other special, indirect and consequential damages, even if 26 * Sun has been advised of the possibility of such damages. 27 * 28 * Sun Microsystems, Inc. 29 * 2550 Garcia Avenue 30 * Mountain View, California 94043 31 */ 32 33 #include <sys/cdefs.h> 34 #if defined(LIBC_SCCS) && !defined(lint) 35 static char *sccsid = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro"; 36 static char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 37 static char sccsid[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 38 #endif 39 40 /* 41 * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 42 * 43 * Copyright (C) 1984, Sun Microsystems, Inc. 44 * 45 * TCP based RPC supports 'batched calls'. 46 * A sequence of calls may be batched-up in a send buffer. The rpc call 47 * return immediately to the client even though the call was not necessarily 48 * sent. The batching occurs if the results' xdr routine is NULL (0) AND 49 * the rpc timeout value is zero (see clnt.h, rpc). 50 * 51 * Clients should NOT casually batch calls that in fact return results; that is, 52 * the server side should be aware that a call is batched and not produce any 53 * return message. Batched calls that produce many result messages can 54 * deadlock (netlock) the client and the server.... 55 * 56 * Now go hang yourself. 57 */ 58 59 #include "namespace.h" 60 #include "reentrant.h" 61 #include <sys/types.h> 62 #include <sys/poll.h> 63 #include <sys/syslog.h> 64 #include <sys/socket.h> 65 #include <sys/un.h> 66 #include <sys/uio.h> 67 68 #include <assert.h> 69 #include <err.h> 70 #include <errno.h> 71 #include <netdb.h> 72 #include <stdio.h> 73 #include <stdlib.h> 74 #include <string.h> 75 #include <unistd.h> 76 #include <signal.h> 77 78 #include <rpc/rpc.h> 79 #include "un-namespace.h" 80 #include "rpc_com.h" 81 82 #define MCALL_MSG_SIZE 24 83 84 struct cmessage { 85 struct cmsghdr cmsg; 86 struct cmsgcred cmcred; 87 }; 88 89 static enum clnt_stat clnt_vc_call __P((CLIENT *, rpcproc_t, xdrproc_t, caddr_t, 90 xdrproc_t, caddr_t, struct timeval)); 91 static void clnt_vc_geterr __P((CLIENT *, struct rpc_err *)); 92 static bool_t clnt_vc_freeres __P((CLIENT *, xdrproc_t, caddr_t)); 93 static void clnt_vc_abort __P((CLIENT *)); 94 static bool_t clnt_vc_control __P((CLIENT *, u_int, char *)); 95 static void clnt_vc_destroy __P((CLIENT *)); 96 static struct clnt_ops *clnt_vc_ops __P((void)); 97 static bool_t time_not_ok __P((struct timeval *)); 98 static int read_vc __P((caddr_t, caddr_t, int)); 99 static int write_vc __P((caddr_t, caddr_t, int)); 100 static int __msgwrite(int, void *, size_t); 101 static int __msgread(int, void *, size_t); 102 103 struct ct_data { 104 int ct_fd; /* connection's fd */ 105 bool_t ct_closeit; /* close it on destroy */ 106 struct timeval ct_wait; /* wait interval in milliseconds */ 107 bool_t ct_waitset; /* wait set by clnt_control? */ 108 struct netbuf ct_addr; /* remote 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; /* XDR stream */ 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 static int *vc_fd_locks; 131 extern mutex_t clnt_fd_lock; 132 static cond_t *vc_cv; 133 #define release_fd_lock(fd, mask) { \ 134 mutex_lock(&clnt_fd_lock); \ 135 vc_fd_locks[fd] = 0; \ 136 mutex_unlock(&clnt_fd_lock); \ 137 thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \ 138 cond_signal(&vc_cv[fd]); \ 139 } 140 141 static const char clnt_vc_errstr[] = "%s : %s"; 142 static const char clnt_vc_str[] = "clnt_vc_create"; 143 static const char clnt_read_vc_str[] = "read_vc"; 144 static const char __no_mem_str[] = "out of memory"; 145 146 /* 147 * Create a client handle for a connection. 148 * Default options are set, which the user can change using clnt_control()'s. 149 * The rpc/vc package does buffering similar to stdio, so the client 150 * must pick send and receive buffer sizes, 0 => use the default. 151 * NB: fd is copied into a private area. 152 * NB: The rpch->cl_auth is set null authentication. Caller may wish to 153 * set this something more useful. 154 * 155 * fd should be an open socket 156 */ 157 CLIENT * 158 clnt_vc_create(fd, raddr, prog, vers, sendsz, recvsz) 159 int fd; /* open file descriptor */ 160 const struct netbuf *raddr; /* servers address */ 161 rpcprog_t prog; /* program number */ 162 rpcvers_t vers; /* version number */ 163 u_int sendsz; /* buffer recv size */ 164 u_int recvsz; /* buffer send size */ 165 { 166 CLIENT *cl; /* client handle */ 167 struct ct_data *ct = NULL; /* client handle */ 168 struct timeval now; 169 struct rpc_msg call_msg; 170 static u_int32_t disrupt; 171 sigset_t mask; 172 sigset_t newmask; 173 struct sockaddr_storage ss; 174 socklen_t slen; 175 struct __rpc_sockinfo si; 176 177 if (disrupt == 0) 178 disrupt = (u_int32_t)(long)raddr; 179 180 cl = (CLIENT *)mem_alloc(sizeof (*cl)); 181 ct = (struct ct_data *)mem_alloc(sizeof (*ct)); 182 if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) { 183 (void) syslog(LOG_ERR, clnt_vc_errstr, 184 clnt_vc_str, __no_mem_str); 185 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 186 rpc_createerr.cf_error.re_errno = errno; 187 goto err; 188 } 189 ct->ct_addr.buf = NULL; 190 sigfillset(&newmask); 191 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 192 mutex_lock(&clnt_fd_lock); 193 if (vc_fd_locks == (int *) NULL) { 194 int cv_allocsz, fd_allocsz; 195 int dtbsize = __rpc_dtbsize(); 196 197 fd_allocsz = dtbsize * sizeof (int); 198 vc_fd_locks = (int *) mem_alloc(fd_allocsz); 199 if (vc_fd_locks == (int *) NULL) { 200 mutex_unlock(&clnt_fd_lock); 201 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 202 goto err; 203 } else 204 memset(vc_fd_locks, '\0', fd_allocsz); 205 206 assert(vc_cv == (cond_t *) NULL); 207 cv_allocsz = dtbsize * sizeof (cond_t); 208 vc_cv = (cond_t *) mem_alloc(cv_allocsz); 209 if (vc_cv == (cond_t *) NULL) { 210 mem_free(vc_fd_locks, fd_allocsz); 211 vc_fd_locks = (int *) NULL; 212 mutex_unlock(&clnt_fd_lock); 213 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 214 goto err; 215 } else { 216 int i; 217 218 for (i = 0; i < dtbsize; i++) 219 cond_init(&vc_cv[i], 0, (void *) 0); 220 } 221 } else 222 assert(vc_cv != (cond_t *) NULL); 223 224 /* 225 * XXX - fvdl connecting while holding a mutex? 226 */ 227 slen = sizeof ss; 228 if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 229 if (errno != ENOTCONN) { 230 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 231 rpc_createerr.cf_error.re_errno = errno; 232 mutex_unlock(&clnt_fd_lock); 233 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 234 goto err; 235 } 236 if (_connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){ 237 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 238 rpc_createerr.cf_error.re_errno = errno; 239 mutex_unlock(&clnt_fd_lock); 240 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 241 goto err; 242 } 243 } 244 mutex_unlock(&clnt_fd_lock); 245 if (!__rpc_fd2sockinfo(fd, &si)) 246 goto err; 247 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 248 249 ct->ct_closeit = FALSE; 250 251 /* 252 * Set up private data struct 253 */ 254 ct->ct_fd = fd; 255 ct->ct_wait.tv_usec = 0; 256 ct->ct_waitset = FALSE; 257 ct->ct_addr.buf = malloc(raddr->maxlen); 258 if (ct->ct_addr.buf == NULL) 259 goto err; 260 memcpy(ct->ct_addr.buf, raddr->buf, raddr->len); 261 ct->ct_addr.len = raddr->maxlen; 262 ct->ct_addr.maxlen = raddr->maxlen; 263 264 /* 265 * Initialize call message 266 */ 267 (void)gettimeofday(&now, NULL); 268 call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now); 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 err; 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 cl->cl_ops = clnt_vc_ops(); 293 cl->cl_private = ct; 294 cl->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 cl->cl_private, read_vc, write_vc); 299 return (cl); 300 301 err: 302 if (cl) { 303 if (ct) { 304 if (ct->ct_addr.len) 305 mem_free(ct->ct_addr.buf, ct->ct_addr.len); 306 mem_free((caddr_t)ct, sizeof (struct ct_data)); 307 } 308 if (cl) 309 mem_free((caddr_t)cl, sizeof (CLIENT)); 310 } 311 return ((CLIENT *)NULL); 312 } 313 314 static enum clnt_stat 315 clnt_vc_call(cl, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) 316 CLIENT *cl; 317 rpcproc_t proc; 318 xdrproc_t xdr_args; 319 caddr_t args_ptr; 320 xdrproc_t xdr_results; 321 caddr_t results_ptr; 322 struct timeval timeout; 323 { 324 struct ct_data *ct = (struct ct_data *) cl->cl_private; 325 XDR *xdrs = &(ct->ct_xdrs); 326 struct rpc_msg reply_msg; 327 u_int32_t x_id; 328 u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */ 329 bool_t shipnow; 330 int refreshes = 2; 331 sigset_t mask, newmask; 332 int rpc_lock_value; 333 334 assert(cl != NULL); 335 336 sigfillset(&newmask); 337 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 338 mutex_lock(&clnt_fd_lock); 339 while (vc_fd_locks[ct->ct_fd]) 340 cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 341 if (__isthreaded) 342 rpc_lock_value = 1; 343 else 344 rpc_lock_value = 0; 345 vc_fd_locks[ct->ct_fd] = rpc_lock_value; 346 mutex_unlock(&clnt_fd_lock); 347 if (!ct->ct_waitset) { 348 /* If time is not within limits, we ignore it. */ 349 if (time_not_ok(&timeout) == FALSE) 350 ct->ct_wait = timeout; 351 } 352 353 shipnow = 354 (xdr_results == NULL && timeout.tv_sec == 0 355 && timeout.tv_usec == 0) ? FALSE : TRUE; 356 357 call_again: 358 xdrs->x_op = XDR_ENCODE; 359 ct->ct_error.re_status = RPC_SUCCESS; 360 x_id = ntohl(--(*msg_x_id)); 361 362 if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) || 363 (! XDR_PUTINT32(xdrs, &proc)) || 364 (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || 365 (! (*xdr_args)(xdrs, args_ptr))) { 366 if (ct->ct_error.re_status == RPC_SUCCESS) 367 ct->ct_error.re_status = RPC_CANTENCODEARGS; 368 (void)xdrrec_endofrecord(xdrs, TRUE); 369 release_fd_lock(ct->ct_fd, mask); 370 return (ct->ct_error.re_status); 371 } 372 if (! xdrrec_endofrecord(xdrs, shipnow)) { 373 release_fd_lock(ct->ct_fd, mask); 374 return (ct->ct_error.re_status = RPC_CANTSEND); 375 } 376 if (! shipnow) { 377 release_fd_lock(ct->ct_fd, mask); 378 return (RPC_SUCCESS); 379 } 380 /* 381 * Hack to provide rpc-based message passing 382 */ 383 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 384 release_fd_lock(ct->ct_fd, mask); 385 return(ct->ct_error.re_status = RPC_TIMEDOUT); 386 } 387 388 389 /* 390 * Keep receiving until we get a valid transaction id 391 */ 392 xdrs->x_op = XDR_DECODE; 393 while (TRUE) { 394 reply_msg.acpted_rply.ar_verf = _null_auth; 395 reply_msg.acpted_rply.ar_results.where = NULL; 396 reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 397 if (! xdrrec_skiprecord(xdrs)) { 398 release_fd_lock(ct->ct_fd, mask); 399 return (ct->ct_error.re_status); 400 } 401 /* now decode and validate the response header */ 402 if (! xdr_replymsg(xdrs, &reply_msg)) { 403 if (ct->ct_error.re_status == RPC_SUCCESS) 404 continue; 405 release_fd_lock(ct->ct_fd, mask); 406 return (ct->ct_error.re_status); 407 } 408 if (reply_msg.rm_xid == x_id) 409 break; 410 } 411 412 /* 413 * process header 414 */ 415 _seterr_reply(&reply_msg, &(ct->ct_error)); 416 if (ct->ct_error.re_status == RPC_SUCCESS) { 417 if (! AUTH_VALIDATE(cl->cl_auth, 418 &reply_msg.acpted_rply.ar_verf)) { 419 ct->ct_error.re_status = RPC_AUTHERROR; 420 ct->ct_error.re_why = AUTH_INVALIDRESP; 421 } else if (! (*xdr_results)(xdrs, results_ptr)) { 422 if (ct->ct_error.re_status == RPC_SUCCESS) 423 ct->ct_error.re_status = RPC_CANTDECODERES; 424 } 425 /* free verifier ... */ 426 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 427 xdrs->x_op = XDR_FREE; 428 (void)xdr_opaque_auth(xdrs, 429 &(reply_msg.acpted_rply.ar_verf)); 430 } 431 } /* end successful completion */ 432 else { 433 /* maybe our credentials need to be refreshed ... */ 434 if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg)) 435 goto call_again; 436 } /* end of unsuccessful completion */ 437 release_fd_lock(ct->ct_fd, mask); 438 return (ct->ct_error.re_status); 439 } 440 441 static void 442 clnt_vc_geterr(cl, errp) 443 CLIENT *cl; 444 struct rpc_err *errp; 445 { 446 struct ct_data *ct; 447 448 assert(cl != NULL); 449 assert(errp != NULL); 450 451 ct = (struct ct_data *) cl->cl_private; 452 *errp = ct->ct_error; 453 } 454 455 static bool_t 456 clnt_vc_freeres(cl, xdr_res, res_ptr) 457 CLIENT *cl; 458 xdrproc_t xdr_res; 459 caddr_t res_ptr; 460 { 461 struct ct_data *ct; 462 XDR *xdrs; 463 bool_t dummy; 464 sigset_t mask; 465 sigset_t newmask; 466 467 assert(cl != NULL); 468 469 ct = (struct ct_data *)cl->cl_private; 470 xdrs = &(ct->ct_xdrs); 471 472 sigfillset(&newmask); 473 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 474 mutex_lock(&clnt_fd_lock); 475 while (vc_fd_locks[ct->ct_fd]) 476 cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 477 xdrs->x_op = XDR_FREE; 478 dummy = (*xdr_res)(xdrs, res_ptr); 479 mutex_unlock(&clnt_fd_lock); 480 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 481 cond_signal(&vc_cv[ct->ct_fd]); 482 483 return dummy; 484 } 485 486 /*ARGSUSED*/ 487 static void 488 clnt_vc_abort(cl) 489 CLIENT *cl; 490 { 491 } 492 493 static bool_t 494 clnt_vc_control(cl, request, info) 495 CLIENT *cl; 496 u_int request; 497 char *info; 498 { 499 struct ct_data *ct; 500 void *infop = info; 501 sigset_t mask; 502 sigset_t newmask; 503 int rpc_lock_value; 504 505 assert(cl != NULL); 506 507 ct = (struct ct_data *)cl->cl_private; 508 509 sigfillset(&newmask); 510 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 511 mutex_lock(&clnt_fd_lock); 512 while (vc_fd_locks[ct->ct_fd]) 513 cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); 514 if (__isthreaded) 515 rpc_lock_value = 1; 516 else 517 rpc_lock_value = 0; 518 vc_fd_locks[ct->ct_fd] = rpc_lock_value; 519 mutex_unlock(&clnt_fd_lock); 520 521 switch (request) { 522 case CLSET_FD_CLOSE: 523 ct->ct_closeit = TRUE; 524 release_fd_lock(ct->ct_fd, mask); 525 return (TRUE); 526 case CLSET_FD_NCLOSE: 527 ct->ct_closeit = FALSE; 528 release_fd_lock(ct->ct_fd, mask); 529 return (TRUE); 530 default: 531 break; 532 } 533 534 /* for other requests which use info */ 535 if (info == NULL) { 536 release_fd_lock(ct->ct_fd, mask); 537 return (FALSE); 538 } 539 switch (request) { 540 case CLSET_TIMEOUT: 541 if (time_not_ok((struct timeval *)(void *)info)) { 542 release_fd_lock(ct->ct_fd, mask); 543 return (FALSE); 544 } 545 ct->ct_wait = *(struct timeval *)infop; 546 ct->ct_waitset = TRUE; 547 break; 548 case CLGET_TIMEOUT: 549 *(struct timeval *)infop = ct->ct_wait; 550 break; 551 case CLGET_SERVER_ADDR: 552 (void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len); 553 break; 554 case CLGET_FD: 555 *(int *)(void *)info = ct->ct_fd; 556 break; 557 case CLGET_SVC_ADDR: 558 /* The caller should not free this memory area */ 559 *(struct netbuf *)(void *)info = ct->ct_addr; 560 break; 561 case CLSET_SVC_ADDR: /* set to new address */ 562 release_fd_lock(ct->ct_fd, mask); 563 return (FALSE); 564 case CLGET_XID: 565 /* 566 * use the knowledge that xid is the 567 * first element in the call structure 568 * This will get the xid of the PREVIOUS call 569 */ 570 *(u_int32_t *)(void *)info = 571 ntohl(*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli); 572 break; 573 case CLSET_XID: 574 /* This will set the xid of the NEXT call */ 575 *(u_int32_t *)(void *)&ct->ct_u.ct_mcalli = 576 htonl(*((u_int32_t *)(void *)info) + 1); 577 /* increment by 1 as clnt_vc_call() decrements once */ 578 break; 579 case CLGET_VERS: 580 /* 581 * This RELIES on the information that, in the call body, 582 * the version number field is the fifth field from the 583 * begining of the RPC header. MUST be changed if the 584 * call_struct is changed 585 */ 586 *(u_int32_t *)(void *)info = 587 ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 588 4 * BYTES_PER_XDR_UNIT)); 589 break; 590 591 case CLSET_VERS: 592 *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 593 4 * BYTES_PER_XDR_UNIT) = 594 htonl(*(u_int32_t *)(void *)info); 595 break; 596 597 case CLGET_PROG: 598 /* 599 * This RELIES on the information that, in the call body, 600 * the program number field is the fourth field from the 601 * begining of the RPC header. MUST be changed if the 602 * call_struct is changed 603 */ 604 *(u_int32_t *)(void *)info = 605 ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 606 3 * BYTES_PER_XDR_UNIT)); 607 break; 608 609 case CLSET_PROG: 610 *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + 611 3 * BYTES_PER_XDR_UNIT) = 612 htonl(*(u_int32_t *)(void *)info); 613 break; 614 615 default: 616 release_fd_lock(ct->ct_fd, mask); 617 return (FALSE); 618 } 619 release_fd_lock(ct->ct_fd, mask); 620 return (TRUE); 621 } 622 623 624 static void 625 clnt_vc_destroy(cl) 626 CLIENT *cl; 627 { 628 struct ct_data *ct = (struct ct_data *) cl->cl_private; 629 int ct_fd = ct->ct_fd; 630 sigset_t mask; 631 sigset_t newmask; 632 633 assert(cl != NULL); 634 635 ct = (struct ct_data *) cl->cl_private; 636 637 sigfillset(&newmask); 638 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 639 mutex_lock(&clnt_fd_lock); 640 while (vc_fd_locks[ct_fd]) 641 cond_wait(&vc_cv[ct_fd], &clnt_fd_lock); 642 if (ct->ct_closeit && ct->ct_fd != -1) { 643 (void)_close(ct->ct_fd); 644 } 645 XDR_DESTROY(&(ct->ct_xdrs)); 646 if (ct->ct_addr.buf) 647 free(ct->ct_addr.buf); 648 mem_free(ct, sizeof(struct ct_data)); 649 mem_free(cl, sizeof(CLIENT)); 650 mutex_unlock(&clnt_fd_lock); 651 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 652 cond_signal(&vc_cv[ct_fd]); 653 } 654 655 /* 656 * Interface between xdr serializer and tcp connection. 657 * Behaves like the system calls, read & write, but keeps some error state 658 * around for the rpc level. 659 */ 660 static int 661 read_vc(ctp, buf, len) 662 caddr_t ctp; 663 caddr_t buf; 664 int len; 665 { 666 struct sockaddr sa; 667 socklen_t sal; 668 struct ct_data *ct = (struct ct_data *)(void *)ctp; 669 struct pollfd fd; 670 int milliseconds = (int)((ct->ct_wait.tv_sec * 1000) + 671 (ct->ct_wait.tv_usec / 1000)); 672 673 if (len == 0) 674 return (0); 675 fd.fd = ct->ct_fd; 676 fd.events = POLLIN; 677 for (;;) { 678 switch (_poll(&fd, 1, milliseconds)) { 679 case 0: 680 ct->ct_error.re_status = RPC_TIMEDOUT; 681 return (-1); 682 683 case -1: 684 if (errno == EINTR) 685 continue; 686 ct->ct_error.re_status = RPC_CANTRECV; 687 ct->ct_error.re_errno = errno; 688 return (-1); 689 } 690 break; 691 } 692 693 sal = sizeof(sa); 694 if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) && 695 (sa.sa_family == AF_LOCAL)) { 696 len = __msgread(ct->ct_fd, buf, (size_t)len); 697 } else { 698 len = _read(ct->ct_fd, buf, (size_t)len); 699 } 700 701 switch (len) { 702 case 0: 703 /* premature eof */ 704 ct->ct_error.re_errno = ECONNRESET; 705 ct->ct_error.re_status = RPC_CANTRECV; 706 len = -1; /* it's really an error */ 707 break; 708 709 case -1: 710 ct->ct_error.re_errno = errno; 711 ct->ct_error.re_status = RPC_CANTRECV; 712 break; 713 } 714 return (len); 715 } 716 717 static int 718 write_vc(ctp, buf, len) 719 caddr_t ctp; 720 caddr_t buf; 721 int len; 722 { 723 struct sockaddr sa; 724 socklen_t sal; 725 struct ct_data *ct = (struct ct_data *)(void *)ctp; 726 int i, cnt; 727 728 sal = sizeof(sa); 729 if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) && 730 (sa.sa_family == AF_LOCAL)) { 731 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 732 if ((i = __msgwrite(ct->ct_fd, buf, 733 (size_t)cnt)) == -1) { 734 ct->ct_error.re_errno = errno; 735 ct->ct_error.re_status = RPC_CANTSEND; 736 return (-1); 737 } 738 } 739 } else { 740 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 741 if ((i = _write(ct->ct_fd, buf, (size_t)cnt)) == -1) { 742 ct->ct_error.re_errno = errno; 743 ct->ct_error.re_status = RPC_CANTSEND; 744 return (-1); 745 } 746 } 747 } 748 return (len); 749 } 750 751 static struct clnt_ops * 752 clnt_vc_ops() 753 { 754 static struct clnt_ops ops; 755 extern mutex_t ops_lock; 756 sigset_t mask, newmask; 757 758 /* VARIABLES PROTECTED BY ops_lock: ops */ 759 760 sigfillset(&newmask); 761 thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 762 mutex_lock(&ops_lock); 763 if (ops.cl_call == NULL) { 764 ops.cl_call = clnt_vc_call; 765 ops.cl_abort = clnt_vc_abort; 766 ops.cl_geterr = clnt_vc_geterr; 767 ops.cl_freeres = clnt_vc_freeres; 768 ops.cl_destroy = clnt_vc_destroy; 769 ops.cl_control = clnt_vc_control; 770 } 771 mutex_unlock(&ops_lock); 772 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 773 return (&ops); 774 } 775 776 /* 777 * Make sure that the time is not garbage. -1 value is disallowed. 778 * Note this is different from time_not_ok in clnt_dg.c 779 */ 780 static bool_t 781 time_not_ok(t) 782 struct timeval *t; 783 { 784 return (t->tv_sec <= -1 || t->tv_sec > 100000000 || 785 t->tv_usec <= -1 || t->tv_usec > 1000000); 786 } 787 788 static int 789 __msgread(sock, buf, cnt) 790 int sock; 791 void *buf; 792 size_t cnt; 793 { 794 struct iovec iov[1]; 795 struct msghdr msg; 796 struct cmessage cm; 797 798 bzero((char *)&cm, sizeof(cm)); 799 iov[0].iov_base = buf; 800 iov[0].iov_len = cnt; 801 802 msg.msg_iov = iov; 803 msg.msg_iovlen = 1; 804 msg.msg_name = NULL; 805 msg.msg_namelen = 0; 806 msg.msg_control = (caddr_t)&cm; 807 msg.msg_controllen = sizeof(struct cmessage); 808 msg.msg_flags = 0; 809 810 return(_recvmsg(sock, &msg, 0)); 811 } 812 813 static int 814 __msgwrite(sock, buf, cnt) 815 int sock; 816 void *buf; 817 size_t cnt; 818 { 819 struct iovec iov[1]; 820 struct msghdr msg; 821 struct cmessage cm; 822 823 bzero((char *)&cm, sizeof(cm)); 824 iov[0].iov_base = buf; 825 iov[0].iov_len = cnt; 826 827 cm.cmsg.cmsg_type = SCM_CREDS; 828 cm.cmsg.cmsg_level = SOL_SOCKET; 829 cm.cmsg.cmsg_len = sizeof(struct cmessage); 830 831 msg.msg_iov = iov; 832 msg.msg_iovlen = 1; 833 msg.msg_name = NULL; 834 msg.msg_namelen = 0; 835 msg.msg_control = (caddr_t)&cm; 836 msg.msg_controllen = sizeof(struct cmessage); 837 msg.msg_flags = 0; 838 839 return(_sendmsg(sock, &msg, 0)); 840 } 841