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