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