svc_vc.c revision 116391
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) 33static char *sccsid = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 34static char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 35#endif 36#include <sys/cdefs.h> 37__FBSDID("$FreeBSD: head/lib/libc/rpc/svc_vc.c 116391 2003-06-15 10:32:01Z mbr $"); 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 73extern rwlock_t svc_fd_lock; 74 75static SVCXPRT *makefd_xprt(int, u_int, u_int); 76static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *); 77static enum xprt_stat rendezvous_stat(SVCXPRT *); 78static void svc_vc_destroy(SVCXPRT *); 79static void __svc_vc_dodestroy (SVCXPRT *); 80static int read_vc(void *, void *, int); 81static int write_vc(void *, void *, int); 82static enum xprt_stat svc_vc_stat(SVCXPRT *); 83static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *); 84static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *); 85static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *); 86static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *); 87static void svc_vc_rendezvous_ops(SVCXPRT *); 88static void svc_vc_ops(SVCXPRT *); 89static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); 90static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, 91 void *in); 92static int __msgwrite(int, void *, size_t); 93 94struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */ 95 u_int sendsize; 96 u_int recvsize; 97 int maxrec; 98}; 99 100struct cf_conn { /* kept in xprt->xp_p1 for actual connection */ 101 enum xprt_stat strm_stat; 102 u_int32_t x_id; 103 XDR xdrs; 104 char verf_body[MAX_AUTH_BYTES]; 105 u_int sendsize; 106 u_int recvsize; 107 int maxrec; 108 bool_t nonblock; 109 struct timeval last_recv_time; 110}; 111 112/* 113 * Usage: 114 * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); 115 * 116 * Creates, registers, and returns a (rpc) tcp based transporter. 117 * Once *xprt is initialized, it is registered as a transporter 118 * see (svc.h, xprt_register). This routine returns 119 * a NULL if a problem occurred. 120 * 121 * The filedescriptor passed in is expected to refer to a bound, but 122 * not yet connected socket. 123 * 124 * Since streams do buffered io similar to stdio, the caller can specify 125 * how big the send and receive buffers are via the second and third parms; 126 * 0 => use the system default. 127 */ 128SVCXPRT * 129svc_vc_create(fd, sendsize, recvsize) 130 int fd; 131 u_int sendsize; 132 u_int recvsize; 133{ 134 SVCXPRT *xprt; 135 struct cf_rendezvous *r = NULL; 136 struct __rpc_sockinfo si; 137 struct sockaddr_storage sslocal; 138 socklen_t slen; 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 if (!__rpc_fd2sockinfo(fd, &si)) 146 return NULL; 147 r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); 148 r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); 149 r->maxrec = __svc_maxrec; 150 xprt = mem_alloc(sizeof(SVCXPRT)); 151 if (xprt == NULL) { 152 warnx("svc_vc_create: out of memory"); 153 goto cleanup_svc_vc_create; 154 } 155 xprt->xp_tp = NULL; 156 xprt->xp_p1 = r; 157 xprt->xp_p2 = NULL; 158 xprt->xp_p3 = NULL; 159 xprt->xp_verf = _null_auth; 160 svc_vc_rendezvous_ops(xprt); 161 xprt->xp_port = (u_short)-1; /* It is the rendezvouser */ 162 xprt->xp_fd = fd; 163 164 slen = sizeof (struct sockaddr_storage); 165 if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) { 166 warnx("svc_vc_create: could not retrieve local addr"); 167 goto cleanup_svc_vc_create; 168 } 169 170 xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len; 171 xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len); 172 if (xprt->xp_ltaddr.buf == NULL) { 173 warnx("svc_vc_create: no mem for local addr"); 174 goto cleanup_svc_vc_create; 175 } 176 memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len); 177 178 xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); 179 xprt_register(xprt); 180 return (xprt); 181cleanup_svc_vc_create: 182 if (r != NULL) 183 mem_free(r, sizeof(*r)); 184 return (NULL); 185} 186 187/* 188 * Like svtcp_create(), except the routine takes any *open* UNIX file 189 * descriptor as its first input. 190 */ 191SVCXPRT * 192svc_fd_create(fd, sendsize, recvsize) 193 int fd; 194 u_int sendsize; 195 u_int recvsize; 196{ 197 struct sockaddr_storage ss; 198 socklen_t slen; 199 SVCXPRT *ret; 200 201 assert(fd != -1); 202 203 ret = makefd_xprt(fd, sendsize, recvsize); 204 if (ret == NULL) 205 return NULL; 206 207 slen = sizeof (struct sockaddr_storage); 208 if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 209 warnx("svc_fd_create: could not retrieve local addr"); 210 goto freedata; 211 } 212 ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len; 213 ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len); 214 if (ret->xp_ltaddr.buf == NULL) { 215 warnx("svc_fd_create: no mem for local addr"); 216 goto freedata; 217 } 218 memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len); 219 220 slen = sizeof (struct sockaddr_storage); 221 if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 222 warnx("svc_fd_create: could not retrieve remote addr"); 223 goto freedata; 224 } 225 ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len; 226 ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len); 227 if (ret->xp_rtaddr.buf == NULL) { 228 warnx("svc_fd_create: no mem for local addr"); 229 goto freedata; 230 } 231 memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len); 232#ifdef PORTMAP 233 if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) { 234 ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf; 235 ret->xp_addrlen = sizeof (struct sockaddr_in); 236 } 237#endif /* PORTMAP */ 238 239 return ret; 240 241freedata: 242 if (ret->xp_ltaddr.buf != NULL) 243 mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen); 244 245 return NULL; 246} 247 248static SVCXPRT * 249makefd_xprt(fd, sendsize, recvsize) 250 int fd; 251 u_int sendsize; 252 u_int recvsize; 253{ 254 SVCXPRT *xprt; 255 struct cf_conn *cd; 256 const char *netid; 257 struct __rpc_sockinfo si; 258 259 assert(fd != -1); 260 261 xprt = mem_alloc(sizeof(SVCXPRT)); 262 if (xprt == NULL) { 263 warnx("svc_vc: makefd_xprt: out of memory"); 264 goto done; 265 } 266 memset(xprt, 0, sizeof *xprt); 267 cd = mem_alloc(sizeof(struct cf_conn)); 268 if (cd == NULL) { 269 warnx("svc_tcp: makefd_xprt: out of memory"); 270 mem_free(xprt, sizeof(SVCXPRT)); 271 xprt = NULL; 272 goto done; 273 } 274 cd->strm_stat = XPRT_IDLE; 275 xdrrec_create(&(cd->xdrs), sendsize, recvsize, 276 xprt, read_vc, write_vc); 277 xprt->xp_p1 = cd; 278 xprt->xp_verf.oa_base = cd->verf_body; 279 svc_vc_ops(xprt); /* truely deals with calls */ 280 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ 281 xprt->xp_fd = fd; 282 if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid)) 283 xprt->xp_netid = strdup(netid); 284 285 xprt_register(xprt); 286done: 287 return (xprt); 288} 289 290/*ARGSUSED*/ 291static bool_t 292rendezvous_request(xprt, msg) 293 SVCXPRT *xprt; 294 struct rpc_msg *msg; 295{ 296 int sock, flags; 297 struct cf_rendezvous *r; 298 struct cf_conn *cd; 299 struct sockaddr_storage addr; 300 socklen_t len; 301 struct __rpc_sockinfo si; 302 SVCXPRT *newxprt; 303 fd_set cleanfds; 304 305 assert(xprt != NULL); 306 assert(msg != NULL); 307 308 r = (struct cf_rendezvous *)xprt->xp_p1; 309again: 310 len = sizeof addr; 311 if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, 312 &len)) < 0) { 313 if (errno == EINTR) 314 goto again; 315 /* 316 * Clean out the most idle file descriptor when we're 317 * running out. 318 */ 319 if (errno == EMFILE || errno == ENFILE) { 320 cleanfds = svc_fdset; 321 __svc_clean_idle(&cleanfds, 0, FALSE); 322 goto again; 323 } 324 return (FALSE); 325 } 326 /* 327 * make a new transporter (re-uses xprt) 328 */ 329 newxprt = makefd_xprt(sock, r->sendsize, r->recvsize); 330 newxprt->xp_rtaddr.buf = mem_alloc(len); 331 if (newxprt->xp_rtaddr.buf == NULL) 332 return (FALSE); 333 memcpy(newxprt->xp_rtaddr.buf, &addr, len); 334 newxprt->xp_rtaddr.len = len; 335#ifdef PORTMAP 336 if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) { 337 newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf; 338 newxprt->xp_addrlen = sizeof (struct sockaddr_in); 339 } 340#endif /* PORTMAP */ 341 if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) { 342 len = 1; 343 /* XXX fvdl - is this useful? */ 344 _setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len)); 345 } 346 347 cd = (struct cf_conn *)newxprt->xp_p1; 348 349 cd->recvsize = r->recvsize; 350 cd->sendsize = r->sendsize; 351 cd->maxrec = r->maxrec; 352 353 if (cd->maxrec != 0) { 354 flags = _fcntl(sock, F_GETFL, 0); 355 if (flags == -1) 356 return (FALSE); 357 if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) 358 return (FALSE); 359 if (cd->recvsize > cd->maxrec) 360 cd->recvsize = cd->maxrec; 361 cd->nonblock = TRUE; 362 __xdrrec_setnonblock(&cd->xdrs, cd->maxrec); 363 } else 364 cd->nonblock = FALSE; 365 366 gettimeofday(&cd->last_recv_time, NULL); 367 368 return (FALSE); /* there is never an rpc msg to be processed */ 369} 370 371/*ARGSUSED*/ 372static enum xprt_stat 373rendezvous_stat(xprt) 374 SVCXPRT *xprt; 375{ 376 377 return (XPRT_IDLE); 378} 379 380static void 381svc_vc_destroy(xprt) 382 SVCXPRT *xprt; 383{ 384 assert(xprt != NULL); 385 386 xprt_unregister(xprt); 387 __svc_vc_dodestroy(xprt); 388} 389 390static void 391__svc_vc_dodestroy(xprt) 392 SVCXPRT *xprt; 393{ 394 struct cf_conn *cd; 395 struct cf_rendezvous *r; 396 397 cd = (struct cf_conn *)xprt->xp_p1; 398 399 if (xprt->xp_fd != RPC_ANYFD) 400 (void)_close(xprt->xp_fd); 401 if (xprt->xp_port != 0) { 402 /* a rendezvouser socket */ 403 r = (struct cf_rendezvous *)xprt->xp_p1; 404 mem_free(r, sizeof (struct cf_rendezvous)); 405 xprt->xp_port = 0; 406 } else { 407 /* an actual connection socket */ 408 XDR_DESTROY(&(cd->xdrs)); 409 mem_free(cd, sizeof(struct cf_conn)); 410 } 411 if (xprt->xp_rtaddr.buf) 412 mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); 413 if (xprt->xp_ltaddr.buf) 414 mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); 415 if (xprt->xp_tp) 416 free(xprt->xp_tp); 417 if (xprt->xp_netid) 418 free(xprt->xp_netid); 419 mem_free(xprt, sizeof(SVCXPRT)); 420} 421 422/*ARGSUSED*/ 423static bool_t 424svc_vc_control(xprt, rq, in) 425 SVCXPRT *xprt; 426 const u_int rq; 427 void *in; 428{ 429 return (FALSE); 430} 431 432static bool_t 433svc_vc_rendezvous_control(xprt, rq, in) 434 SVCXPRT *xprt; 435 const u_int rq; 436 void *in; 437{ 438 struct cf_rendezvous *cfp; 439 440 cfp = (struct cf_rendezvous *)xprt->xp_p1; 441 if (cfp == NULL) 442 return (FALSE); 443 switch (rq) { 444 case SVCGET_CONNMAXREC: 445 *(int *)in = cfp->maxrec; 446 break; 447 case SVCSET_CONNMAXREC: 448 cfp->maxrec = *(int *)in; 449 break; 450 default: 451 return (FALSE); 452 } 453 return (TRUE); 454} 455 456/* 457 * reads data from the tcp or uip connection. 458 * any error is fatal and the connection is closed. 459 * (And a read of zero bytes is a half closed stream => error.) 460 * All read operations timeout after 35 seconds. A timeout is 461 * fatal for the connection. 462 */ 463static int 464read_vc(xprtp, buf, len) 465 void *xprtp; 466 void *buf; 467 int len; 468{ 469 SVCXPRT *xprt; 470 int sock; 471 int milliseconds = 35 * 1000; 472 struct pollfd pollfd; 473 struct cf_conn *cfp; 474 475 xprt = (SVCXPRT *)xprtp; 476 assert(xprt != NULL); 477 478 sock = xprt->xp_fd; 479 480 cfp = (struct cf_conn *)xprt->xp_p1; 481 482 if (cfp->nonblock) { 483 len = _read(sock, buf, (size_t)len); 484 if (len < 0) { 485 if (errno == EAGAIN) 486 len = 0; 487 else 488 goto fatal_err; 489 } 490 if (len != 0) 491 gettimeofday(&cfp->last_recv_time, NULL); 492 return len; 493 } 494 495 do { 496 pollfd.fd = sock; 497 pollfd.events = POLLIN; 498 pollfd.revents = 0; 499 switch (_poll(&pollfd, 1, milliseconds)) { 500 case -1: 501 if (errno == EINTR) 502 continue; 503 /*FALLTHROUGH*/ 504 case 0: 505 goto fatal_err; 506 507 default: 508 break; 509 } 510 } while ((pollfd.revents & POLLIN) == 0); 511 512 if ((len = _read(sock, buf, (size_t)len)) > 0) { 513 gettimeofday(&cfp->last_recv_time, NULL); 514 return (len); 515 } 516 517fatal_err: 518 ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 519 return (-1); 520} 521 522/* 523 * writes data to the tcp connection. 524 * Any error is fatal and the connection is closed. 525 */ 526static int 527write_vc(xprtp, buf, len) 528 void *xprtp; 529 void *buf; 530 int len; 531{ 532 SVCXPRT *xprt; 533 int i, cnt; 534 struct cf_conn *cd; 535 struct timeval tv0, tv1; 536 537 xprt = (SVCXPRT *)xprtp; 538 assert(xprt != NULL); 539 540 cd = (struct cf_conn *)xprt->xp_p1; 541 542 if (cd->nonblock) 543 gettimeofday(&tv0, NULL); 544 545 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 546 i = _write(xprt->xp_fd, buf, (size_t)cnt); 547 if (i < 0) { 548 if (errno != EAGAIN || !cd->nonblock) { 549 cd->strm_stat = XPRT_DIED; 550 return (-1); 551 } 552 if (cd->nonblock && i != cnt) { 553 /* 554 * For non-blocking connections, do not 555 * take more than 2 seconds writing the 556 * data out. 557 * 558 * XXX 2 is an arbitrary amount. 559 */ 560 gettimeofday(&tv1, NULL); 561 if (tv1.tv_sec - tv0.tv_sec >= 2) { 562 cd->strm_stat = XPRT_DIED; 563 return (-1); 564 } 565 } 566 } 567 } 568 569 return (len); 570} 571 572static enum xprt_stat 573svc_vc_stat(xprt) 574 SVCXPRT *xprt; 575{ 576 struct cf_conn *cd; 577 578 assert(xprt != NULL); 579 580 cd = (struct cf_conn *)(xprt->xp_p1); 581 582 if (cd->strm_stat == XPRT_DIED) 583 return (XPRT_DIED); 584 if (! xdrrec_eof(&(cd->xdrs))) 585 return (XPRT_MOREREQS); 586 return (XPRT_IDLE); 587} 588 589static bool_t 590svc_vc_recv(xprt, msg) 591 SVCXPRT *xprt; 592 struct rpc_msg *msg; 593{ 594 struct cf_conn *cd; 595 XDR *xdrs; 596 597 assert(xprt != NULL); 598 assert(msg != NULL); 599 600 cd = (struct cf_conn *)(xprt->xp_p1); 601 xdrs = &(cd->xdrs); 602 603 if (cd->nonblock) { 604 if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE)) 605 return FALSE; 606 } 607 608 xdrs->x_op = XDR_DECODE; 609 (void)xdrrec_skiprecord(xdrs); 610 if (xdr_callmsg(xdrs, msg)) { 611 cd->x_id = msg->rm_xid; 612 return (TRUE); 613 } 614 cd->strm_stat = XPRT_DIED; 615 return (FALSE); 616} 617 618static bool_t 619svc_vc_getargs(xprt, xdr_args, args_ptr) 620 SVCXPRT *xprt; 621 xdrproc_t xdr_args; 622 void *args_ptr; 623{ 624 625 assert(xprt != NULL); 626 /* args_ptr may be NULL */ 627 return ((*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs), 628 args_ptr)); 629} 630 631static bool_t 632svc_vc_freeargs(xprt, xdr_args, args_ptr) 633 SVCXPRT *xprt; 634 xdrproc_t xdr_args; 635 void *args_ptr; 636{ 637 XDR *xdrs; 638 639 assert(xprt != NULL); 640 /* args_ptr may be NULL */ 641 642 xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs); 643 644 xdrs->x_op = XDR_FREE; 645 return ((*xdr_args)(xdrs, args_ptr)); 646} 647 648static bool_t 649svc_vc_reply(xprt, msg) 650 SVCXPRT *xprt; 651 struct rpc_msg *msg; 652{ 653 struct cf_conn *cd; 654 XDR *xdrs; 655 bool_t rstat; 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 = xdr_replymsg(xdrs, msg); 666 (void)xdrrec_endofrecord(xdrs, TRUE); 667 return (rstat); 668} 669 670static void 671svc_vc_ops(xprt) 672 SVCXPRT *xprt; 673{ 674 static struct xp_ops ops; 675 static struct xp_ops2 ops2; 676 extern mutex_t ops_lock; 677 678/* VARIABLES PROTECTED BY ops_lock: ops, ops2 */ 679 680 mutex_lock(&ops_lock); 681 if (ops.xp_recv == NULL) { 682 ops.xp_recv = svc_vc_recv; 683 ops.xp_stat = svc_vc_stat; 684 ops.xp_getargs = svc_vc_getargs; 685 ops.xp_reply = svc_vc_reply; 686 ops.xp_freeargs = svc_vc_freeargs; 687 ops.xp_destroy = svc_vc_destroy; 688 ops2.xp_control = svc_vc_control; 689 } 690 xprt->xp_ops = &ops; 691 xprt->xp_ops2 = &ops2; 692 mutex_unlock(&ops_lock); 693} 694 695static void 696svc_vc_rendezvous_ops(xprt) 697 SVCXPRT *xprt; 698{ 699 static struct xp_ops ops; 700 static struct xp_ops2 ops2; 701 extern mutex_t ops_lock; 702 703 mutex_lock(&ops_lock); 704 if (ops.xp_recv == NULL) { 705 ops.xp_recv = rendezvous_request; 706 ops.xp_stat = rendezvous_stat; 707 ops.xp_getargs = 708 (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort; 709 ops.xp_reply = 710 (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort; 711 ops.xp_freeargs = 712 (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort, 713 ops.xp_destroy = svc_vc_destroy; 714 ops2.xp_control = svc_vc_rendezvous_control; 715 } 716 xprt->xp_ops = &ops; 717 xprt->xp_ops2 = &ops2; 718 mutex_unlock(&ops_lock); 719} 720 721/* 722 * Get the effective UID of the sending process. Used by rpcbind, keyserv 723 * and rpc.yppasswdd on AF_LOCAL. 724 */ 725int 726__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { 727 int sock, ret; 728 gid_t egid; 729 uid_t euid; 730 struct sockaddr *sa; 731 732 sock = transp->xp_fd; 733 sa = (struct sockaddr *)transp->xp_rtaddr.buf; 734 if (sa->sa_family == AF_LOCAL) { 735 ret = getpeereid(sock, &euid, &egid); 736 if (ret == 0) 737 *uid = euid; 738 return (ret); 739 } else 740 return (-1); 741} 742 743/* 744 * Destroy xprts that have not have had any activity in 'timeout' seconds. 745 * If 'cleanblock' is true, blocking connections (the default) are also 746 * cleaned. If timeout is 0, the least active connection is picked. 747 */ 748bool_t 749__svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock) 750{ 751 int i, ncleaned; 752 SVCXPRT *xprt, *least_active; 753 struct timeval tv, tdiff, tmax; 754 struct cf_conn *cd; 755 756 gettimeofday(&tv, NULL); 757 tmax.tv_sec = tmax.tv_usec = 0; 758 least_active = NULL; 759 rwlock_wrlock(&svc_fd_lock); 760 for (i = ncleaned = 0; i <= svc_maxfd; i++) { 761 if (FD_ISSET(i, fds)) { 762 xprt = __svc_xports[i]; 763 if (xprt == NULL || xprt->xp_ops == NULL || 764 xprt->xp_ops->xp_recv != svc_vc_recv) 765 continue; 766 cd = (struct cf_conn *)xprt->xp_p1; 767 if (!cleanblock && !cd->nonblock) 768 continue; 769 if (timeout == 0) { 770 timersub(&tv, &cd->last_recv_time, &tdiff); 771 if (timercmp(&tdiff, &tmax, >)) { 772 tmax = tdiff; 773 least_active = xprt; 774 } 775 continue; 776 } 777 if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) { 778 __xprt_unregister_unlocked(xprt); 779 __svc_vc_dodestroy(xprt); 780 ncleaned++; 781 } 782 } 783 } 784 if (timeout == 0 && least_active != NULL) { 785 __xprt_unregister_unlocked(least_active); 786 __svc_vc_dodestroy(least_active); 787 ncleaned++; 788 } 789 rwlock_unlock(&svc_fd_lock); 790 return ncleaned > 0 ? TRUE : FALSE; 791} 792