1 /* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ 2 3 /* 4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5 * unrestricted use provided that this legend is included on all tape 6 * media and as a part of the software program in whole or part. Users 7 * may copy or modify Sun RPC without charge, but are not authorized 8 * to license or distribute it to anyone else except as part of a product or 9 * program developed by the user. 10 * 11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 14 * 15 * Sun RPC is provided with no support and without any obligation on the 16 * part of Sun Microsystems, Inc. to assist in its use, correction, 17 * modification or enhancement. 18 * 19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 21 * OR ANY PART THEREOF. 22 * 23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24 * or profits or other special, indirect and consequential damages, even if 25 * Sun has been advised of the possibility of such damages. 26 * 27 * Sun Microsystems, Inc. 28 * 2550 Garcia Avenue 29 * Mountain View, California 94043 30 */ 31 32 #if defined(LIBC_SCCS) && !defined(lint) 33 static char *sccsid = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 34 static char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 35 #endif 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 39 /* 40 * svc_vc.c, Server side for Connection Oriented based RPC. 41 * 42 * Actually implements two flavors of transporter - 43 * a tcp rendezvouser (a listner and connection establisher) 44 * and a record/tcp stream. 45 */ 46 47 #include "namespace.h" 48 #include "reentrant.h" 49 #include <sys/types.h> 50 #include <sys/param.h> 51 #include <sys/poll.h> 52 #include <sys/socket.h> 53 #include <sys/un.h> 54 #include <sys/time.h> 55 #include <sys/uio.h> 56 #include <netinet/in.h> 57 #include <netinet/tcp.h> 58 59 #include <assert.h> 60 #include <err.h> 61 #include <errno.h> 62 #include <fcntl.h> 63 #include <stdio.h> 64 #include <stdlib.h> 65 #include <string.h> 66 #include <unistd.h> 67 68 #include <rpc/rpc.h> 69 70 #include "rpc_com.h" 71 #include "un-namespace.h" 72 73 struct cmessage { 74 struct cmsghdr cmsg; 75 struct cmsgcred cmcred; 76 }; 77 78 extern rwlock_t svc_fd_lock; 79 80 static SVCXPRT *makefd_xprt(int, u_int, u_int); 81 static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *); 82 static enum xprt_stat rendezvous_stat(SVCXPRT *); 83 static void svc_vc_destroy(SVCXPRT *); 84 static void __svc_vc_dodestroy (SVCXPRT *); 85 static int read_vc(void *, void *, int); 86 static int write_vc(void *, void *, int); 87 static enum xprt_stat svc_vc_stat(SVCXPRT *); 88 static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *); 89 static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *); 90 static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *); 91 static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *); 92 static void svc_vc_rendezvous_ops(SVCXPRT *); 93 static void svc_vc_ops(SVCXPRT *); 94 static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); 95 static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, 96 void *in); 97 static int __msgread_withcred(int, void *, size_t, struct cmessage *); 98 static int __msgwrite(int, void *, size_t); 99 100 struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */ 101 u_int sendsize; 102 u_int recvsize; 103 int maxrec; 104 }; 105 106 struct cf_conn { /* kept in xprt->xp_p1 for actual connection */ 107 enum xprt_stat strm_stat; 108 u_int32_t x_id; 109 XDR xdrs; 110 char verf_body[MAX_AUTH_BYTES]; 111 u_int sendsize; 112 u_int recvsize; 113 int maxrec; 114 bool_t nonblock; 115 struct timeval last_recv_time; 116 }; 117 118 /* 119 * Usage: 120 * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); 121 * 122 * Creates, registers, and returns a (rpc) tcp based transporter. 123 * Once *xprt is initialized, it is registered as a transporter 124 * see (svc.h, xprt_register). This routine returns 125 * a NULL if a problem occurred. 126 * 127 * The filedescriptor passed in is expected to refer to a bound, but 128 * not yet connected socket. 129 * 130 * Since streams do buffered io similar to stdio, the caller can specify 131 * how big the send and receive buffers are via the second and third parms; 132 * 0 => use the system default. 133 */ 134 SVCXPRT * 135 svc_vc_create(fd, sendsize, recvsize) 136 int fd; 137 u_int sendsize; 138 u_int recvsize; 139 { 140 SVCXPRT *xprt; 141 struct cf_rendezvous *r = NULL; 142 struct __rpc_sockinfo si; 143 struct sockaddr_storage sslocal; 144 socklen_t slen; 145 146 r = mem_alloc(sizeof(*r)); 147 if (r == NULL) { 148 warnx("svc_vc_create: out of memory"); 149 goto cleanup_svc_vc_create; 150 } 151 if (!__rpc_fd2sockinfo(fd, &si)) 152 return NULL; 153 r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); 154 r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); 155 r->maxrec = __svc_maxrec; 156 xprt = mem_alloc(sizeof(SVCXPRT)); 157 if (xprt == NULL) { 158 warnx("svc_vc_create: out of memory"); 159 goto cleanup_svc_vc_create; 160 } 161 xprt->xp_tp = NULL; 162 xprt->xp_p1 = r; 163 xprt->xp_p2 = NULL; 164 xprt->xp_p3 = NULL; 165 xprt->xp_verf = _null_auth; 166 svc_vc_rendezvous_ops(xprt); 167 xprt->xp_port = (u_short)-1; /* It is the rendezvouser */ 168 xprt->xp_fd = fd; 169 170 slen = sizeof (struct sockaddr_storage); 171 if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) { 172 warnx("svc_vc_create: could not retrieve local addr"); 173 goto cleanup_svc_vc_create; 174 } 175 176 xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len; 177 xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len); 178 if (xprt->xp_ltaddr.buf == NULL) { 179 warnx("svc_vc_create: no mem for local addr"); 180 goto cleanup_svc_vc_create; 181 } 182 memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len); 183 184 xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); 185 xprt_register(xprt); 186 return (xprt); 187 cleanup_svc_vc_create: 188 if (r != NULL) 189 mem_free(r, sizeof(*r)); 190 return (NULL); 191 } 192 193 /* 194 * Like svtcp_create(), except the routine takes any *open* UNIX file 195 * descriptor as its first input. 196 */ 197 SVCXPRT * 198 svc_fd_create(fd, sendsize, recvsize) 199 int fd; 200 u_int sendsize; 201 u_int recvsize; 202 { 203 struct sockaddr_storage ss; 204 socklen_t slen; 205 SVCXPRT *ret; 206 207 assert(fd != -1); 208 209 ret = makefd_xprt(fd, sendsize, recvsize); 210 if (ret == NULL) 211 return NULL; 212 213 slen = sizeof (struct sockaddr_storage); 214 if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 215 warnx("svc_fd_create: could not retrieve local addr"); 216 goto freedata; 217 } 218 ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len; 219 ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len); 220 if (ret->xp_ltaddr.buf == NULL) { 221 warnx("svc_fd_create: no mem for local addr"); 222 goto freedata; 223 } 224 memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len); 225 226 slen = sizeof (struct sockaddr_storage); 227 if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 228 warnx("svc_fd_create: could not retrieve remote addr"); 229 goto freedata; 230 } 231 ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len; 232 ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len); 233 if (ret->xp_rtaddr.buf == NULL) { 234 warnx("svc_fd_create: no mem for local addr"); 235 goto freedata; 236 } 237 memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len); 238 #ifdef PORTMAP 239 if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) { 240 ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf; 241 ret->xp_addrlen = sizeof (struct sockaddr_in); 242 } 243 #endif /* PORTMAP */ 244 245 return ret; 246 247 freedata: 248 if (ret->xp_ltaddr.buf != NULL) 249 mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen); 250 251 return NULL; 252 } 253 254 static SVCXPRT * 255 makefd_xprt(fd, sendsize, recvsize) 256 int fd; 257 u_int sendsize; 258 u_int recvsize; 259 { 260 SVCXPRT *xprt; 261 struct cf_conn *cd; 262 const char *netid; 263 struct __rpc_sockinfo si; 264 265 assert(fd != -1); 266 267 xprt = mem_alloc(sizeof(SVCXPRT)); 268 if (xprt == NULL) { 269 warnx("svc_vc: makefd_xprt: out of memory"); 270 goto done; 271 } 272 memset(xprt, 0, sizeof *xprt); 273 cd = mem_alloc(sizeof(struct cf_conn)); 274 if (cd == NULL) { 275 warnx("svc_tcp: makefd_xprt: out of memory"); 276 mem_free(xprt, sizeof(SVCXPRT)); 277 xprt = NULL; 278 goto done; 279 } 280 cd->strm_stat = XPRT_IDLE; 281 xdrrec_create(&(cd->xdrs), sendsize, recvsize, 282 xprt, read_vc, write_vc); 283 xprt->xp_p1 = cd; 284 xprt->xp_verf.oa_base = cd->verf_body; 285 svc_vc_ops(xprt); /* truely deals with calls */ 286 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ 287 xprt->xp_fd = fd; 288 if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid)) 289 xprt->xp_netid = strdup(netid); 290 291 xprt_register(xprt); 292 done: 293 return (xprt); 294 } 295 296 /*ARGSUSED*/ 297 static bool_t 298 rendezvous_request(xprt, msg) 299 SVCXPRT *xprt; 300 struct rpc_msg *msg; 301 { 302 int sock, flags; 303 struct cf_rendezvous *r; 304 struct cf_conn *cd; 305 struct sockaddr_storage addr; 306 socklen_t len; 307 struct __rpc_sockinfo si; 308 SVCXPRT *newxprt; 309 fd_set cleanfds; 310 311 assert(xprt != NULL); 312 assert(msg != NULL); 313 314 r = (struct cf_rendezvous *)xprt->xp_p1; 315 again: 316 len = sizeof addr; 317 if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, 318 &len)) < 0) { 319 if (errno == EINTR) 320 goto again; 321 /* 322 * Clean out the most idle file descriptor when we're 323 * running out. 324 */ 325 if (errno == EMFILE || errno == ENFILE) { 326 cleanfds = svc_fdset; 327 __svc_clean_idle(&cleanfds, 0, FALSE); 328 goto again; 329 } 330 return (FALSE); 331 } 332 /* 333 * make a new transporter (re-uses xprt) 334 */ 335 newxprt = makefd_xprt(sock, r->sendsize, r->recvsize); 336 newxprt->xp_rtaddr.buf = mem_alloc(len); 337 if (newxprt->xp_rtaddr.buf == NULL) 338 return (FALSE); 339 memcpy(newxprt->xp_rtaddr.buf, &addr, len); 340 newxprt->xp_rtaddr.len = len; 341 #ifdef PORTMAP 342 if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) { 343 newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf; 344 newxprt->xp_addrlen = sizeof (struct sockaddr_in); 345 } 346 #endif /* PORTMAP */ 347 if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) { 348 len = 1; 349 /* XXX fvdl - is this useful? */ 350 _setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len)); 351 } 352 353 cd = (struct cf_conn *)newxprt->xp_p1; 354 355 cd->recvsize = r->recvsize; 356 cd->sendsize = r->sendsize; 357 cd->maxrec = r->maxrec; 358 359 if (cd->maxrec != 0) { 360 flags = _fcntl(sock, F_GETFL, 0); 361 if (flags == -1) 362 return (FALSE); 363 if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) 364 return (FALSE); 365 if (cd->recvsize > cd->maxrec) 366 cd->recvsize = cd->maxrec; 367 cd->nonblock = TRUE; 368 __xdrrec_setnonblock(&cd->xdrs, cd->maxrec); 369 } else 370 cd->nonblock = FALSE; 371 372 gettimeofday(&cd->last_recv_time, NULL); 373 374 return (FALSE); /* there is never an rpc msg to be processed */ 375 } 376 377 /*ARGSUSED*/ 378 static enum xprt_stat 379 rendezvous_stat(xprt) 380 SVCXPRT *xprt; 381 { 382 383 return (XPRT_IDLE); 384 } 385 386 static void 387 svc_vc_destroy(xprt) 388 SVCXPRT *xprt; 389 { 390 assert(xprt != NULL); 391 392 xprt_unregister(xprt); 393 __svc_vc_dodestroy(xprt); 394 } 395 396 static void 397 __svc_vc_dodestroy(xprt) 398 SVCXPRT *xprt; 399 { 400 struct cf_conn *cd; 401 struct cf_rendezvous *r; 402 403 cd = (struct cf_conn *)xprt->xp_p1; 404 405 if (xprt->xp_fd != RPC_ANYFD) 406 (void)_close(xprt->xp_fd); 407 if (xprt->xp_port != 0) { 408 /* a rendezvouser socket */ 409 r = (struct cf_rendezvous *)xprt->xp_p1; 410 mem_free(r, sizeof (struct cf_rendezvous)); 411 xprt->xp_port = 0; 412 } else { 413 /* an actual connection socket */ 414 XDR_DESTROY(&(cd->xdrs)); 415 mem_free(cd, sizeof(struct cf_conn)); 416 } 417 if (xprt->xp_rtaddr.buf) 418 mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); 419 if (xprt->xp_ltaddr.buf) 420 mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); 421 if (xprt->xp_tp) 422 free(xprt->xp_tp); 423 if (xprt->xp_netid) 424 free(xprt->xp_netid); 425 mem_free(xprt, sizeof(SVCXPRT)); 426 } 427 428 /*ARGSUSED*/ 429 static bool_t 430 svc_vc_control(xprt, rq, in) 431 SVCXPRT *xprt; 432 const u_int rq; 433 void *in; 434 { 435 return (FALSE); 436 } 437 438 static bool_t 439 svc_vc_rendezvous_control(xprt, rq, in) 440 SVCXPRT *xprt; 441 const u_int rq; 442 void *in; 443 { 444 struct cf_rendezvous *cfp; 445 446 cfp = (struct cf_rendezvous *)xprt->xp_p1; 447 if (cfp == NULL) 448 return (FALSE); 449 switch (rq) { 450 case SVCGET_CONNMAXREC: 451 *(int *)in = cfp->maxrec; 452 break; 453 case SVCSET_CONNMAXREC: 454 cfp->maxrec = *(int *)in; 455 break; 456 default: 457 return (FALSE); 458 } 459 return (TRUE); 460 } 461 462 /* 463 * reads data from the tcp or uip connection. 464 * any error is fatal and the connection is closed. 465 * (And a read of zero bytes is a half closed stream => error.) 466 * All read operations timeout after 35 seconds. A timeout is 467 * fatal for the connection. 468 */ 469 static int 470 read_vc(xprtp, buf, len) 471 void *xprtp; 472 void *buf; 473 int len; 474 { 475 SVCXPRT *xprt; 476 int sock; 477 int milliseconds = 35 * 1000; 478 struct pollfd pollfd; 479 struct sockaddr *sa; 480 struct cmessage *cm; 481 struct cf_conn *cfp; 482 483 xprt = (SVCXPRT *)xprtp; 484 assert(xprt != NULL); 485 486 sock = xprt->xp_fd; 487 488 cfp = (struct cf_conn *)xprt->xp_p1; 489 490 if (cfp->nonblock) { 491 len = _read(sock, buf, (size_t)len); 492 if (len < 0) { 493 if (errno == EAGAIN) 494 len = 0; 495 else 496 goto fatal_err; 497 } 498 if (len != 0) 499 gettimeofday(&cfp->last_recv_time, NULL); 500 return len; 501 } 502 503 do { 504 pollfd.fd = sock; 505 pollfd.events = POLLIN; 506 pollfd.revents = 0; 507 switch (_poll(&pollfd, 1, milliseconds)) { 508 case -1: 509 if (errno == EINTR) 510 continue; 511 /*FALLTHROUGH*/ 512 case 0: 513 goto fatal_err; 514 515 default: 516 break; 517 } 518 } while ((pollfd.revents & POLLIN) == 0); 519 520 cm = NULL; 521 sa = (struct sockaddr *)xprt->xp_rtaddr.buf; 522 if (sa->sa_family == AF_LOCAL) { 523 cm = (struct cmessage *)xprt->xp_verf.oa_base; 524 if ((len = __msgread_withcred(sock, buf, len, cm)) > 0) { 525 xprt->xp_p2 = &cm->cmcred; 526 return (len); 527 } else 528 goto fatal_err; 529 } else { 530 if ((len = _read(sock, buf, (size_t)len)) > 0) { 531 gettimeofday(&cfp->last_recv_time, NULL); 532 return (len); 533 } 534 } 535 536 fatal_err: 537 ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 538 return (-1); 539 } 540 541 /* 542 * writes data to the tcp connection. 543 * Any error is fatal and the connection is closed. 544 */ 545 static int 546 write_vc(xprtp, buf, len) 547 void *xprtp; 548 void *buf; 549 int len; 550 { 551 SVCXPRT *xprt; 552 int i, cnt; 553 struct sockaddr *sa; 554 struct cf_conn *cd; 555 struct timeval tv0, tv1; 556 557 xprt = (SVCXPRT *)xprtp; 558 assert(xprt != NULL); 559 560 cd = (struct cf_conn *)xprt->xp_p1; 561 562 if (cd->nonblock) 563 gettimeofday(&tv0, NULL); 564 565 sa = (struct sockaddr *)xprt->xp_rtaddr.buf; 566 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 567 if (sa->sa_family == AF_LOCAL) 568 i = __msgwrite(xprt->xp_fd, buf, (size_t)cnt); 569 else 570 i = _write(xprt->xp_fd, buf, (size_t)cnt); 571 if (i < 0) { 572 if (errno != EAGAIN || !cd->nonblock) { 573 cd->strm_stat = XPRT_DIED; 574 return (-1); 575 } 576 if (cd->nonblock && i != cnt) { 577 /* 578 * For non-blocking connections, do not 579 * take more than 2 seconds writing the 580 * data out. 581 * 582 * XXX 2 is an arbitrary amount. 583 */ 584 gettimeofday(&tv1, NULL); 585 if (tv1.tv_sec - tv0.tv_sec >= 2) { 586 cd->strm_stat = XPRT_DIED; 587 return (-1); 588 } 589 } 590 } 591 } 592 593 return (len); 594 } 595 596 static enum xprt_stat 597 svc_vc_stat(xprt) 598 SVCXPRT *xprt; 599 { 600 struct cf_conn *cd; 601 602 assert(xprt != NULL); 603 604 cd = (struct cf_conn *)(xprt->xp_p1); 605 606 if (cd->strm_stat == XPRT_DIED) 607 return (XPRT_DIED); 608 if (! xdrrec_eof(&(cd->xdrs))) 609 return (XPRT_MOREREQS); 610 return (XPRT_IDLE); 611 } 612 613 static bool_t 614 svc_vc_recv(xprt, msg) 615 SVCXPRT *xprt; 616 struct rpc_msg *msg; 617 { 618 struct cf_conn *cd; 619 XDR *xdrs; 620 621 assert(xprt != NULL); 622 assert(msg != NULL); 623 624 cd = (struct cf_conn *)(xprt->xp_p1); 625 xdrs = &(cd->xdrs); 626 627 if (cd->nonblock) { 628 if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE)) 629 return FALSE; 630 } 631 632 xdrs->x_op = XDR_DECODE; 633 (void)xdrrec_skiprecord(xdrs); 634 if (xdr_callmsg(xdrs, msg)) { 635 cd->x_id = msg->rm_xid; 636 return (TRUE); 637 } 638 cd->strm_stat = XPRT_DIED; 639 return (FALSE); 640 } 641 642 static bool_t 643 svc_vc_getargs(xprt, xdr_args, args_ptr) 644 SVCXPRT *xprt; 645 xdrproc_t xdr_args; 646 void *args_ptr; 647 { 648 649 assert(xprt != NULL); 650 /* args_ptr may be NULL */ 651 return ((*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs), 652 args_ptr)); 653 } 654 655 static bool_t 656 svc_vc_freeargs(xprt, xdr_args, args_ptr) 657 SVCXPRT *xprt; 658 xdrproc_t xdr_args; 659 void *args_ptr; 660 { 661 XDR *xdrs; 662 663 assert(xprt != NULL); 664 /* args_ptr may be NULL */ 665 666 xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs); 667 668 xdrs->x_op = XDR_FREE; 669 return ((*xdr_args)(xdrs, args_ptr)); 670 } 671 672 static bool_t 673 svc_vc_reply(xprt, msg) 674 SVCXPRT *xprt; 675 struct rpc_msg *msg; 676 { 677 struct cf_conn *cd; 678 XDR *xdrs; 679 bool_t rstat; 680 681 assert(xprt != NULL); 682 assert(msg != NULL); 683 684 cd = (struct cf_conn *)(xprt->xp_p1); 685 xdrs = &(cd->xdrs); 686 687 xdrs->x_op = XDR_ENCODE; 688 msg->rm_xid = cd->x_id; 689 rstat = xdr_replymsg(xdrs, msg); 690 (void)xdrrec_endofrecord(xdrs, TRUE); 691 return (rstat); 692 } 693 694 static void 695 svc_vc_ops(xprt) 696 SVCXPRT *xprt; 697 { 698 static struct xp_ops ops; 699 static struct xp_ops2 ops2; 700 extern mutex_t ops_lock; 701 702 /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */ 703 704 mutex_lock(&ops_lock); 705 if (ops.xp_recv == NULL) { 706 ops.xp_recv = svc_vc_recv; 707 ops.xp_stat = svc_vc_stat; 708 ops.xp_getargs = svc_vc_getargs; 709 ops.xp_reply = svc_vc_reply; 710 ops.xp_freeargs = svc_vc_freeargs; 711 ops.xp_destroy = svc_vc_destroy; 712 ops2.xp_control = svc_vc_control; 713 } 714 xprt->xp_ops = &ops; 715 xprt->xp_ops2 = &ops2; 716 mutex_unlock(&ops_lock); 717 } 718 719 static void 720 svc_vc_rendezvous_ops(xprt) 721 SVCXPRT *xprt; 722 { 723 static struct xp_ops ops; 724 static struct xp_ops2 ops2; 725 extern mutex_t ops_lock; 726 727 mutex_lock(&ops_lock); 728 if (ops.xp_recv == NULL) { 729 ops.xp_recv = rendezvous_request; 730 ops.xp_stat = rendezvous_stat; 731 ops.xp_getargs = 732 (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort; 733 ops.xp_reply = 734 (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort; 735 ops.xp_freeargs = 736 (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort, 737 ops.xp_destroy = svc_vc_destroy; 738 ops2.xp_control = svc_vc_rendezvous_control; 739 } 740 xprt->xp_ops = &ops; 741 xprt->xp_ops2 = &ops2; 742 mutex_unlock(&ops_lock); 743 } 744 745 int 746 __msgread_withcred(sock, buf, cnt, cmp) 747 int sock; 748 void *buf; 749 size_t cnt; 750 struct cmessage *cmp; 751 { 752 struct iovec iov[1]; 753 struct msghdr msg; 754 union { 755 struct cmsghdr cmsg; 756 char control[CMSG_SPACE(sizeof(struct cmsgcred))]; 757 } cm; 758 int ret; 759 760 761 bzero(&cm, sizeof(cm)); 762 iov[0].iov_base = buf; 763 iov[0].iov_len = cnt; 764 765 msg.msg_iov = iov; 766 msg.msg_iovlen = 1; 767 msg.msg_name = NULL; 768 msg.msg_namelen = 0; 769 msg.msg_control = &cm; 770 msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred)); 771 msg.msg_flags = 0; 772 773 ret = _recvmsg(sock, &msg, 0); 774 bcopy(&cm.cmsg, &cmp->cmsg, sizeof(cmp->cmsg)); 775 bcopy(CMSG_DATA(&cm), &cmp->cmcred, sizeof(cmp->cmcred)); 776 777 if (msg.msg_controllen == 0 || 778 (msg.msg_flags & MSG_CTRUNC) != 0) 779 return (-1); 780 781 return (ret); 782 } 783 784 static int 785 __msgwrite(sock, buf, cnt) 786 int sock; 787 void *buf; 788 size_t cnt; 789 { 790 struct iovec iov[1]; 791 struct msghdr msg; 792 struct cmessage cm; 793 794 bzero((char *)&cm, sizeof(cm)); 795 iov[0].iov_base = buf; 796 iov[0].iov_len = cnt; 797 798 cm.cmsg.cmsg_type = SCM_CREDS; 799 cm.cmsg.cmsg_level = SOL_SOCKET; 800 cm.cmsg.cmsg_len = sizeof(struct cmessage); 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 = &cm; 807 msg.msg_controllen = sizeof(struct cmessage); 808 msg.msg_flags = 0; 809 810 return(_sendmsg(sock, &msg, 0)); 811 } 812 813 /* 814 * Get the effective UID of the sending process. Used by rpcbind and keyserv 815 * (AF_LOCAL). 816 */ 817 int 818 __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) 819 { 820 struct cmsgcred *cmcred; 821 struct cmessage *cm; 822 struct cmsghdr *cmp; 823 824 cm = (struct cmessage *)transp->xp_verf.oa_base; 825 826 if (cm == NULL) 827 return (-1); 828 cmp = &cm->cmsg; 829 if (cmp == NULL || cmp->cmsg_level != SOL_SOCKET || 830 cmp->cmsg_type != SCM_CREDS) 831 return (-1); 832 833 cmcred = __svc_getcallercreds(transp); 834 if (cmcred == NULL) 835 return (-1); 836 *uid = cmcred->cmcred_euid; 837 return (0); 838 } 839 840 /* 841 * Destroy xprts that have not have had any activity in 'timeout' seconds. 842 * If 'cleanblock' is true, blocking connections (the default) are also 843 * cleaned. If timeout is 0, the least active connection is picked. 844 */ 845 bool_t 846 __svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock) 847 { 848 int i, ncleaned; 849 SVCXPRT *xprt, *least_active; 850 struct timeval tv, tdiff, tmax; 851 struct cf_conn *cd; 852 853 gettimeofday(&tv, NULL); 854 tmax.tv_sec = tmax.tv_usec = 0; 855 least_active = NULL; 856 rwlock_wrlock(&svc_fd_lock); 857 for (i = ncleaned = 0; i <= svc_maxfd; i++) { 858 if (FD_ISSET(i, fds)) { 859 xprt = __svc_xports[i]; 860 if (xprt == NULL || xprt->xp_ops == NULL || 861 xprt->xp_ops->xp_recv != svc_vc_recv) 862 continue; 863 cd = (struct cf_conn *)xprt->xp_p1; 864 if (!cleanblock && !cd->nonblock) 865 continue; 866 if (timeout == 0) { 867 timersub(&tv, &cd->last_recv_time, &tdiff); 868 if (timercmp(&tdiff, &tmax, >)) { 869 tmax = tdiff; 870 least_active = xprt; 871 } 872 continue; 873 } 874 if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) { 875 __xprt_unregister_unlocked(xprt); 876 __svc_vc_dodestroy(xprt); 877 ncleaned++; 878 } 879 } 880 } 881 if (timeout == 0 && least_active != NULL) { 882 __xprt_unregister_unlocked(least_active); 883 __svc_vc_dodestroy(least_active); 884 ncleaned++; 885 } 886 rwlock_unlock(&svc_fd_lock); 887 return ncleaned > 0 ? TRUE : FALSE; 888 } 889