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 cm = NULL; 491 sa = (struct sockaddr *)xprt->xp_rtaddr.buf; 492 if (cfp->nonblock) { 493 if (sa->sa_family == AF_LOCAL) { 494 cm = (struct cmessage *)xprt->xp_verf.oa_base; 495 if ((len = __msgread_withcred(sock, buf, len, cm)) > 0) 496 xprt->xp_p2 = &cm->cmcred; 497 } else 498 len = _read(sock, buf, (size_t)len); 499 if (len < 0) { 500 if (errno == EAGAIN) 501 len = 0; 502 else 503 goto fatal_err; 504 } 505 if (len != 0) 506 gettimeofday(&cfp->last_recv_time, NULL); 507 return len; 508 } 509 510 do { 511 pollfd.fd = sock; 512 pollfd.events = POLLIN; 513 pollfd.revents = 0; 514 switch (_poll(&pollfd, 1, milliseconds)) { 515 case -1: 516 if (errno == EINTR) 517 continue; 518 /*FALLTHROUGH*/ 519 case 0: 520 goto fatal_err; 521 522 default: 523 break; 524 } 525 } while ((pollfd.revents & POLLIN) == 0); 526 527 if (sa->sa_family == AF_LOCAL) { 528 cm = (struct cmessage *)xprt->xp_verf.oa_base; 529 if ((len = __msgread_withcred(sock, buf, len, cm)) > 0) { 530 xprt->xp_p2 = &cm->cmcred; 531 return (len); 532 } else 533 goto fatal_err; 534 } else { 535 if ((len = _read(sock, buf, (size_t)len)) > 0) { 536 gettimeofday(&cfp->last_recv_time, NULL); 537 return (len); 538 } 539 } 540 541 fatal_err: 542 ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 543 return (-1); 544 } 545 546 /* 547 * writes data to the tcp connection. 548 * Any error is fatal and the connection is closed. 549 */ 550 static int 551 write_vc(xprtp, buf, len) 552 void *xprtp; 553 void *buf; 554 int len; 555 { 556 SVCXPRT *xprt; 557 int i, cnt; 558 struct sockaddr *sa; 559 struct cf_conn *cd; 560 struct timeval tv0, tv1; 561 562 xprt = (SVCXPRT *)xprtp; 563 assert(xprt != NULL); 564 565 cd = (struct cf_conn *)xprt->xp_p1; 566 567 if (cd->nonblock) 568 gettimeofday(&tv0, NULL); 569 570 sa = (struct sockaddr *)xprt->xp_rtaddr.buf; 571 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 572 if (sa->sa_family == AF_LOCAL) 573 i = __msgwrite(xprt->xp_fd, buf, (size_t)cnt); 574 else 575 i = _write(xprt->xp_fd, buf, (size_t)cnt); 576 if (i < 0) { 577 if (errno != EAGAIN || !cd->nonblock) { 578 cd->strm_stat = XPRT_DIED; 579 return (-1); 580 } 581 if (cd->nonblock && i != cnt) { 582 /* 583 * For non-blocking connections, do not 584 * take more than 2 seconds writing the 585 * data out. 586 * 587 * XXX 2 is an arbitrary amount. 588 */ 589 gettimeofday(&tv1, NULL); 590 if (tv1.tv_sec - tv0.tv_sec >= 2) { 591 cd->strm_stat = XPRT_DIED; 592 return (-1); 593 } 594 } 595 } 596 } 597 598 return (len); 599 } 600 601 static enum xprt_stat 602 svc_vc_stat(xprt) 603 SVCXPRT *xprt; 604 { 605 struct cf_conn *cd; 606 607 assert(xprt != NULL); 608 609 cd = (struct cf_conn *)(xprt->xp_p1); 610 611 if (cd->strm_stat == XPRT_DIED) 612 return (XPRT_DIED); 613 if (! xdrrec_eof(&(cd->xdrs))) 614 return (XPRT_MOREREQS); 615 return (XPRT_IDLE); 616 } 617 618 static bool_t 619 svc_vc_recv(xprt, msg) 620 SVCXPRT *xprt; 621 struct rpc_msg *msg; 622 { 623 struct cf_conn *cd; 624 XDR *xdrs; 625 626 assert(xprt != NULL); 627 assert(msg != NULL); 628 629 cd = (struct cf_conn *)(xprt->xp_p1); 630 xdrs = &(cd->xdrs); 631 632 if (cd->nonblock) { 633 if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE)) 634 return FALSE; 635 } 636 637 xdrs->x_op = XDR_DECODE; 638 (void)xdrrec_skiprecord(xdrs); 639 if (xdr_callmsg(xdrs, msg)) { 640 cd->x_id = msg->rm_xid; 641 return (TRUE); 642 } 643 cd->strm_stat = XPRT_DIED; 644 return (FALSE); 645 } 646 647 static bool_t 648 svc_vc_getargs(xprt, xdr_args, args_ptr) 649 SVCXPRT *xprt; 650 xdrproc_t xdr_args; 651 void *args_ptr; 652 { 653 654 assert(xprt != NULL); 655 /* args_ptr may be NULL */ 656 return ((*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs), 657 args_ptr)); 658 } 659 660 static bool_t 661 svc_vc_freeargs(xprt, xdr_args, args_ptr) 662 SVCXPRT *xprt; 663 xdrproc_t xdr_args; 664 void *args_ptr; 665 { 666 XDR *xdrs; 667 668 assert(xprt != NULL); 669 /* args_ptr may be NULL */ 670 671 xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs); 672 673 xdrs->x_op = XDR_FREE; 674 return ((*xdr_args)(xdrs, args_ptr)); 675 } 676 677 static bool_t 678 svc_vc_reply(xprt, msg) 679 SVCXPRT *xprt; 680 struct rpc_msg *msg; 681 { 682 struct cf_conn *cd; 683 XDR *xdrs; 684 bool_t rstat; 685 686 assert(xprt != NULL); 687 assert(msg != NULL); 688 689 cd = (struct cf_conn *)(xprt->xp_p1); 690 xdrs = &(cd->xdrs); 691 692 xdrs->x_op = XDR_ENCODE; 693 msg->rm_xid = cd->x_id; 694 rstat = xdr_replymsg(xdrs, msg); 695 (void)xdrrec_endofrecord(xdrs, TRUE); 696 return (rstat); 697 } 698 699 static void 700 svc_vc_ops(xprt) 701 SVCXPRT *xprt; 702 { 703 static struct xp_ops ops; 704 static struct xp_ops2 ops2; 705 extern mutex_t ops_lock; 706 707 /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */ 708 709 mutex_lock(&ops_lock); 710 if (ops.xp_recv == NULL) { 711 ops.xp_recv = svc_vc_recv; 712 ops.xp_stat = svc_vc_stat; 713 ops.xp_getargs = svc_vc_getargs; 714 ops.xp_reply = svc_vc_reply; 715 ops.xp_freeargs = svc_vc_freeargs; 716 ops.xp_destroy = svc_vc_destroy; 717 ops2.xp_control = svc_vc_control; 718 } 719 xprt->xp_ops = &ops; 720 xprt->xp_ops2 = &ops2; 721 mutex_unlock(&ops_lock); 722 } 723 724 static void 725 svc_vc_rendezvous_ops(xprt) 726 SVCXPRT *xprt; 727 { 728 static struct xp_ops ops; 729 static struct xp_ops2 ops2; 730 extern mutex_t ops_lock; 731 732 mutex_lock(&ops_lock); 733 if (ops.xp_recv == NULL) { 734 ops.xp_recv = rendezvous_request; 735 ops.xp_stat = rendezvous_stat; 736 ops.xp_getargs = 737 (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort; 738 ops.xp_reply = 739 (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort; 740 ops.xp_freeargs = 741 (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort, 742 ops.xp_destroy = svc_vc_destroy; 743 ops2.xp_control = svc_vc_rendezvous_control; 744 } 745 xprt->xp_ops = &ops; 746 xprt->xp_ops2 = &ops2; 747 mutex_unlock(&ops_lock); 748 } 749 750 int 751 __msgread_withcred(sock, buf, cnt, cmp) 752 int sock; 753 void *buf; 754 size_t cnt; 755 struct cmessage *cmp; 756 { 757 struct iovec iov[1]; 758 struct msghdr msg; 759 union { 760 struct cmsghdr cmsg; 761 char control[CMSG_SPACE(sizeof(struct cmsgcred))]; 762 } cm; 763 int ret; 764 765 766 bzero(&cm, sizeof(cm)); 767 iov[0].iov_base = buf; 768 iov[0].iov_len = cnt; 769 770 msg.msg_iov = iov; 771 msg.msg_iovlen = 1; 772 msg.msg_name = NULL; 773 msg.msg_namelen = 0; 774 msg.msg_control = &cm; 775 msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred)); 776 msg.msg_flags = 0; 777 778 ret = _recvmsg(sock, &msg, 0); 779 bcopy(&cm.cmsg, &cmp->cmsg, sizeof(cmp->cmsg)); 780 bcopy(CMSG_DATA(&cm), &cmp->cmcred, sizeof(cmp->cmcred)); 781 782 if ((msg.msg_flags & MSG_CTRUNC) != 0) 783 return (-1); 784 785 return (ret); 786 } 787 788 static int 789 __msgwrite(sock, buf, cnt) 790 int sock; 791 void *buf; 792 size_t cnt; 793 { 794 struct iovec iov[1]; 795 struct msghdr msg; 796 struct cmessage cm; 797 798 bzero((char *)&cm, sizeof(cm)); 799 iov[0].iov_base = buf; 800 iov[0].iov_len = cnt; 801 802 cm.cmsg.cmsg_type = SCM_CREDS; 803 cm.cmsg.cmsg_level = SOL_SOCKET; 804 cm.cmsg.cmsg_len = sizeof(struct cmessage); 805 806 msg.msg_iov = iov; 807 msg.msg_iovlen = 1; 808 msg.msg_name = NULL; 809 msg.msg_namelen = 0; 810 msg.msg_control = &cm; 811 msg.msg_controllen = sizeof(struct cmessage); 812 msg.msg_flags = 0; 813 814 return(_sendmsg(sock, &msg, 0)); 815 } 816 817 /* 818 * Get the effective UID of the sending process. Used by rpcbind and keyserv 819 * (AF_LOCAL). 820 */ 821 int 822 __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) 823 { 824 struct cmsgcred *cmcred; 825 struct cmessage *cm; 826 struct cmsghdr *cmp; 827 828 cm = (struct cmessage *)transp->xp_verf.oa_base; 829 830 if (cm == NULL) 831 return (-1); 832 cmp = &cm->cmsg; 833 if (cmp == NULL || cmp->cmsg_level != SOL_SOCKET || 834 cmp->cmsg_type != SCM_CREDS) 835 return (-1); 836 837 cmcred = __svc_getcallercreds(transp); 838 if (cmcred == NULL) 839 return (-1); 840 *uid = cmcred->cmcred_euid; 841 return (0); 842 } 843 844 /* 845 * Destroy xprts that have not have had any activity in 'timeout' seconds. 846 * If 'cleanblock' is true, blocking connections (the default) are also 847 * cleaned. If timeout is 0, the least active connection is picked. 848 */ 849 bool_t 850 __svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock) 851 { 852 int i, ncleaned; 853 SVCXPRT *xprt, *least_active; 854 struct timeval tv, tdiff, tmax; 855 struct cf_conn *cd; 856 857 gettimeofday(&tv, NULL); 858 tmax.tv_sec = tmax.tv_usec = 0; 859 least_active = NULL; 860 rwlock_wrlock(&svc_fd_lock); 861 for (i = ncleaned = 0; i <= svc_maxfd; i++) { 862 if (FD_ISSET(i, fds)) { 863 xprt = __svc_xports[i]; 864 if (xprt == NULL || xprt->xp_ops == NULL || 865 xprt->xp_ops->xp_recv != svc_vc_recv) 866 continue; 867 cd = (struct cf_conn *)xprt->xp_p1; 868 if (!cleanblock && !cd->nonblock) 869 continue; 870 if (timeout == 0) { 871 timersub(&tv, &cd->last_recv_time, &tdiff); 872 if (timercmp(&tdiff, &tmax, >)) { 873 tmax = tdiff; 874 least_active = xprt; 875 } 876 continue; 877 } 878 if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) { 879 __xprt_unregister_unlocked(xprt); 880 __svc_vc_dodestroy(xprt); 881 ncleaned++; 882 } 883 } 884 } 885 if (timeout == 0 && least_active != NULL) { 886 __xprt_unregister_unlocked(least_active); 887 __svc_vc_dodestroy(least_active); 888 ncleaned++; 889 } 890 rwlock_unlock(&svc_fd_lock); 891 return ncleaned > 0 ? TRUE : FALSE; 892 } 893