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