svc_vc.c revision 290899
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) 32static char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 33static char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 34#endif 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: stable/10/lib/libc/rpc/svc_vc.c 290899 2015-11-16 01:09:25Z ngie $"); 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 73static SVCXPRT *makefd_xprt(int, u_int, u_int); 74static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *); 75static enum xprt_stat rendezvous_stat(SVCXPRT *); 76static void svc_vc_destroy(SVCXPRT *); 77static void __svc_vc_dodestroy (SVCXPRT *); 78static int read_vc(void *, void *, int); 79static int write_vc(void *, void *, int); 80static enum xprt_stat svc_vc_stat(SVCXPRT *); 81static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *); 82static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *); 83static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *); 84static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *); 85static void svc_vc_rendezvous_ops(SVCXPRT *); 86static void svc_vc_ops(SVCXPRT *); 87static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); 88static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, 89 void *in); 90 91struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */ 92 u_int sendsize; 93 u_int recvsize; 94 int maxrec; 95}; 96 97struct 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 */ 125SVCXPRT * 126svc_vc_create(fd, sendsize, recvsize) 127 int fd; 128 u_int sendsize; 129 u_int recvsize; 130{ 131 SVCXPRT *xprt; 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); 176cleanup_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 */ 188SVCXPRT * 189svc_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 238freedata: 239 if (ret->xp_ltaddr.buf != NULL) 240 mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen); 241 242 return NULL; 243} 244 245static SVCXPRT * 246makefd_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); 282done: 283 return (xprt); 284} 285 286/*ARGSUSED*/ 287static bool_t 288rendezvous_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; 305again: 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*/ 368static enum xprt_stat 369rendezvous_stat(xprt) 370 SVCXPRT *xprt; 371{ 372 373 return (XPRT_IDLE); 374} 375 376static void 377svc_vc_destroy(xprt) 378 SVCXPRT *xprt; 379{ 380 assert(xprt != NULL); 381 382 xprt_unregister(xprt); 383 __svc_vc_dodestroy(xprt); 384} 385 386static 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 free(xprt->xp_tp); 412 free(xprt->xp_netid); 413 svc_xprt_free(xprt); 414} 415 416/*ARGSUSED*/ 417static bool_t 418svc_vc_control(xprt, rq, in) 419 SVCXPRT *xprt; 420 const u_int rq; 421 void *in; 422{ 423 return (FALSE); 424} 425 426static bool_t 427svc_vc_rendezvous_control(xprt, rq, in) 428 SVCXPRT *xprt; 429 const u_int rq; 430 void *in; 431{ 432 struct cf_rendezvous *cfp; 433 434 cfp = (struct cf_rendezvous *)xprt->xp_p1; 435 if (cfp == NULL) 436 return (FALSE); 437 switch (rq) { 438 case SVCGET_CONNMAXREC: 439 *(int *)in = cfp->maxrec; 440 break; 441 case SVCSET_CONNMAXREC: 442 cfp->maxrec = *(int *)in; 443 break; 444 default: 445 return (FALSE); 446 } 447 return (TRUE); 448} 449 450/* 451 * reads data from the tcp or uip connection. 452 * any error is fatal and the connection is closed. 453 * (And a read of zero bytes is a half closed stream => error.) 454 * All read operations timeout after 35 seconds. A timeout is 455 * fatal for the connection. 456 */ 457static int 458read_vc(xprtp, buf, len) 459 void *xprtp; 460 void *buf; 461 int len; 462{ 463 SVCXPRT *xprt; 464 int sock; 465 int milliseconds = 35 * 1000; 466 struct pollfd pollfd; 467 struct cf_conn *cfp; 468 469 xprt = (SVCXPRT *)xprtp; 470 assert(xprt != NULL); 471 472 sock = xprt->xp_fd; 473 474 cfp = (struct cf_conn *)xprt->xp_p1; 475 476 if (cfp->nonblock) { 477 len = _read(sock, buf, (size_t)len); 478 if (len < 0) { 479 if (errno == EAGAIN) 480 len = 0; 481 else 482 goto fatal_err; 483 } 484 if (len != 0) 485 gettimeofday(&cfp->last_recv_time, NULL); 486 return len; 487 } 488 489 do { 490 pollfd.fd = sock; 491 pollfd.events = POLLIN; 492 pollfd.revents = 0; 493 switch (_poll(&pollfd, 1, milliseconds)) { 494 case -1: 495 if (errno == EINTR) 496 continue; 497 /*FALLTHROUGH*/ 498 case 0: 499 goto fatal_err; 500 501 default: 502 break; 503 } 504 } while ((pollfd.revents & POLLIN) == 0); 505 506 if ((len = _read(sock, buf, (size_t)len)) > 0) { 507 gettimeofday(&cfp->last_recv_time, NULL); 508 return (len); 509 } 510 511fatal_err: 512 ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 513 return (-1); 514} 515 516/* 517 * writes data to the tcp connection. 518 * Any error is fatal and the connection is closed. 519 */ 520static int 521write_vc(xprtp, buf, len) 522 void *xprtp; 523 void *buf; 524 int len; 525{ 526 SVCXPRT *xprt; 527 int i, cnt; 528 struct cf_conn *cd; 529 struct timeval tv0, tv1; 530 531 xprt = (SVCXPRT *)xprtp; 532 assert(xprt != NULL); 533 534 cd = (struct cf_conn *)xprt->xp_p1; 535 536 if (cd->nonblock) 537 gettimeofday(&tv0, NULL); 538 539 for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) { 540 i = _write(xprt->xp_fd, buf, (size_t)cnt); 541 if (i < 0) { 542 if (errno != EAGAIN || !cd->nonblock) { 543 cd->strm_stat = XPRT_DIED; 544 return (-1); 545 } 546 if (cd->nonblock) { 547 /* 548 * For non-blocking connections, do not 549 * take more than 2 seconds writing the 550 * data out. 551 * 552 * XXX 2 is an arbitrary amount. 553 */ 554 gettimeofday(&tv1, NULL); 555 if (tv1.tv_sec - tv0.tv_sec >= 2) { 556 cd->strm_stat = XPRT_DIED; 557 return (-1); 558 } 559 } 560 i = 0; 561 } 562 } 563 564 return (len); 565} 566 567static enum xprt_stat 568svc_vc_stat(xprt) 569 SVCXPRT *xprt; 570{ 571 struct cf_conn *cd; 572 573 assert(xprt != NULL); 574 575 cd = (struct cf_conn *)(xprt->xp_p1); 576 577 if (cd->strm_stat == XPRT_DIED) 578 return (XPRT_DIED); 579 if (! xdrrec_eof(&(cd->xdrs))) 580 return (XPRT_MOREREQS); 581 return (XPRT_IDLE); 582} 583 584static bool_t 585svc_vc_recv(xprt, msg) 586 SVCXPRT *xprt; 587 struct rpc_msg *msg; 588{ 589 struct cf_conn *cd; 590 XDR *xdrs; 591 592 assert(xprt != NULL); 593 assert(msg != NULL); 594 595 cd = (struct cf_conn *)(xprt->xp_p1); 596 xdrs = &(cd->xdrs); 597 598 if (cd->nonblock) { 599 if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE)) 600 return FALSE; 601 } else { 602 (void)xdrrec_skiprecord(xdrs); 603 } 604 605 xdrs->x_op = XDR_DECODE; 606 if (xdr_callmsg(xdrs, msg)) { 607 cd->x_id = msg->rm_xid; 608 return (TRUE); 609 } 610 cd->strm_stat = XPRT_DIED; 611 return (FALSE); 612} 613 614static bool_t 615svc_vc_getargs(xprt, xdr_args, args_ptr) 616 SVCXPRT *xprt; 617 xdrproc_t xdr_args; 618 void *args_ptr; 619{ 620 struct cf_conn *cd; 621 622 assert(xprt != NULL); 623 cd = (struct cf_conn *)(xprt->xp_p1); 624 return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), 625 &cd->xdrs, xdr_args, args_ptr)); 626} 627 628static bool_t 629svc_vc_freeargs(xprt, xdr_args, args_ptr) 630 SVCXPRT *xprt; 631 xdrproc_t xdr_args; 632 void *args_ptr; 633{ 634 XDR *xdrs; 635 636 assert(xprt != NULL); 637 /* args_ptr may be NULL */ 638 639 xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs); 640 641 xdrs->x_op = XDR_FREE; 642 return ((*xdr_args)(xdrs, args_ptr)); 643} 644 645static bool_t 646svc_vc_reply(xprt, msg) 647 SVCXPRT *xprt; 648 struct rpc_msg *msg; 649{ 650 struct cf_conn *cd; 651 XDR *xdrs; 652 bool_t rstat; 653 xdrproc_t xdr_proc; 654 caddr_t xdr_where; 655 u_int pos; 656 657 assert(xprt != NULL); 658 assert(msg != NULL); 659 660 cd = (struct cf_conn *)(xprt->xp_p1); 661 xdrs = &(cd->xdrs); 662 663 xdrs->x_op = XDR_ENCODE; 664 msg->rm_xid = cd->x_id; 665 rstat = TRUE; 666 if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 667 msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 668 xdr_proc = msg->acpted_rply.ar_results.proc; 669 xdr_where = msg->acpted_rply.ar_results.where; 670 msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; 671 msg->acpted_rply.ar_results.where = NULL; 672 673 pos = XDR_GETPOS(xdrs); 674 if (!xdr_replymsg(xdrs, msg) || 675 !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) { 676 XDR_SETPOS(xdrs, pos); 677 rstat = FALSE; 678 } 679 } else { 680 rstat = xdr_replymsg(xdrs, msg); 681 } 682 683 if (rstat) 684 (void)xdrrec_endofrecord(xdrs, TRUE); 685 686 return (rstat); 687} 688 689static void 690svc_vc_ops(xprt) 691 SVCXPRT *xprt; 692{ 693 static struct xp_ops ops; 694 static struct xp_ops2 ops2; 695 696/* VARIABLES PROTECTED BY ops_lock: ops, ops2 */ 697 698 mutex_lock(&ops_lock); 699 if (ops.xp_recv == NULL) { 700 ops.xp_recv = svc_vc_recv; 701 ops.xp_stat = svc_vc_stat; 702 ops.xp_getargs = svc_vc_getargs; 703 ops.xp_reply = svc_vc_reply; 704 ops.xp_freeargs = svc_vc_freeargs; 705 ops.xp_destroy = svc_vc_destroy; 706 ops2.xp_control = svc_vc_control; 707 } 708 xprt->xp_ops = &ops; 709 xprt->xp_ops2 = &ops2; 710 mutex_unlock(&ops_lock); 711} 712 713static void 714svc_vc_rendezvous_ops(xprt) 715 SVCXPRT *xprt; 716{ 717 static struct xp_ops ops; 718 static struct xp_ops2 ops2; 719 720 mutex_lock(&ops_lock); 721 if (ops.xp_recv == NULL) { 722 ops.xp_recv = rendezvous_request; 723 ops.xp_stat = rendezvous_stat; 724 ops.xp_getargs = 725 (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort; 726 ops.xp_reply = 727 (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort; 728 ops.xp_freeargs = 729 (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort, 730 ops.xp_destroy = svc_vc_destroy; 731 ops2.xp_control = svc_vc_rendezvous_control; 732 } 733 xprt->xp_ops = &ops; 734 xprt->xp_ops2 = &ops2; 735 mutex_unlock(&ops_lock); 736} 737 738/* 739 * Get the effective UID of the sending process. Used by rpcbind, keyserv 740 * and rpc.yppasswdd on AF_LOCAL. 741 */ 742int 743__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { 744 int sock, ret; 745 gid_t egid; 746 uid_t euid; 747 struct sockaddr *sa; 748 749 sock = transp->xp_fd; 750 sa = (struct sockaddr *)transp->xp_rtaddr.buf; 751 if (sa->sa_family == AF_LOCAL) { 752 ret = getpeereid(sock, &euid, &egid); 753 if (ret == 0) 754 *uid = euid; 755 return (ret); 756 } else 757 return (-1); 758} 759 760/* 761 * Destroy xprts that have not have had any activity in 'timeout' seconds. 762 * If 'cleanblock' is true, blocking connections (the default) are also 763 * cleaned. If timeout is 0, the least active connection is picked. 764 */ 765bool_t 766__svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock) 767{ 768 int i, ncleaned; 769 SVCXPRT *xprt, *least_active; 770 struct timeval tv, tdiff, tmax; 771 struct cf_conn *cd; 772 773 gettimeofday(&tv, NULL); 774 tmax.tv_sec = tmax.tv_usec = 0; 775 least_active = NULL; 776 rwlock_wrlock(&svc_fd_lock); 777 for (i = ncleaned = 0; i <= svc_maxfd; i++) { 778 if (FD_ISSET(i, fds)) { 779 xprt = __svc_xports[i]; 780 if (xprt == NULL || xprt->xp_ops == NULL || 781 xprt->xp_ops->xp_recv != svc_vc_recv) 782 continue; 783 cd = (struct cf_conn *)xprt->xp_p1; 784 if (!cleanblock && !cd->nonblock) 785 continue; 786 if (timeout == 0) { 787 timersub(&tv, &cd->last_recv_time, &tdiff); 788 if (timercmp(&tdiff, &tmax, >)) { 789 tmax = tdiff; 790 least_active = xprt; 791 } 792 continue; 793 } 794 if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) { 795 __xprt_unregister_unlocked(xprt); 796 __svc_vc_dodestroy(xprt); 797 ncleaned++; 798 } 799 } 800 } 801 if (timeout == 0 && least_active != NULL) { 802 __xprt_unregister_unlocked(least_active); 803 __svc_vc_dodestroy(least_active); 804 ncleaned++; 805 } 806 rwlock_unlock(&svc_fd_lock); 807 return ncleaned > 0 ? TRUE : FALSE; 808} 809