1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* 27 * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 28 */ 29 30 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 31 /* All Rights Reserved */ 32 /* 33 * Portions of this source code were derived from Berkeley 34 * 4.3 BSD under license from the Regents of the University of 35 * California. 36 */ 37 38 /* 39 * Server side for Connection Oriented RPC. 40 * 41 * Actually implements two flavors of transporter - 42 * a rendezvouser (a listener and connection establisher) 43 * and a record stream. 44 */ 45 46 #include "mt.h" 47 #include "rpc_mt.h" 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <rpc/rpc.h> 51 #include <sys/types.h> 52 #include <errno.h> 53 #include <sys/stat.h> 54 #include <sys/mkdev.h> 55 #include <sys/poll.h> 56 #include <syslog.h> 57 #include <rpc/nettype.h> 58 #include <tiuser.h> 59 #include <string.h> 60 #include <stropts.h> 61 #include <stdlib.h> 62 #include <unistd.h> 63 #include <sys/timod.h> 64 #include <limits.h> 65 66 #ifndef MIN 67 #define MIN(a, b) (((a) < (b)) ? (a) : (b)) 68 #endif 69 70 #define CLEANUP_SIZE 1024 71 72 extern int nsvc_xdrs; 73 extern int __rpc_connmaxrec; 74 extern int __rpc_irtimeout; 75 76 extern SVCXPRT **svc_xports; 77 extern int __td_setnodelay(int); 78 extern bool_t __xdrrec_getbytes_nonblock(XDR *, enum xprt_stat *); 79 extern bool_t __xdrrec_set_conn_nonblock(XDR *, uint32_t); 80 extern int _t_do_ioctl(int, char *, int, int, int *); 81 extern int __rpc_legal_connmaxrec(int); 82 /* Structure used to initialize SVC_XP_AUTH(xprt).svc_ah_ops. */ 83 extern struct svc_auth_ops svc_auth_any_ops; 84 extern void __xprt_unregister_private(const SVCXPRT *, bool_t); 85 86 static struct xp_ops *svc_vc_ops(void); 87 static struct xp_ops *svc_vc_rendezvous_ops(void); 88 static void svc_vc_destroy(SVCXPRT *); 89 static bool_t svc_vc_nonblock(SVCXPRT *, SVCXPRT *); 90 static int read_vc(SVCXPRT *, caddr_t, int); 91 static int write_vc(SVCXPRT *, caddr_t, int); 92 static SVCXPRT *makefd_xprt(int, uint_t, uint_t, t_scalar_t, char *); 93 static bool_t fd_is_dead(int); 94 static void update_nonblock_timestamps(SVCXPRT *); 95 96 struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */ 97 uint_t sendsize; 98 uint_t recvsize; 99 struct t_call *t_call; 100 struct t_bind *t_bind; 101 t_scalar_t cf_tsdu; 102 char *cf_cache; 103 int tcp_flag; 104 int tcp_keepalive; 105 int cf_connmaxrec; 106 }; 107 108 struct cf_conn { /* kept in xprt->xp_p1 for actual connection */ 109 uint_t sendsize; 110 uint_t recvsize; 111 enum xprt_stat strm_stat; 112 uint32_t x_id; 113 t_scalar_t cf_tsdu; 114 XDR xdrs; 115 char *cf_cache; 116 char verf_body[MAX_AUTH_BYTES]; 117 bool_t cf_conn_nonblock; 118 time_t cf_conn_nonblock_timestamp; 119 }; 120 121 static int t_rcvall(int, char *, int); 122 static int t_rcvnonblock(SVCXPRT *, caddr_t, int); 123 static void svc_timeout_nonblock_xprt_and_LRU(bool_t); 124 125 extern int __xdrrec_setfirst(XDR *); 126 extern int __xdrrec_resetfirst(XDR *); 127 extern int __is_xdrrec_first(XDR *); 128 129 void __svc_nisplus_enable_timestamps(void); 130 void __svc_timeout_nonblock_xprt(void); 131 132 /* 133 * This is intended as a performance improvement on the old string handling 134 * stuff by read only moving data into the text segment. 135 * Format = <routine> : <error> 136 */ 137 138 static const char errstring[] = " %s : %s"; 139 140 /* Routine names */ 141 142 static const char svc_vc_create_str[] = "svc_vc_create"; 143 static const char svc_fd_create_str[] = "svc_fd_create"; 144 static const char makefd_xprt_str[] = "svc_vc_create: makefd_xprt "; 145 static const char rendezvous_request_str[] = "rendezvous_request"; 146 static const char svc_vc_fderr[] = 147 "fd > FD_SETSIZE; Use rpc_control(RPC_SVC_USE_POLLFD,...);"; 148 static const char do_accept_str[] = "do_accept"; 149 150 /* error messages */ 151 152 static const char no_mem_str[] = "out of memory"; 153 static const char no_tinfo_str[] = "could not get transport information"; 154 static const char no_fcntl_getfl_str[] = "could not get status flags and modes"; 155 static const char no_nonblock_str[] = "could not set transport non-blocking"; 156 157 /* 158 * Records a timestamp when data comes in on a descriptor. This is 159 * only used if timestamps are enabled with __svc_nisplus_enable_timestamps(). 160 */ 161 static long *timestamps; 162 static int ntimestamps; /* keep track how many timestamps */ 163 static mutex_t timestamp_lock = DEFAULTMUTEX; 164 165 /* 166 * Used to determine whether the time-out logic should be executed. 167 */ 168 static bool_t check_nonblock_timestamps = FALSE; 169 170 void 171 svc_vc_xprtfree(SVCXPRT *xprt) 172 { 173 /* LINTED pointer alignment */ 174 SVCXPRT_EXT *xt = xprt ? SVCEXT(xprt) : NULL; 175 struct cf_rendezvous *r = xprt ? 176 /* LINTED pointer alignment */ 177 (struct cf_rendezvous *)xprt->xp_p1 : NULL; 178 179 if (!xprt) 180 return; 181 182 if (xprt->xp_tp) 183 free(xprt->xp_tp); 184 if (xprt->xp_netid) 185 free(xprt->xp_netid); 186 if (xt && (xt->parent == NULL)) { 187 if (xprt->xp_ltaddr.buf) 188 free(xprt->xp_ltaddr.buf); 189 if (xprt->xp_rtaddr.buf) 190 free(xprt->xp_rtaddr.buf); 191 } 192 if (r) { 193 if (r->t_call) 194 (void) t_free((char *)r->t_call, T_CALL); 195 if (r->t_bind) 196 (void) t_free((char *)r->t_bind, T_BIND); 197 free(r); 198 } 199 svc_xprt_free(xprt); 200 } 201 202 /* 203 * Usage: 204 * xprt = svc_vc_create(fd, sendsize, recvsize); 205 * Since connection streams do buffered io similar to stdio, the caller 206 * can specify how big the send and receive buffers are. If recvsize 207 * or sendsize are 0, defaults will be chosen. 208 * fd should be open and bound. 209 */ 210 SVCXPRT * 211 svc_vc_create_private(int fd, uint_t sendsize, uint_t recvsize) 212 { 213 struct cf_rendezvous *r; 214 SVCXPRT *xprt; 215 struct t_info tinfo; 216 217 if (RPC_FD_NOTIN_FDSET(fd)) { 218 errno = EBADF; 219 t_errno = TBADF; 220 (void) syslog(LOG_ERR, errstring, svc_vc_create_str, 221 svc_vc_fderr); 222 return (NULL); 223 } 224 if ((xprt = svc_xprt_alloc()) == NULL) { 225 (void) syslog(LOG_ERR, errstring, 226 svc_vc_create_str, no_mem_str); 227 return (NULL); 228 } 229 /* LINTED pointer alignment */ 230 svc_flags(xprt) |= SVC_RENDEZVOUS; 231 232 r = calloc(1, sizeof (*r)); 233 if (r == NULL) { 234 (void) syslog(LOG_ERR, errstring, 235 svc_vc_create_str, no_mem_str); 236 svc_vc_xprtfree(xprt); 237 return (NULL); 238 } 239 if (t_getinfo(fd, &tinfo) == -1) { 240 char errorstr[100]; 241 242 __tli_sys_strerror(errorstr, sizeof (errorstr), 243 t_errno, errno); 244 (void) syslog(LOG_ERR, "%s : %s : %s", 245 svc_vc_create_str, no_tinfo_str, errorstr); 246 free(r); 247 svc_vc_xprtfree(xprt); 248 return (NULL); 249 } 250 /* 251 * Find the receive and the send size 252 */ 253 r->sendsize = __rpc_get_t_size((int)sendsize, tinfo.tsdu); 254 r->recvsize = __rpc_get_t_size((int)recvsize, tinfo.tsdu); 255 if ((r->sendsize == 0) || (r->recvsize == 0)) { 256 syslog(LOG_ERR, 257 "svc_vc_create: transport does not support " 258 "data transfer"); 259 free(r); 260 svc_vc_xprtfree(xprt); 261 return (NULL); 262 } 263 264 /* LINTED pointer alignment */ 265 r->t_call = (struct t_call *)t_alloc(fd, T_CALL, T_ADDR | T_OPT); 266 if (r->t_call == NULL) { 267 (void) syslog(LOG_ERR, errstring, 268 svc_vc_create_str, no_mem_str); 269 free(r); 270 svc_vc_xprtfree(xprt); 271 return (NULL); 272 } 273 274 /* LINTED pointer alignment */ 275 r->t_bind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR); 276 if (r->t_bind == NULL) { 277 (void) syslog(LOG_ERR, errstring, 278 svc_vc_create_str, no_mem_str); 279 (void) t_free((char *)r->t_call, T_CALL); 280 free(r); 281 svc_vc_xprtfree(xprt); 282 return (NULL); 283 } 284 285 r->cf_tsdu = tinfo.tsdu; 286 r->tcp_flag = FALSE; 287 r->tcp_keepalive = FALSE; 288 r->cf_connmaxrec = __rpc_connmaxrec; 289 xprt->xp_fd = fd; 290 xprt->xp_p1 = (caddr_t)r; 291 xprt->xp_p2 = NULL; 292 xprt->xp_verf = _null_auth; 293 xprt->xp_ops = svc_vc_rendezvous_ops(); 294 /* LINTED pointer alignment */ 295 SVC_XP_AUTH(xprt).svc_ah_ops = svc_auth_any_ops; 296 /* LINTED pointer alignment */ 297 SVC_XP_AUTH(xprt).svc_ah_private = NULL; 298 299 return (xprt); 300 } 301 302 SVCXPRT * 303 svc_vc_create(const int fd, const uint_t sendsize, const uint_t recvsize) 304 { 305 SVCXPRT *xprt; 306 307 if ((xprt = svc_vc_create_private(fd, sendsize, recvsize)) != NULL) 308 xprt_register(xprt); 309 return (xprt); 310 } 311 312 SVCXPRT * 313 svc_vc_xprtcopy(SVCXPRT *parent) 314 { 315 SVCXPRT *xprt; 316 struct cf_rendezvous *r, *pr; 317 int fd = parent->xp_fd; 318 319 if ((xprt = svc_xprt_alloc()) == NULL) 320 return (NULL); 321 322 /* LINTED pointer alignment */ 323 SVCEXT(xprt)->parent = parent; 324 /* LINTED pointer alignment */ 325 SVCEXT(xprt)->flags = SVCEXT(parent)->flags; 326 327 xprt->xp_fd = fd; 328 xprt->xp_ops = svc_vc_rendezvous_ops(); 329 if (parent->xp_tp) { 330 xprt->xp_tp = (char *)strdup(parent->xp_tp); 331 if (xprt->xp_tp == NULL) { 332 syslog(LOG_ERR, "svc_vc_xprtcopy: strdup failed"); 333 svc_vc_xprtfree(xprt); 334 return (NULL); 335 } 336 } 337 if (parent->xp_netid) { 338 xprt->xp_netid = (char *)strdup(parent->xp_netid); 339 if (xprt->xp_netid == NULL) { 340 syslog(LOG_ERR, "svc_vc_xprtcopy: strdup failed"); 341 if (xprt->xp_tp) 342 free(xprt->xp_tp); 343 svc_vc_xprtfree(xprt); 344 return (NULL); 345 } 346 } 347 348 /* 349 * can share both local and remote address 350 */ 351 xprt->xp_ltaddr = parent->xp_ltaddr; 352 xprt->xp_rtaddr = parent->xp_rtaddr; /* XXX - not used for rendezvous */ 353 xprt->xp_type = parent->xp_type; 354 xprt->xp_verf = parent->xp_verf; 355 356 if ((r = calloc(1, sizeof (*r))) == NULL) { 357 svc_vc_xprtfree(xprt); 358 return (NULL); 359 } 360 xprt->xp_p1 = (caddr_t)r; 361 /* LINTED pointer alignment */ 362 pr = (struct cf_rendezvous *)parent->xp_p1; 363 r->sendsize = pr->sendsize; 364 r->recvsize = pr->recvsize; 365 r->cf_tsdu = pr->cf_tsdu; 366 r->cf_cache = pr->cf_cache; 367 r->tcp_flag = pr->tcp_flag; 368 r->tcp_keepalive = pr->tcp_keepalive; 369 r->cf_connmaxrec = pr->cf_connmaxrec; 370 /* LINTED pointer alignment */ 371 r->t_call = (struct t_call *)t_alloc(fd, T_CALL, T_ADDR | T_OPT); 372 if (r->t_call == NULL) { 373 svc_vc_xprtfree(xprt); 374 return (NULL); 375 } 376 /* LINTED pointer alignment */ 377 r->t_bind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR); 378 if (r->t_bind == NULL) { 379 svc_vc_xprtfree(xprt); 380 return (NULL); 381 } 382 383 return (xprt); 384 } 385 386 /* 387 * XXX : Used for setting flag to indicate that this is TCP 388 */ 389 390 /*ARGSUSED*/ 391 int 392 __svc_vc_setflag(SVCXPRT *xprt, int flag) 393 { 394 struct cf_rendezvous *r; 395 396 /* LINTED pointer alignment */ 397 r = (struct cf_rendezvous *)xprt->xp_p1; 398 r->tcp_flag = TRUE; 399 return (1); 400 } 401 402 /* 403 * used for the actual connection. 404 */ 405 SVCXPRT * 406 svc_fd_create_private(int fd, uint_t sendsize, uint_t recvsize) 407 { 408 struct t_info tinfo; 409 SVCXPRT *dummy; 410 struct netbuf tres = {0}; 411 412 if (RPC_FD_NOTIN_FDSET(fd)) { 413 errno = EBADF; 414 t_errno = TBADF; 415 (void) syslog(LOG_ERR, errstring, 416 svc_fd_create_str, svc_vc_fderr); 417 return (NULL); 418 } 419 if (t_getinfo(fd, &tinfo) == -1) { 420 char errorstr[100]; 421 422 __tli_sys_strerror(errorstr, sizeof (errorstr), 423 t_errno, errno); 424 (void) syslog(LOG_ERR, "%s : %s : %s", 425 svc_fd_create_str, no_tinfo_str, errorstr); 426 return (NULL); 427 } 428 /* 429 * Find the receive and the send size 430 */ 431 sendsize = __rpc_get_t_size((int)sendsize, tinfo.tsdu); 432 recvsize = __rpc_get_t_size((int)recvsize, tinfo.tsdu); 433 if ((sendsize == 0) || (recvsize == 0)) { 434 syslog(LOG_ERR, errstring, svc_fd_create_str, 435 "transport does not support data transfer"); 436 return (NULL); 437 } 438 dummy = makefd_xprt(fd, sendsize, recvsize, tinfo.tsdu, NULL); 439 /* NULL signifies no dup cache */ 440 /* Assign the local bind address */ 441 if (t_getname(fd, &tres, LOCALNAME) == -1) 442 tres.len = 0; 443 dummy->xp_ltaddr = tres; 444 /* Fill in type of service */ 445 dummy->xp_type = tinfo.servtype; 446 return (dummy); 447 } 448 449 SVCXPRT * 450 svc_fd_create(const int fd, const uint_t sendsize, const uint_t recvsize) 451 { 452 SVCXPRT *xprt; 453 454 if ((xprt = svc_fd_create_private(fd, sendsize, recvsize)) != NULL) 455 xprt_register(xprt); 456 return (xprt); 457 } 458 459 void 460 svc_fd_xprtfree(SVCXPRT *xprt) 461 { 462 /* LINTED pointer alignment */ 463 SVCXPRT_EXT *xt = xprt ? SVCEXT(xprt) : NULL; 464 /* LINTED pointer alignment */ 465 struct cf_conn *cd = xprt ? (struct cf_conn *)xprt->xp_p1 : NULL; 466 467 if (!xprt) 468 return; 469 470 if (xprt->xp_tp) 471 free(xprt->xp_tp); 472 if (xprt->xp_netid) 473 free(xprt->xp_netid); 474 if (xt && (xt->parent == NULL)) { 475 if (xprt->xp_ltaddr.buf) 476 free(xprt->xp_ltaddr.buf); 477 if (xprt->xp_rtaddr.buf) 478 free(xprt->xp_rtaddr.buf); 479 } 480 if (cd) { 481 XDR_DESTROY(&(cd->xdrs)); 482 free(cd); 483 } 484 if (xt && (xt->parent == NULL) && xprt->xp_p2) { 485 /* LINTED pointer alignment */ 486 free(((struct netbuf *)xprt->xp_p2)->buf); 487 free(xprt->xp_p2); 488 } 489 svc_xprt_free(xprt); 490 } 491 492 static SVCXPRT * 493 makefd_xprt(int fd, uint_t sendsize, uint_t recvsize, t_scalar_t tsdu, 494 char *cache) 495 { 496 SVCXPRT *xprt; 497 struct cf_conn *cd; 498 499 xprt = svc_xprt_alloc(); 500 if (xprt == NULL) { 501 (void) syslog(LOG_ERR, errstring, makefd_xprt_str, no_mem_str); 502 return (NULL); 503 } 504 /* LINTED pointer alignment */ 505 svc_flags(xprt) |= SVC_CONNECTION; 506 507 cd = malloc(sizeof (struct cf_conn)); 508 if (cd == NULL) { 509 (void) syslog(LOG_ERR, errstring, makefd_xprt_str, no_mem_str); 510 svc_fd_xprtfree(xprt); 511 return (NULL); 512 } 513 cd->sendsize = sendsize; 514 cd->recvsize = recvsize; 515 cd->strm_stat = XPRT_IDLE; 516 cd->cf_tsdu = tsdu; 517 cd->cf_cache = cache; 518 cd->cf_conn_nonblock = FALSE; 519 cd->cf_conn_nonblock_timestamp = 0; 520 cd->xdrs.x_ops = NULL; 521 xdrrec_create(&(cd->xdrs), sendsize, 0, (caddr_t)xprt, 522 (int(*)())NULL, (int(*)(void *, char *, int))write_vc); 523 if (cd->xdrs.x_ops == NULL) { 524 (void) syslog(LOG_ERR, errstring, makefd_xprt_str, no_mem_str); 525 free(cd); 526 svc_fd_xprtfree(xprt); 527 return (NULL); 528 } 529 530 (void) rw_wrlock(&svc_fd_lock); 531 if (svc_xdrs == NULL) { 532 svc_xdrs = calloc(FD_INCREMENT, sizeof (XDR *)); 533 if (svc_xdrs == NULL) { 534 (void) syslog(LOG_ERR, errstring, makefd_xprt_str, 535 no_mem_str); 536 XDR_DESTROY(&(cd->xdrs)); 537 free(cd); 538 svc_fd_xprtfree(xprt); 539 (void) rw_unlock(&svc_fd_lock); 540 return (NULL); 541 } 542 nsvc_xdrs = FD_INCREMENT; 543 } 544 545 while (fd >= nsvc_xdrs) { 546 XDR **tmp_xdrs = realloc(svc_xdrs, 547 sizeof (XDR *) * (nsvc_xdrs + FD_INCREMENT)); 548 if (tmp_xdrs == NULL) { 549 (void) syslog(LOG_ERR, errstring, makefd_xprt_str, 550 no_mem_str); 551 XDR_DESTROY(&(cd->xdrs)); 552 free(cd); 553 svc_fd_xprtfree(xprt); 554 (void) rw_unlock(&svc_fd_lock); 555 return (NULL); 556 } 557 558 svc_xdrs = tmp_xdrs; 559 /* initial the new array to 0 from the last allocated array */ 560 (void) memset(&svc_xdrs[nsvc_xdrs], 0, 561 sizeof (XDR *) * FD_INCREMENT); 562 nsvc_xdrs += FD_INCREMENT; 563 } 564 565 if (svc_xdrs[fd] != NULL) { 566 XDR_DESTROY(svc_xdrs[fd]); 567 } else if ((svc_xdrs[fd] = malloc(sizeof (XDR))) == NULL) { 568 (void) syslog(LOG_ERR, errstring, makefd_xprt_str, no_mem_str); 569 XDR_DESTROY(&(cd->xdrs)); 570 free(cd); 571 svc_fd_xprtfree(xprt); 572 (void) rw_unlock(&svc_fd_lock); 573 return (NULL); 574 } 575 (void) memset(svc_xdrs[fd], 0, sizeof (XDR)); 576 xdrrec_create(svc_xdrs[fd], 0, recvsize, (caddr_t)xprt, 577 (int(*)(void *, char *, int))read_vc, (int(*)())NULL); 578 if (svc_xdrs[fd]->x_ops == NULL) { 579 free(svc_xdrs[fd]); 580 svc_xdrs[fd] = NULL; 581 XDR_DESTROY(&(cd->xdrs)); 582 free(cd); 583 svc_fd_xprtfree(xprt); 584 (void) rw_unlock(&svc_fd_lock); 585 return (NULL); 586 } 587 (void) rw_unlock(&svc_fd_lock); 588 589 xprt->xp_p1 = (caddr_t)cd; 590 xprt->xp_p2 = NULL; 591 xprt->xp_verf.oa_base = cd->verf_body; 592 xprt->xp_ops = svc_vc_ops(); /* truely deals with calls */ 593 xprt->xp_fd = fd; 594 return (xprt); 595 } 596 597 SVCXPRT * 598 svc_fd_xprtcopy(SVCXPRT *parent) 599 { 600 SVCXPRT *xprt; 601 struct cf_conn *cd, *pcd; 602 603 if ((xprt = svc_xprt_alloc()) == NULL) 604 return (NULL); 605 606 /* LINTED pointer alignment */ 607 SVCEXT(xprt)->parent = parent; 608 /* LINTED pointer alignment */ 609 SVCEXT(xprt)->flags = SVCEXT(parent)->flags; 610 611 xprt->xp_fd = parent->xp_fd; 612 xprt->xp_ops = svc_vc_ops(); 613 if (parent->xp_tp) { 614 xprt->xp_tp = (char *)strdup(parent->xp_tp); 615 if (xprt->xp_tp == NULL) { 616 syslog(LOG_ERR, "svc_fd_xprtcopy: strdup failed"); 617 svc_fd_xprtfree(xprt); 618 return (NULL); 619 } 620 } 621 if (parent->xp_netid) { 622 xprt->xp_netid = (char *)strdup(parent->xp_netid); 623 if (xprt->xp_netid == NULL) { 624 syslog(LOG_ERR, "svc_fd_xprtcopy: strdup failed"); 625 if (xprt->xp_tp) 626 free(xprt->xp_tp); 627 svc_fd_xprtfree(xprt); 628 return (NULL); 629 } 630 } 631 /* 632 * share local and remote addresses with parent 633 */ 634 xprt->xp_ltaddr = parent->xp_ltaddr; 635 xprt->xp_rtaddr = parent->xp_rtaddr; 636 xprt->xp_type = parent->xp_type; 637 638 if ((cd = malloc(sizeof (struct cf_conn))) == NULL) { 639 svc_fd_xprtfree(xprt); 640 return (NULL); 641 } 642 /* LINTED pointer alignment */ 643 pcd = (struct cf_conn *)parent->xp_p1; 644 cd->sendsize = pcd->sendsize; 645 cd->recvsize = pcd->recvsize; 646 cd->strm_stat = pcd->strm_stat; 647 cd->x_id = pcd->x_id; 648 cd->cf_tsdu = pcd->cf_tsdu; 649 cd->cf_cache = pcd->cf_cache; 650 cd->cf_conn_nonblock = pcd->cf_conn_nonblock; 651 cd->cf_conn_nonblock_timestamp = pcd->cf_conn_nonblock_timestamp; 652 cd->xdrs.x_ops = NULL; 653 xdrrec_create(&(cd->xdrs), cd->sendsize, 0, (caddr_t)xprt, 654 (int(*)())NULL, (int(*)(void *, char *, int))write_vc); 655 if (cd->xdrs.x_ops == NULL) { 656 free(cd); 657 svc_fd_xprtfree(xprt); 658 return (NULL); 659 } 660 xprt->xp_verf.oa_base = cd->verf_body; 661 xprt->xp_p1 = (char *)cd; 662 xprt->xp_p2 = parent->xp_p2; /* shared */ 663 664 return (xprt); 665 } 666 667 static void do_accept(); 668 669 /* 670 * This routine is called by svc_getreqset(), when a packet is recd. 671 * The listener process creates another end point on which the actual 672 * connection is carried. It returns FALSE to indicate that it was 673 * not a rpc packet (falsely though), but as a side effect creates 674 * another endpoint which is also registered, which then always 675 * has a request ready to be served. 676 */ 677 /* ARGSUSED1 */ 678 static bool_t 679 rendezvous_request(SVCXPRT *xprt, struct rpc_msg *msg) 680 { 681 struct cf_rendezvous *r; 682 char *tpname = NULL; 683 char devbuf[256]; 684 685 /* LINTED pointer alignment */ 686 r = (struct cf_rendezvous *)xprt->xp_p1; 687 688 again: 689 switch (t_look(xprt->xp_fd)) { 690 case T_DISCONNECT: 691 (void) t_rcvdis(xprt->xp_fd, NULL); 692 return (FALSE); 693 694 case T_LISTEN: 695 696 if (t_listen(xprt->xp_fd, r->t_call) == -1) { 697 if ((t_errno == TSYSERR) && (errno == EINTR)) 698 goto again; 699 700 if (t_errno == TLOOK) { 701 if (t_look(xprt->xp_fd) == T_DISCONNECT) 702 (void) t_rcvdis(xprt->xp_fd, NULL); 703 } 704 return (FALSE); 705 } 706 break; 707 default: 708 return (FALSE); 709 } 710 /* 711 * Now create another endpoint, and accept the connection 712 * on it. 713 */ 714 715 if (xprt->xp_tp) { 716 tpname = xprt->xp_tp; 717 } else { 718 /* 719 * If xprt->xp_tp is NULL, then try to extract the 720 * transport protocol information from the transport 721 * protcol corresponding to xprt->xp_fd 722 */ 723 struct netconfig *nconf; 724 tpname = devbuf; 725 if ((nconf = __rpcfd_to_nconf(xprt->xp_fd, xprt->xp_type)) 726 == NULL) { 727 (void) syslog(LOG_ERR, errstring, 728 rendezvous_request_str, "no suitable transport"); 729 goto err; 730 } 731 (void) strcpy(tpname, nconf->nc_device); 732 freenetconfigent(nconf); 733 } 734 735 do_accept(xprt->xp_fd, tpname, xprt->xp_netid, r); 736 737 err: 738 return (FALSE); /* there is never an rpc msg to be processed */ 739 } 740 741 struct entry { 742 struct t_call *t_call; 743 struct entry *next; 744 }; 745 746 static void 747 do_accept(int srcfd, char *tpname, char *netid, struct cf_rendezvous *r) 748 { 749 int destfd; 750 struct t_call t_call; 751 struct t_call *tcp2 = NULL; 752 struct t_info tinfo; 753 SVCXPRT *xprt; 754 SVCXPRT *xprt_srcfd; 755 struct entry *head = NULL; 756 struct entry *tail = NULL; 757 struct entry *e; 758 struct t_call *tcp; 759 760 restart: 761 tcp = r->t_call; 762 763 destfd = t_open(tpname, O_RDWR, &tinfo); 764 if (check_nonblock_timestamps) { 765 if (destfd == -1 && t_errno == TSYSERR && errno == EMFILE) { 766 /* 767 * Since there are nonblocking connection xprts and 768 * too many open files, the LRU connection xprt should 769 * get destroyed in case an attacker has been creating 770 * many connections. 771 */ 772 (void) mutex_lock(&svc_mutex); 773 svc_timeout_nonblock_xprt_and_LRU(TRUE); 774 (void) mutex_unlock(&svc_mutex); 775 destfd = t_open(tpname, O_RDWR, &tinfo); 776 } else { 777 /* 778 * Destroy/timeout all nonblock connection xprts 779 * that have not had recent activity. 780 * Do not destroy LRU xprt unless there are 781 * too many open files. 782 */ 783 (void) mutex_lock(&svc_mutex); 784 svc_timeout_nonblock_xprt_and_LRU(FALSE); 785 (void) mutex_unlock(&svc_mutex); 786 } 787 } 788 if (destfd == -1) { 789 char errorstr[100]; 790 791 __tli_sys_strerror(errorstr, sizeof (errorstr), t_errno, errno); 792 (void) syslog(LOG_ERR, "%s : %s : %s", do_accept_str, 793 "can't open connection", errorstr); 794 (void) t_snddis(srcfd, tcp); 795 796 goto end; 797 } 798 if (RPC_FD_NOTIN_FDSET(destfd)) { 799 (void) syslog(LOG_ERR, errstring, do_accept_str, svc_vc_fderr); 800 (void) t_close(destfd); 801 (void) t_snddis(srcfd, tcp); 802 803 goto end; 804 } 805 (void) fcntl(destfd, F_SETFD, FD_CLOEXEC); 806 if ((tinfo.servtype != T_COTS) && (tinfo.servtype != T_COTS_ORD)) { 807 /* Not a connection oriented mode */ 808 (void) syslog(LOG_ERR, errstring, do_accept_str, 809 "do_accept: illegal transport"); 810 (void) t_close(destfd); 811 (void) t_snddis(srcfd, tcp); 812 813 goto end; 814 } 815 816 817 if (t_bind(destfd, NULL, r->t_bind) == -1) { 818 char errorstr[100]; 819 820 __tli_sys_strerror(errorstr, sizeof (errorstr), t_errno, errno); 821 (void) syslog(LOG_ERR, " %s : %s : %s", do_accept_str, 822 "t_bind failed", errorstr); 823 (void) t_close(destfd); 824 (void) t_snddis(srcfd, tcp); 825 826 goto end; 827 } 828 829 if (r->tcp_flag) /* if TCP, set NODELAY flag */ 830 (void) __td_setnodelay(destfd); 831 832 /* 833 * This connection is not listening, hence no need to set 834 * the qlen. 835 */ 836 837 /* 838 * XXX: The local transport chokes on its own listen 839 * options so we zero them for now 840 */ 841 t_call = *tcp; 842 t_call.opt.len = 0; 843 t_call.opt.maxlen = 0; 844 t_call.opt.buf = NULL; 845 846 while (t_accept(srcfd, destfd, &t_call) == -1) { 847 char errorstr[100]; 848 849 switch (t_errno) { 850 case TLOOK: 851 again: 852 switch (t_look(srcfd)) { 853 case T_CONNECT: 854 case T_DATA: 855 case T_EXDATA: 856 /* this should not happen */ 857 break; 858 859 case T_DISCONNECT: 860 (void) t_rcvdis(srcfd, NULL); 861 break; 862 863 case T_LISTEN: 864 if (tcp2 == NULL) 865 /* LINTED pointer alignment */ 866 tcp2 = (struct t_call *)t_alloc(srcfd, 867 T_CALL, T_ADDR | T_OPT); 868 if (tcp2 == NULL) { 869 (void) t_close(destfd); 870 (void) t_snddis(srcfd, tcp); 871 syslog(LOG_ERR, errstring, 872 do_accept_str, no_mem_str); 873 874 goto end; 875 } 876 if (t_listen(srcfd, tcp2) == -1) { 877 switch (t_errno) { 878 case TSYSERR: 879 if (errno == EINTR) 880 goto again; 881 break; 882 883 case TLOOK: 884 goto again; 885 } 886 (void) t_close(destfd); 887 (void) t_snddis(srcfd, tcp); 888 889 goto end; 890 } 891 892 e = malloc(sizeof (struct entry)); 893 if (e == NULL) { 894 (void) t_snddis(srcfd, tcp2); 895 (void) t_free((char *)tcp2, T_CALL); 896 tcp2 = NULL; 897 898 break; 899 } 900 901 e->t_call = tcp2; 902 tcp2 = NULL; 903 e->next = NULL; 904 905 if (head == NULL) 906 head = e; 907 else 908 tail->next = e; 909 tail = e; 910 911 break; 912 913 case T_ORDREL: 914 (void) t_rcvrel(srcfd); 915 (void) t_sndrel(srcfd); 916 break; 917 } 918 break; 919 920 case TBADSEQ: 921 /* 922 * This can happen if the remote side has 923 * disconnected before the connection is 924 * accepted. In this case, a disconnect 925 * should not be sent on srcfd (important! 926 * the listening fd will be hosed otherwise!). 927 * This error is not logged since this is an 928 * operational situation that is recoverable. 929 */ 930 (void) t_close(destfd); 931 932 goto end; 933 934 case TOUTSTATE: 935 /* 936 * This can happen if the t_rcvdis() or t_rcvrel()/ 937 * t_sndrel() put srcfd into the T_IDLE state. 938 */ 939 if (t_getstate(srcfd) == T_IDLE) { 940 (void) t_close(destfd); 941 (void) t_snddis(srcfd, tcp); 942 943 goto end; 944 } 945 /* else FALL THROUGH TO */ 946 947 default: 948 __tli_sys_strerror(errorstr, sizeof (errorstr), 949 t_errno, errno); 950 (void) syslog(LOG_ERR, 951 "cannot accept connection: %s (current state %d)", 952 errorstr, t_getstate(srcfd)); 953 (void) t_close(destfd); 954 (void) t_snddis(srcfd, tcp); 955 956 goto end; 957 } 958 } 959 960 if (r->tcp_flag && r->tcp_keepalive) { 961 char *option; 962 char *option_ret; 963 964 option = malloc(sizeof (struct opthdr) + sizeof (int)); 965 option_ret = malloc(sizeof (struct opthdr) + sizeof (int)); 966 if (option != NULL && option_ret != NULL) { 967 struct opthdr *opt; 968 struct t_optmgmt optreq, optret; 969 int *p_optval; 970 971 /* LINTED pointer cast */ 972 opt = (struct opthdr *)option; 973 opt->level = SOL_SOCKET; 974 opt->name = SO_KEEPALIVE; 975 opt->len = sizeof (int); 976 p_optval = (int *)(opt + 1); 977 *p_optval = SO_KEEPALIVE; 978 optreq.opt.maxlen = optreq.opt.len = 979 sizeof (struct opthdr) + sizeof (int); 980 optreq.opt.buf = (char *)option; 981 optreq.flags = T_NEGOTIATE; 982 optret.opt.maxlen = sizeof (struct opthdr) 983 + sizeof (int); 984 optret.opt.buf = (char *)option_ret; 985 (void) t_optmgmt(destfd, &optreq, &optret); 986 } 987 free(option); 988 free(option_ret); 989 } 990 991 992 /* 993 * make a new transporter 994 */ 995 xprt = makefd_xprt(destfd, r->sendsize, r->recvsize, r->cf_tsdu, 996 r->cf_cache); 997 if (xprt == NULL) { 998 /* 999 * makefd_xprt() returns a NULL xprt only when 1000 * it's out of memory. 1001 */ 1002 goto memerr; 1003 } 1004 1005 /* 1006 * Copy the new local and remote bind information 1007 */ 1008 1009 xprt->xp_rtaddr.len = tcp->addr.len; 1010 xprt->xp_rtaddr.maxlen = tcp->addr.len; 1011 if ((xprt->xp_rtaddr.buf = malloc(tcp->addr.len)) == NULL) 1012 goto memerr; 1013 (void) memcpy(xprt->xp_rtaddr.buf, tcp->addr.buf, tcp->addr.len); 1014 1015 if (strcmp(netid, "tcp") == 0) { 1016 xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_in); 1017 if ((xprt->xp_ltaddr.buf = 1018 malloc(xprt->xp_ltaddr.maxlen)) == NULL) 1019 goto memerr; 1020 if (t_getname(destfd, &xprt->xp_ltaddr, LOCALNAME) < 0) { 1021 (void) syslog(LOG_ERR, 1022 "do_accept: t_getname for tcp failed!"); 1023 goto xprt_err; 1024 } 1025 } else if (strcmp(netid, "tcp6") == 0) { 1026 xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_in6); 1027 if ((xprt->xp_ltaddr.buf = 1028 malloc(xprt->xp_ltaddr.maxlen)) == NULL) 1029 goto memerr; 1030 if (t_getname(destfd, &xprt->xp_ltaddr, LOCALNAME) < 0) { 1031 (void) syslog(LOG_ERR, 1032 "do_accept: t_getname for tcp6 failed!"); 1033 goto xprt_err; 1034 } 1035 } 1036 1037 xprt->xp_tp = strdup(tpname); 1038 xprt->xp_netid = strdup(netid); 1039 if ((xprt->xp_tp == NULL) || 1040 (xprt->xp_netid == NULL)) { 1041 goto memerr; 1042 } 1043 if (tcp->opt.len > 0) { 1044 xprt->xp_p2 = malloc(sizeof (struct netbuf)); 1045 1046 if (xprt->xp_p2 != NULL) { 1047 /* LINTED pointer alignment */ 1048 struct netbuf *netptr = (struct netbuf *)xprt->xp_p2; 1049 1050 netptr->len = tcp->opt.len; 1051 netptr->maxlen = tcp->opt.len; 1052 if ((netptr->buf = malloc(tcp->opt.len)) == NULL) 1053 goto memerr; 1054 (void) memcpy(netptr->buf, tcp->opt.buf, tcp->opt.len); 1055 } else 1056 goto memerr; 1057 } 1058 /* (void) ioctl(destfd, I_POP, NULL); */ 1059 1060 /* 1061 * If a nonblocked connection fd has been requested, 1062 * perform the necessary operations. 1063 */ 1064 xprt_srcfd = svc_xports[srcfd]; 1065 /* LINTED pointer cast */ 1066 if (((struct cf_rendezvous *)(xprt_srcfd->xp_p1))->cf_connmaxrec) { 1067 if (!svc_vc_nonblock(xprt_srcfd, xprt)) 1068 goto xprt_err; 1069 } 1070 1071 /* 1072 * Copy the call back declared for the service to the current 1073 * connection 1074 */ 1075 xprt->xp_closeclnt = xprt_srcfd->xp_closeclnt; 1076 xprt_register(xprt); 1077 1078 end: 1079 if (head != NULL) { 1080 (void) t_free((char *)r->t_call, T_CALL); 1081 r->t_call = head->t_call; 1082 e = head; 1083 head = head->next; 1084 free(e); 1085 goto restart; 1086 } 1087 1088 if (tcp2) 1089 (void) t_free((char *)tcp2, T_CALL); 1090 1091 return; 1092 1093 memerr: 1094 (void) syslog(LOG_ERR, errstring, do_accept_str, no_mem_str); 1095 xprt_err: 1096 if (xprt) 1097 svc_vc_destroy(xprt); 1098 (void) t_close(destfd); 1099 1100 goto end; 1101 } 1102 1103 /* 1104 * This routine performs the necessary fcntl() operations to create 1105 * a nonblocked connection fd. 1106 * It also adjusts the sizes and allocates the buffer 1107 * for the nonblocked operations, and updates the associated 1108 * timestamp field in struct cf_conn for timeout bookkeeping. 1109 */ 1110 static bool_t 1111 svc_vc_nonblock(SVCXPRT *xprt_rendezvous, SVCXPRT *xprt_conn) 1112 { 1113 int nn; 1114 int fdconn = xprt_conn->xp_fd; 1115 struct cf_rendezvous *r = 1116 /* LINTED pointer cast */ 1117 (struct cf_rendezvous *)xprt_rendezvous->xp_p1; 1118 /* LINTED pointer cast */ 1119 struct cf_conn *cd = (struct cf_conn *)xprt_conn->xp_p1; 1120 uint32_t maxrecsz; 1121 1122 if ((nn = fcntl(fdconn, F_GETFL, 0)) < 0) { 1123 (void) syslog(LOG_ERR, "%s : %s : %m", do_accept_str, 1124 no_fcntl_getfl_str); 1125 return (FALSE); 1126 } 1127 1128 if (fcntl(fdconn, F_SETFL, nn|O_NONBLOCK) != 0) { 1129 (void) syslog(LOG_ERR, "%s : %s : %m", do_accept_str, 1130 no_nonblock_str); 1131 return (FALSE); 1132 } 1133 1134 cd->cf_conn_nonblock = TRUE; 1135 /* 1136 * If the max fragment size has not been set via 1137 * rpc_control(), use the default. 1138 */ 1139 if ((maxrecsz = r->cf_connmaxrec) == 0) 1140 maxrecsz = r->recvsize; 1141 /* Set XDR stream to use non-blocking semantics. */ 1142 if (__xdrrec_set_conn_nonblock(svc_xdrs[fdconn], maxrecsz)) { 1143 check_nonblock_timestamps = TRUE; 1144 update_nonblock_timestamps(xprt_conn); 1145 return (TRUE); 1146 } 1147 return (FALSE); 1148 } 1149 1150 /* ARGSUSED */ 1151 static enum xprt_stat 1152 rendezvous_stat(SVCXPRT *xprt) 1153 { 1154 return (XPRT_IDLE); 1155 } 1156 1157 static void 1158 svc_vc_destroy(SVCXPRT *xprt) 1159 { 1160 (void) mutex_lock(&svc_mutex); 1161 _svc_vc_destroy_private(xprt, TRUE); 1162 (void) svc_timeout_nonblock_xprt_and_LRU(FALSE); 1163 (void) mutex_unlock(&svc_mutex); 1164 } 1165 1166 void 1167 _svc_vc_destroy_private(SVCXPRT *xprt, bool_t lock_not_held) 1168 { 1169 if (svc_mt_mode != RPC_SVC_MT_NONE) { 1170 /* LINTED pointer alignment */ 1171 if (SVCEXT(xprt)->parent) 1172 /* LINTED pointer alignment */ 1173 xprt = SVCEXT(xprt)->parent; 1174 /* LINTED pointer alignment */ 1175 svc_flags(xprt) |= SVC_DEFUNCT; 1176 /* LINTED pointer alignment */ 1177 if (SVCEXT(xprt)->refcnt > 0) 1178 return; 1179 } 1180 1181 if (xprt->xp_closeclnt != NULL) { 1182 svc_errorhandler_t cb = xprt->xp_closeclnt; 1183 1184 /* 1185 * Reset the pointer here to avoid reentrance on the same 1186 * SVCXPRT handle. 1187 */ 1188 xprt->xp_closeclnt = NULL; 1189 cb(xprt, (xprt->xp_rtaddr.len != 0)); 1190 } 1191 1192 __xprt_unregister_private(xprt, lock_not_held); 1193 (void) t_close(xprt->xp_fd); 1194 1195 (void) mutex_lock(×tamp_lock); 1196 if (timestamps && xprt->xp_fd < ntimestamps) { 1197 timestamps[xprt->xp_fd] = 0; 1198 } 1199 (void) mutex_unlock(×tamp_lock); 1200 1201 if (svc_mt_mode != RPC_SVC_MT_NONE) { 1202 svc_xprt_destroy(xprt); 1203 } else { 1204 /* LINTED pointer alignment */ 1205 if (svc_type(xprt) == SVC_RENDEZVOUS) 1206 svc_vc_xprtfree(xprt); 1207 else 1208 svc_fd_xprtfree(xprt); 1209 } 1210 } 1211 1212 /*ARGSUSED*/ 1213 static bool_t 1214 svc_vc_control(SVCXPRT *xprt, const uint_t rq, void *in) 1215 { 1216 switch (rq) { 1217 case SVCSET_RECVERRHANDLER: 1218 xprt->xp_closeclnt = (svc_errorhandler_t)in; 1219 return (TRUE); 1220 case SVCGET_RECVERRHANDLER: 1221 *(svc_errorhandler_t *)in = xprt->xp_closeclnt; 1222 return (TRUE); 1223 case SVCGET_XID: 1224 if (xprt->xp_p1 == NULL) 1225 return (FALSE); 1226 /* LINTED pointer alignment */ 1227 *(uint32_t *)in = ((struct cf_conn *)(xprt->xp_p1))->x_id; 1228 return (TRUE); 1229 default: 1230 return (FALSE); 1231 } 1232 } 1233 1234 static bool_t 1235 rendezvous_control(SVCXPRT *xprt, const uint_t rq, void *in) 1236 { 1237 struct cf_rendezvous *r; 1238 int tmp; 1239 1240 switch (rq) { 1241 case SVCSET_RECVERRHANDLER: 1242 xprt->xp_closeclnt = (svc_errorhandler_t)in; 1243 return (TRUE); 1244 case SVCGET_RECVERRHANDLER: 1245 *(svc_errorhandler_t *)in = xprt->xp_closeclnt; 1246 return (TRUE); 1247 case SVCSET_KEEPALIVE: 1248 /* LINTED pointer cast */ 1249 r = (struct cf_rendezvous *)xprt->xp_p1; 1250 if (r->tcp_flag) { 1251 r->tcp_keepalive = (int)(intptr_t)in; 1252 return (TRUE); 1253 } 1254 return (FALSE); 1255 case SVCSET_CONNMAXREC: 1256 /* 1257 * Override the default maximum record size, set via 1258 * rpc_control(), for this connection. Only appropriate 1259 * for connection oriented transports, but is ignored for 1260 * the connectionless case, so no need to check the 1261 * connection type here. 1262 */ 1263 /* LINTED pointer cast */ 1264 r = (struct cf_rendezvous *)xprt->xp_p1; 1265 tmp = __rpc_legal_connmaxrec(*(int *)in); 1266 if (r != 0 && tmp >= 0) { 1267 r->cf_connmaxrec = tmp; 1268 return (TRUE); 1269 } 1270 return (FALSE); 1271 case SVCGET_CONNMAXREC: 1272 /* LINTED pointer cast */ 1273 r = (struct cf_rendezvous *)xprt->xp_p1; 1274 if (r != 0) { 1275 *(int *)in = r->cf_connmaxrec; 1276 return (TRUE); 1277 } 1278 return (FALSE); 1279 case SVCGET_XID: /* fall through for now */ 1280 default: 1281 return (FALSE); 1282 } 1283 } 1284 1285 /* 1286 * All read operations timeout after 35 seconds. 1287 * A timeout is fatal for the connection. 1288 * update_timestamps() is used by nisplus operations, 1289 * update_nonblock_timestamps() is used for nonblocked 1290 * connection fds. 1291 */ 1292 #define WAIT_PER_TRY 35000 /* milliseconds */ 1293 1294 static void 1295 update_timestamps(int fd) 1296 { 1297 (void) mutex_lock(×tamp_lock); 1298 if (timestamps) { 1299 struct timeval tv; 1300 1301 (void) gettimeofday(&tv, NULL); 1302 while (fd >= ntimestamps) { 1303 long *tmp_timestamps = timestamps; 1304 1305 /* allocate more timestamps */ 1306 tmp_timestamps = realloc(timestamps, sizeof (long) * 1307 (ntimestamps + FD_INCREMENT)); 1308 if (tmp_timestamps == NULL) { 1309 (void) mutex_unlock(×tamp_lock); 1310 syslog(LOG_ERR, 1311 "update_timestamps: out of memory"); 1312 return; 1313 } 1314 1315 timestamps = tmp_timestamps; 1316 (void) memset(×tamps[ntimestamps], 0, 1317 sizeof (long) * FD_INCREMENT); 1318 ntimestamps += FD_INCREMENT; 1319 } 1320 timestamps[fd] = tv.tv_sec; 1321 } 1322 (void) mutex_unlock(×tamp_lock); 1323 } 1324 1325 static void 1326 update_nonblock_timestamps(SVCXPRT *xprt_conn) 1327 { 1328 struct timeval tv; 1329 /* LINTED pointer cast */ 1330 struct cf_conn *cd = (struct cf_conn *)xprt_conn->xp_p1; 1331 1332 (void) gettimeofday(&tv, NULL); 1333 cd->cf_conn_nonblock_timestamp = tv.tv_sec; 1334 } 1335 1336 /* 1337 * reads data from the vc conection. 1338 * any error is fatal and the connection is closed. 1339 * (And a read of zero bytes is a half closed stream => error.) 1340 */ 1341 static int 1342 read_vc(SVCXPRT *xprt, caddr_t buf, int len) 1343 { 1344 int fd = xprt->xp_fd; 1345 XDR *xdrs = svc_xdrs[fd]; 1346 struct pollfd pfd; 1347 int ret; 1348 1349 /* 1350 * Make sure the connection is not already dead. 1351 */ 1352 /* LINTED pointer alignment */ 1353 if (svc_failed(xprt)) 1354 return (-1); 1355 1356 /* LINTED pointer cast */ 1357 if (((struct cf_conn *)(xprt->xp_p1))->cf_conn_nonblock) { 1358 /* 1359 * For nonblocked reads, only update the 1360 * timestamps to record the activity so the 1361 * connection will not be timedout. 1362 * Up to "len" bytes are requested. 1363 * If fewer than "len" bytes are received, the 1364 * connection is poll()ed again. 1365 * The poll() for the connection fd is performed 1366 * in the main poll() so that all outstanding fds 1367 * are polled rather than just the vc connection. 1368 * Polling on only the vc connection until the entire 1369 * fragment has been read can be exploited in 1370 * a Denial of Service Attack such as telnet <host> 111. 1371 */ 1372 if ((len = t_rcvnonblock(xprt, buf, len)) >= 0) { 1373 if (len > 0) { 1374 update_timestamps(fd); 1375 update_nonblock_timestamps(xprt); 1376 } 1377 return (len); 1378 } 1379 goto fatal_err; 1380 } 1381 1382 if (!__is_xdrrec_first(xdrs)) { 1383 1384 pfd.fd = fd; 1385 pfd.events = MASKVAL; 1386 1387 do { 1388 if ((ret = poll(&pfd, 1, WAIT_PER_TRY)) <= 0) { 1389 /* 1390 * If errno is EINTR, ERESTART, or EAGAIN 1391 * ignore error and repeat poll 1392 */ 1393 if (ret < 0 && (errno == EINTR || 1394 errno == ERESTART || errno == EAGAIN)) 1395 continue; 1396 goto fatal_err; 1397 } 1398 } while (pfd.revents == 0); 1399 if (pfd.revents & POLLNVAL) 1400 goto fatal_err; 1401 } 1402 (void) __xdrrec_resetfirst(xdrs); 1403 if ((len = t_rcvall(fd, buf, len)) > 0) { 1404 update_timestamps(fd); 1405 return (len); 1406 } 1407 1408 fatal_err: 1409 /* LINTED pointer alignment */ 1410 ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 1411 /* LINTED pointer alignment */ 1412 svc_flags(xprt) |= SVC_FAILED; 1413 return (-1); 1414 } 1415 1416 /* 1417 * Requests up to "len" bytes of data. 1418 * Returns number of bytes actually received, or error indication. 1419 */ 1420 static int 1421 t_rcvnonblock(SVCXPRT *xprt, caddr_t buf, int len) 1422 { 1423 int fd = xprt->xp_fd; 1424 int flag; 1425 int res; 1426 1427 res = t_rcv(fd, buf, (unsigned)len, &flag); 1428 if (res == -1) { 1429 switch (t_errno) { 1430 case TLOOK: 1431 switch (t_look(fd)) { 1432 case T_DISCONNECT: 1433 (void) t_rcvdis(fd, NULL); 1434 break; 1435 case T_ORDREL: 1436 (void) t_rcvrel(fd); 1437 (void) t_sndrel(fd); 1438 break; 1439 default: 1440 break; 1441 } 1442 break; 1443 case TNODATA: 1444 /* 1445 * Either poll() lied, or the xprt/fd was closed and 1446 * re-opened under our feet. Return 0, so that we go 1447 * back to waiting for data. 1448 */ 1449 res = 0; 1450 break; 1451 /* Should handle TBUFOVFLW TSYSERR ? */ 1452 default: 1453 break; 1454 } 1455 } 1456 return (res); 1457 } 1458 1459 /* 1460 * Timeout out nonblocked connection fds 1461 * If there has been no activity on the fd for __rpc_irtimeout 1462 * seconds, timeout the fd by destroying its xprt. 1463 * If the caller gets an EMFILE error, the caller may also request 1464 * that the least busy xprt gets destroyed as well. 1465 * svc_thr_mutex is held when this is called. 1466 * svc_mutex is held when this is called. 1467 */ 1468 static void 1469 svc_timeout_nonblock_xprt_and_LRU(bool_t destroy_lru) 1470 { 1471 SVCXPRT *xprt; 1472 SVCXPRT *dead_xprt[CLEANUP_SIZE]; 1473 SVCXPRT *candidate_xprt = NULL; 1474 struct cf_conn *cd; 1475 int i, fd_idx = 0, dead_idx = 0; 1476 struct timeval now; 1477 time_t lasttime, maxctime = 0; 1478 extern rwlock_t svc_fd_lock; 1479 1480 if (!check_nonblock_timestamps) 1481 return; 1482 1483 (void) gettimeofday(&now, NULL); 1484 if (svc_xports == NULL) 1485 return; 1486 /* 1487 * Hold svc_fd_lock to protect 1488 * svc_xports, svc_maxpollfd, svc_max_pollfd 1489 */ 1490 (void) rw_wrlock(&svc_fd_lock); 1491 for (;;) { 1492 /* 1493 * Timeout upto CLEANUP_SIZE connection fds per 1494 * iteration for the while(1) loop 1495 */ 1496 for (dead_idx = 0; fd_idx < svc_max_pollfd; fd_idx++) { 1497 if ((xprt = svc_xports[fd_idx]) == NULL) { 1498 continue; 1499 } 1500 /* Only look at connection fds */ 1501 /* LINTED pointer cast */ 1502 if (svc_type(xprt) != SVC_CONNECTION) { 1503 continue; 1504 } 1505 /* LINTED pointer cast */ 1506 cd = (struct cf_conn *)xprt->xp_p1; 1507 if (!cd->cf_conn_nonblock) 1508 continue; 1509 lasttime = now.tv_sec - cd->cf_conn_nonblock_timestamp; 1510 if (lasttime >= __rpc_irtimeout && 1511 __rpc_irtimeout != 0) { 1512 /* Enter in timedout/dead array */ 1513 dead_xprt[dead_idx++] = xprt; 1514 if (dead_idx >= CLEANUP_SIZE) 1515 break; 1516 } else 1517 if (lasttime > maxctime) { 1518 /* Possible LRU xprt */ 1519 candidate_xprt = xprt; 1520 maxctime = lasttime; 1521 } 1522 } 1523 1524 for (i = 0; i < dead_idx; i++) { 1525 /* Still holding svc_fd_lock */ 1526 _svc_vc_destroy_private(dead_xprt[i], FALSE); 1527 } 1528 1529 /* 1530 * If all the nonblocked fds have been checked, we're done. 1531 */ 1532 if (fd_idx++ >= svc_max_pollfd) 1533 break; 1534 } 1535 if ((destroy_lru) && (candidate_xprt != NULL)) { 1536 _svc_vc_destroy_private(candidate_xprt, FALSE); 1537 } 1538 (void) rw_unlock(&svc_fd_lock); 1539 } 1540 /* 1541 * Receive the required bytes of data, even if it is fragmented. 1542 */ 1543 static int 1544 t_rcvall(int fd, char *buf, int len) 1545 { 1546 int flag; 1547 int final = 0; 1548 int res; 1549 1550 do { 1551 res = t_rcv(fd, buf, (unsigned)len, &flag); 1552 if (res == -1) { 1553 if (t_errno == TLOOK) { 1554 switch (t_look(fd)) { 1555 case T_DISCONNECT: 1556 (void) t_rcvdis(fd, NULL); 1557 break; 1558 case T_ORDREL: 1559 (void) t_rcvrel(fd); 1560 (void) t_sndrel(fd); 1561 break; 1562 default: 1563 break; 1564 } 1565 } 1566 break; 1567 } 1568 final += res; 1569 buf += res; 1570 len -= res; 1571 } while (len && (flag & T_MORE)); 1572 return (res == -1 ? -1 : final); 1573 } 1574 1575 /* 1576 * writes data to the vc connection. 1577 * Any error is fatal and the connection is closed. 1578 */ 1579 static int 1580 write_vc(SVCXPRT *xprt, caddr_t buf, int len) 1581 { 1582 int i, cnt; 1583 int flag; 1584 int maxsz; 1585 int nonblock; 1586 struct pollfd pfd; 1587 1588 /* LINTED pointer alignment */ 1589 maxsz = ((struct cf_conn *)(xprt->xp_p1))->cf_tsdu; 1590 /* LINTED pointer cast */ 1591 nonblock = ((struct cf_conn *)(xprt->xp_p1))->cf_conn_nonblock; 1592 if (nonblock && maxsz <= 0) 1593 maxsz = len; 1594 if ((maxsz == 0) || (maxsz == -1)) { 1595 if ((len = t_snd(xprt->xp_fd, buf, (unsigned)len, 1596 (int)0)) == -1) { 1597 if (t_errno == TLOOK) { 1598 switch (t_look(xprt->xp_fd)) { 1599 case T_DISCONNECT: 1600 (void) t_rcvdis(xprt->xp_fd, NULL); 1601 break; 1602 case T_ORDREL: 1603 (void) t_rcvrel(xprt->xp_fd); 1604 (void) t_sndrel(xprt->xp_fd); 1605 break; 1606 default: 1607 break; 1608 } 1609 } 1610 /* LINTED pointer alignment */ 1611 ((struct cf_conn *)(xprt->xp_p1))->strm_stat = 1612 XPRT_DIED; 1613 /* LINTED pointer alignment */ 1614 svc_flags(xprt) |= SVC_FAILED; 1615 } 1616 return (len); 1617 } 1618 1619 /* 1620 * Setup for polling. We want to be able to write normal 1621 * data to the transport 1622 */ 1623 pfd.fd = xprt->xp_fd; 1624 pfd.events = POLLWRNORM; 1625 1626 /* 1627 * This for those transports which have a max size for data, 1628 * and for the non-blocking case, where t_snd() may send less 1629 * than requested. 1630 */ 1631 for (cnt = len, i = 0; cnt > 0; cnt -= i, buf += i) { 1632 flag = cnt > maxsz ? T_MORE : 0; 1633 if ((i = t_snd(xprt->xp_fd, buf, 1634 (unsigned)MIN(cnt, maxsz), flag)) == -1) { 1635 if (t_errno == TLOOK) { 1636 switch (t_look(xprt->xp_fd)) { 1637 case T_DISCONNECT: 1638 (void) t_rcvdis(xprt->xp_fd, NULL); 1639 break; 1640 case T_ORDREL: 1641 (void) t_rcvrel(xprt->xp_fd); 1642 break; 1643 default: 1644 break; 1645 } 1646 } else if (t_errno == TFLOW) { 1647 /* Try again */ 1648 i = 0; 1649 /* Wait till we can write to the transport */ 1650 do { 1651 if (poll(&pfd, 1, WAIT_PER_TRY) < 0) { 1652 /* 1653 * If errno is ERESTART, or 1654 * EAGAIN ignore error and 1655 * repeat poll 1656 */ 1657 if (errno == ERESTART || 1658 errno == EAGAIN) 1659 continue; 1660 else 1661 goto fatal_err; 1662 } 1663 } while (pfd.revents == 0); 1664 if (pfd.revents & (POLLNVAL | POLLERR | 1665 POLLHUP)) 1666 goto fatal_err; 1667 continue; 1668 } 1669 fatal_err: 1670 /* LINTED pointer alignment */ 1671 ((struct cf_conn *)(xprt->xp_p1))->strm_stat = 1672 XPRT_DIED; 1673 /* LINTED pointer alignment */ 1674 svc_flags(xprt) |= SVC_FAILED; 1675 return (-1); 1676 } 1677 } 1678 return (len); 1679 } 1680 1681 static enum xprt_stat 1682 svc_vc_stat(SVCXPRT *xprt) 1683 { 1684 /* LINTED pointer alignment */ 1685 SVCXPRT *parent = SVCEXT(xprt)->parent ? SVCEXT(xprt)->parent : xprt; 1686 1687 /* LINTED pointer alignment */ 1688 if (svc_failed(parent) || svc_failed(xprt)) 1689 return (XPRT_DIED); 1690 if (!xdrrec_eof(svc_xdrs[xprt->xp_fd])) 1691 return (XPRT_MOREREQS); 1692 /* 1693 * xdrrec_eof could have noticed that the connection is dead, so 1694 * check status again. 1695 */ 1696 /* LINTED pointer alignment */ 1697 if (svc_failed(parent) || svc_failed(xprt)) 1698 return (XPRT_DIED); 1699 return (XPRT_IDLE); 1700 } 1701 1702 1703 1704 static bool_t 1705 svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg) 1706 { 1707 /* LINTED pointer alignment */ 1708 struct cf_conn *cd = (struct cf_conn *)(xprt->xp_p1); 1709 XDR *xdrs = svc_xdrs[xprt->xp_fd]; 1710 1711 xdrs->x_op = XDR_DECODE; 1712 1713 if (cd->cf_conn_nonblock) { 1714 /* Get the next input */ 1715 if (!__xdrrec_getbytes_nonblock(xdrs, &cd->strm_stat)) { 1716 /* 1717 * The entire record has not been received. 1718 * If the xprt has died, pass it along in svc_flags. 1719 * Return FALSE; For nonblocked vc connection, 1720 * xdr_callmsg() is called only after the entire 1721 * record has been received. For blocked vc 1722 * connection, the data is received on the fly as it 1723 * is being processed through the xdr routines. 1724 */ 1725 if (cd->strm_stat == XPRT_DIED) 1726 /* LINTED pointer cast */ 1727 svc_flags(xprt) |= SVC_FAILED; 1728 return (FALSE); 1729 } 1730 } else { 1731 if (!xdrrec_skiprecord(xdrs)) 1732 return (FALSE); 1733 (void) __xdrrec_setfirst(xdrs); 1734 } 1735 1736 if (xdr_callmsg(xdrs, msg)) { 1737 cd->x_id = msg->rm_xid; 1738 return (TRUE); 1739 } 1740 1741 /* 1742 * If a non-blocking connection, drop it when message decode fails. 1743 * We are either under attack, or we're talking to a broken client. 1744 */ 1745 if (cd->cf_conn_nonblock) { 1746 /* LINTED pointer cast */ 1747 svc_flags(xprt) |= SVC_FAILED; 1748 } 1749 1750 return (FALSE); 1751 } 1752 1753 static bool_t 1754 svc_vc_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) 1755 { 1756 bool_t dummy; 1757 1758 /* LINTED pointer alignment */ 1759 dummy = SVCAUTH_UNWRAP(&SVC_XP_AUTH(xprt), svc_xdrs[xprt->xp_fd], 1760 xdr_args, args_ptr); 1761 if (svc_mt_mode != RPC_SVC_MT_NONE) 1762 svc_args_done(xprt); 1763 return (dummy); 1764 } 1765 1766 static bool_t 1767 svc_vc_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) 1768 { 1769 /* LINTED pointer alignment */ 1770 XDR *xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs); 1771 1772 xdrs->x_op = XDR_FREE; 1773 return ((*xdr_args)(xdrs, args_ptr)); 1774 } 1775 1776 static bool_t 1777 svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg) 1778 { 1779 /* LINTED pointer alignment */ 1780 struct cf_conn *cd = (struct cf_conn *)(xprt->xp_p1); 1781 XDR *xdrs = &(cd->xdrs); 1782 bool_t stat = FALSE; 1783 xdrproc_t xdr_results; 1784 caddr_t xdr_location; 1785 bool_t has_args; 1786 1787 #ifdef __lock_lint 1788 (void) mutex_lock(&svc_send_mutex(SVCEXT(xprt)->parent)); 1789 #else 1790 if (svc_mt_mode != RPC_SVC_MT_NONE) 1791 /* LINTED pointer alignment */ 1792 (void) mutex_lock(&svc_send_mutex(SVCEXT(xprt)->parent)); 1793 #endif 1794 1795 if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 1796 msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 1797 has_args = TRUE; 1798 xdr_results = msg->acpted_rply.ar_results.proc; 1799 xdr_location = msg->acpted_rply.ar_results.where; 1800 msg->acpted_rply.ar_results.proc = xdr_void; 1801 msg->acpted_rply.ar_results.where = NULL; 1802 } else 1803 has_args = FALSE; 1804 1805 xdrs->x_op = XDR_ENCODE; 1806 msg->rm_xid = cd->x_id; 1807 /* LINTED pointer alignment */ 1808 if (xdr_replymsg(xdrs, msg) && (!has_args || SVCAUTH_WRAP( 1809 &SVC_XP_AUTH(xprt), xdrs, xdr_results, xdr_location))) { 1810 stat = TRUE; 1811 } 1812 (void) xdrrec_endofrecord(xdrs, TRUE); 1813 1814 #ifdef __lock_lint 1815 (void) mutex_unlock(&svc_send_mutex(SVCEXT(xprt)->parent)); 1816 #else 1817 if (svc_mt_mode != RPC_SVC_MT_NONE) 1818 /* LINTED pointer alignment */ 1819 (void) mutex_unlock(&svc_send_mutex(SVCEXT(xprt)->parent)); 1820 #endif 1821 1822 return (stat); 1823 } 1824 1825 static struct xp_ops * 1826 svc_vc_ops(void) 1827 { 1828 static struct xp_ops ops; 1829 extern mutex_t ops_lock; 1830 1831 /* VARIABLES PROTECTED BY ops_lock: ops */ 1832 1833 (void) mutex_lock(&ops_lock); 1834 if (ops.xp_recv == NULL) { 1835 ops.xp_recv = svc_vc_recv; 1836 ops.xp_stat = svc_vc_stat; 1837 ops.xp_getargs = svc_vc_getargs; 1838 ops.xp_reply = svc_vc_reply; 1839 ops.xp_freeargs = svc_vc_freeargs; 1840 ops.xp_destroy = svc_vc_destroy; 1841 ops.xp_control = svc_vc_control; 1842 } 1843 (void) mutex_unlock(&ops_lock); 1844 return (&ops); 1845 } 1846 1847 static struct xp_ops * 1848 svc_vc_rendezvous_ops(void) 1849 { 1850 static struct xp_ops ops; 1851 extern mutex_t ops_lock; 1852 1853 (void) mutex_lock(&ops_lock); 1854 if (ops.xp_recv == NULL) { 1855 ops.xp_recv = rendezvous_request; 1856 ops.xp_stat = rendezvous_stat; 1857 ops.xp_getargs = (bool_t (*)())abort; 1858 ops.xp_reply = (bool_t (*)())abort; 1859 ops.xp_freeargs = (bool_t (*)())abort; 1860 ops.xp_destroy = svc_vc_destroy; 1861 ops.xp_control = rendezvous_control; 1862 } 1863 (void) mutex_unlock(&ops_lock); 1864 return (&ops); 1865 } 1866 1867 /* 1868 * PRIVATE RPC INTERFACE 1869 * 1870 * This is a hack to let NIS+ clean up connections that have already been 1871 * closed. This problem arises because rpc.nisd forks a child to handle 1872 * existing connections when it does checkpointing. The child may close 1873 * some of these connections. But the descriptors still stay open in the 1874 * parent, and because TLI descriptors don't support persistent EOF 1875 * condition (like sockets do), the parent will never detect that these 1876 * descriptors are dead. 1877 * 1878 * The following internal procedure __svc_nisplus_fdcleanup_hack() - should 1879 * be removed as soon as rpc.nisd is rearchitected to do the right thing. 1880 * This procedure should not find its way into any header files. 1881 * 1882 * This procedure should be called only when rpc.nisd knows that there 1883 * are no children servicing clients. 1884 */ 1885 1886 static bool_t 1887 fd_is_dead(int fd) 1888 { 1889 struct T_info_ack inforeq; 1890 int retval; 1891 1892 inforeq.PRIM_type = T_INFO_REQ; 1893 if (!_t_do_ioctl(fd, (caddr_t)&inforeq, sizeof (struct T_info_req), 1894 TI_GETINFO, &retval)) 1895 return (TRUE); 1896 if (retval != (int)sizeof (struct T_info_ack)) 1897 return (TRUE); 1898 1899 switch (inforeq.CURRENT_state) { 1900 case TS_UNBND: 1901 case TS_IDLE: 1902 return (TRUE); 1903 default: 1904 break; 1905 } 1906 return (FALSE); 1907 } 1908 1909 void 1910 __svc_nisplus_fdcleanup_hack(void) 1911 { 1912 SVCXPRT *xprt; 1913 SVCXPRT *dead_xprt[CLEANUP_SIZE]; 1914 int i, fd_idx = 0, dead_idx = 0; 1915 1916 if (svc_xports == NULL) 1917 return; 1918 for (;;) { 1919 (void) rw_wrlock(&svc_fd_lock); 1920 for (dead_idx = 0; fd_idx < svc_max_pollfd; fd_idx++) { 1921 if ((xprt = svc_xports[fd_idx]) == NULL) 1922 continue; 1923 /* LINTED pointer alignment */ 1924 if (svc_type(xprt) != SVC_CONNECTION) 1925 continue; 1926 if (fd_is_dead(fd_idx)) { 1927 dead_xprt[dead_idx++] = xprt; 1928 if (dead_idx >= CLEANUP_SIZE) 1929 break; 1930 } 1931 } 1932 1933 for (i = 0; i < dead_idx; i++) { 1934 /* Still holding svc_fd_lock */ 1935 _svc_vc_destroy_private(dead_xprt[i], FALSE); 1936 } 1937 (void) rw_unlock(&svc_fd_lock); 1938 if (fd_idx++ >= svc_max_pollfd) 1939 return; 1940 } 1941 } 1942 1943 void 1944 __svc_nisplus_enable_timestamps(void) 1945 { 1946 (void) mutex_lock(×tamp_lock); 1947 if (!timestamps) { 1948 timestamps = calloc(FD_INCREMENT, sizeof (long)); 1949 if (timestamps != NULL) 1950 ntimestamps = FD_INCREMENT; 1951 else { 1952 (void) mutex_unlock(×tamp_lock); 1953 syslog(LOG_ERR, "__svc_nisplus_enable_timestamps: " 1954 "out of memory"); 1955 return; 1956 } 1957 } 1958 (void) mutex_unlock(×tamp_lock); 1959 } 1960 1961 void 1962 __svc_nisplus_purge_since(long since) 1963 { 1964 SVCXPRT *xprt; 1965 SVCXPRT *dead_xprt[CLEANUP_SIZE]; 1966 int i, fd_idx = 0, dead_idx = 0; 1967 1968 if (svc_xports == NULL) 1969 return; 1970 for (;;) { 1971 (void) rw_wrlock(&svc_fd_lock); 1972 (void) mutex_lock(×tamp_lock); 1973 for (dead_idx = 0; fd_idx < svc_max_pollfd; fd_idx++) { 1974 if ((xprt = svc_xports[fd_idx]) == NULL) { 1975 continue; 1976 } 1977 /* LINTED pointer cast */ 1978 if (svc_type(xprt) != SVC_CONNECTION) { 1979 continue; 1980 } 1981 if (fd_idx >= ntimestamps) { 1982 break; 1983 } 1984 if (timestamps[fd_idx] && 1985 timestamps[fd_idx] < since) { 1986 dead_xprt[dead_idx++] = xprt; 1987 if (dead_idx >= CLEANUP_SIZE) 1988 break; 1989 } 1990 } 1991 (void) mutex_unlock(×tamp_lock); 1992 1993 for (i = 0; i < dead_idx; i++) { 1994 /* Still holding svc_fd_lock */ 1995 _svc_vc_destroy_private(dead_xprt[i], FALSE); 1996 } 1997 (void) rw_unlock(&svc_fd_lock); 1998 if (fd_idx++ >= svc_max_pollfd) 1999 return; 2000 } 2001 } 2002 2003 /* 2004 * dup cache wrapper functions for vc requests. The set of dup 2005 * functions were written with the view that they may be expanded 2006 * during creation of a generic svc_vc_enablecache routine 2007 * which would have a size based cache, rather than a time based cache. 2008 * The real work is done in generic svc.c 2009 */ 2010 bool_t 2011 __svc_vc_dupcache_init(SVCXPRT *xprt, void *condition, int basis) 2012 { 2013 return (__svc_dupcache_init(condition, basis, 2014 /* LINTED pointer alignment */ 2015 &(((struct cf_rendezvous *)xprt->xp_p1)->cf_cache))); 2016 } 2017 2018 int 2019 __svc_vc_dup(struct svc_req *req, caddr_t *resp_buf, uint_t *resp_bufsz) 2020 { 2021 return (__svc_dup(req, resp_buf, resp_bufsz, 2022 /* LINTED pointer alignment */ 2023 ((struct cf_conn *)req->rq_xprt->xp_p1)->cf_cache)); 2024 } 2025 2026 int 2027 __svc_vc_dupdone(struct svc_req *req, caddr_t resp_buf, uint_t resp_bufsz, 2028 int status) 2029 { 2030 return (__svc_dupdone(req, resp_buf, resp_bufsz, status, 2031 /* LINTED pointer alignment */ 2032 ((struct cf_conn *)req->rq_xprt->xp_p1)->cf_cache)); 2033 } 2034