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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
30 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
31 /* All Rights Reserved */
33 * Portions of this source code were derived from Berkeley
34 * 4.3 BSD under license from the Regents of the University of
39 * Server side for Connection Oriented RPC.
41 * Actually implements two flavors of transporter -
42 * a rendezvouser (a listener and connection establisher)
43 * and a record stream.
51 #include <sys/types.h>
54 #include <sys/mkdev.h>
57 #include <rpc/nettype.h>
63 #include <sys/timod.h>
67 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
70 #define CLEANUP_SIZE 1024
73 extern int __rpc_connmaxrec
;
74 extern int __rpc_irtimeout
;
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 __rpc_legal_connmaxrec(int);
81 /* Structure used to initialize SVC_XP_AUTH(xprt).svc_ah_ops. */
82 extern struct svc_auth_ops svc_auth_any_ops
;
83 extern void __xprt_unregister_private(const SVCXPRT
*, bool_t
);
85 static struct xp_ops
*svc_vc_ops(void);
86 static struct xp_ops
*svc_vc_rendezvous_ops(void);
87 static void svc_vc_destroy(SVCXPRT
*);
88 static bool_t
svc_vc_nonblock(SVCXPRT
*, SVCXPRT
*);
89 static int read_vc(SVCXPRT
*, caddr_t
, int);
90 static int write_vc(SVCXPRT
*, caddr_t
, int);
91 static SVCXPRT
*makefd_xprt(int, uint_t
, uint_t
, t_scalar_t
, char *);
92 static void update_nonblock_timestamps(SVCXPRT
*);
94 struct cf_rendezvous
{ /* kept in xprt->xp_p1 for rendezvouser */
97 struct t_call
*t_call
;
98 struct t_bind
*t_bind
;
106 struct cf_conn
{ /* kept in xprt->xp_p1 for actual connection */
109 enum xprt_stat strm_stat
;
114 char verf_body
[MAX_AUTH_BYTES
];
115 bool_t cf_conn_nonblock
;
116 time_t cf_conn_nonblock_timestamp
;
119 static int t_rcvall(int, char *, int);
120 static int t_rcvnonblock(SVCXPRT
*, caddr_t
, int);
121 static void svc_timeout_nonblock_xprt_and_LRU(bool_t
);
123 extern int __xdrrec_setfirst(XDR
*);
124 extern int __xdrrec_resetfirst(XDR
*);
125 extern int __is_xdrrec_first(XDR
*);
128 * This is intended as a performance improvement on the old string handling
129 * stuff by read only moving data into the text segment.
130 * Format = <routine> : <error>
133 static const char errstring
[] = " %s : %s";
137 static const char svc_vc_create_str
[] = "svc_vc_create";
138 static const char svc_fd_create_str
[] = "svc_fd_create";
139 static const char makefd_xprt_str
[] = "svc_vc_create: makefd_xprt ";
140 static const char rendezvous_request_str
[] = "rendezvous_request";
141 static const char svc_vc_fderr
[] =
142 "fd > FD_SETSIZE; Use rpc_control(RPC_SVC_USE_POLLFD,...);";
143 static const char do_accept_str
[] = "do_accept";
147 static const char no_mem_str
[] = "out of memory";
148 static const char no_tinfo_str
[] = "could not get transport information";
149 static const char no_fcntl_getfl_str
[] = "could not get status flags and modes";
150 static const char no_nonblock_str
[] = "could not set transport non-blocking";
153 * Used to determine whether the time-out logic should be executed.
155 static bool_t check_nonblock_timestamps
= FALSE
;
158 svc_vc_xprtfree(SVCXPRT
*xprt
)
160 /* LINTED pointer alignment */
161 SVCXPRT_EXT
*xt
= xprt
? SVCEXT(xprt
) : NULL
;
162 struct cf_rendezvous
*r
= xprt
?
163 /* LINTED pointer alignment */
164 (struct cf_rendezvous
*)xprt
->xp_p1
: NULL
;
172 free(xprt
->xp_netid
);
173 if (xt
&& (xt
->parent
== NULL
)) {
174 if (xprt
->xp_ltaddr
.buf
)
175 free(xprt
->xp_ltaddr
.buf
);
176 if (xprt
->xp_rtaddr
.buf
)
177 free(xprt
->xp_rtaddr
.buf
);
181 (void) t_free((char *)r
->t_call
, T_CALL
);
183 (void) t_free((char *)r
->t_bind
, T_BIND
);
191 * xprt = svc_vc_create(fd, sendsize, recvsize);
192 * Since connection streams do buffered io similar to stdio, the caller
193 * can specify how big the send and receive buffers are. If recvsize
194 * or sendsize are 0, defaults will be chosen.
195 * fd should be open and bound.
198 svc_vc_create_private(int fd
, uint_t sendsize
, uint_t recvsize
)
200 struct cf_rendezvous
*r
;
204 if (RPC_FD_NOTIN_FDSET(fd
)) {
207 (void) syslog(LOG_ERR
, errstring
, svc_vc_create_str
,
211 if ((xprt
= svc_xprt_alloc()) == NULL
) {
212 (void) syslog(LOG_ERR
, errstring
,
213 svc_vc_create_str
, no_mem_str
);
216 /* LINTED pointer alignment */
217 svc_flags(xprt
) |= SVC_RENDEZVOUS
;
219 r
= calloc(1, sizeof (*r
));
221 (void) syslog(LOG_ERR
, errstring
,
222 svc_vc_create_str
, no_mem_str
);
223 svc_vc_xprtfree(xprt
);
226 if (t_getinfo(fd
, &tinfo
) == -1) {
229 __tli_sys_strerror(errorstr
, sizeof (errorstr
),
231 (void) syslog(LOG_ERR
, "%s : %s : %s",
232 svc_vc_create_str
, no_tinfo_str
, errorstr
);
234 svc_vc_xprtfree(xprt
);
238 * Find the receive and the send size
240 r
->sendsize
= __rpc_get_t_size((int)sendsize
, tinfo
.tsdu
);
241 r
->recvsize
= __rpc_get_t_size((int)recvsize
, tinfo
.tsdu
);
242 if ((r
->sendsize
== 0) || (r
->recvsize
== 0)) {
244 "svc_vc_create: transport does not support "
247 svc_vc_xprtfree(xprt
);
251 /* LINTED pointer alignment */
252 r
->t_call
= (struct t_call
*)t_alloc(fd
, T_CALL
, T_ADDR
| T_OPT
);
253 if (r
->t_call
== NULL
) {
254 (void) syslog(LOG_ERR
, errstring
,
255 svc_vc_create_str
, no_mem_str
);
257 svc_vc_xprtfree(xprt
);
261 /* LINTED pointer alignment */
262 r
->t_bind
= (struct t_bind
*)t_alloc(fd
, T_BIND
, T_ADDR
);
263 if (r
->t_bind
== NULL
) {
264 (void) syslog(LOG_ERR
, errstring
,
265 svc_vc_create_str
, no_mem_str
);
266 (void) t_free((char *)r
->t_call
, T_CALL
);
268 svc_vc_xprtfree(xprt
);
272 r
->cf_tsdu
= tinfo
.tsdu
;
274 r
->tcp_keepalive
= FALSE
;
275 r
->cf_connmaxrec
= __rpc_connmaxrec
;
277 xprt
->xp_p1
= (caddr_t
)r
;
279 xprt
->xp_verf
= _null_auth
;
280 xprt
->xp_ops
= svc_vc_rendezvous_ops();
281 /* LINTED pointer alignment */
282 SVC_XP_AUTH(xprt
).svc_ah_ops
= svc_auth_any_ops
;
283 /* LINTED pointer alignment */
284 SVC_XP_AUTH(xprt
).svc_ah_private
= NULL
;
290 svc_vc_create(const int fd
, const uint_t sendsize
, const uint_t recvsize
)
294 if ((xprt
= svc_vc_create_private(fd
, sendsize
, recvsize
)) != NULL
)
300 svc_vc_xprtcopy(SVCXPRT
*parent
)
303 struct cf_rendezvous
*r
, *pr
;
304 int fd
= parent
->xp_fd
;
306 if ((xprt
= svc_xprt_alloc()) == NULL
)
309 /* LINTED pointer alignment */
310 SVCEXT(xprt
)->parent
= parent
;
311 /* LINTED pointer alignment */
312 SVCEXT(xprt
)->flags
= SVCEXT(parent
)->flags
;
315 xprt
->xp_ops
= svc_vc_rendezvous_ops();
317 xprt
->xp_tp
= (char *)strdup(parent
->xp_tp
);
318 if (xprt
->xp_tp
== NULL
) {
319 syslog(LOG_ERR
, "svc_vc_xprtcopy: strdup failed");
320 svc_vc_xprtfree(xprt
);
324 if (parent
->xp_netid
) {
325 xprt
->xp_netid
= (char *)strdup(parent
->xp_netid
);
326 if (xprt
->xp_netid
== NULL
) {
327 syslog(LOG_ERR
, "svc_vc_xprtcopy: strdup failed");
330 svc_vc_xprtfree(xprt
);
336 * can share both local and remote address
338 xprt
->xp_ltaddr
= parent
->xp_ltaddr
;
339 xprt
->xp_rtaddr
= parent
->xp_rtaddr
; /* XXX - not used for rendezvous */
340 xprt
->xp_type
= parent
->xp_type
;
341 xprt
->xp_verf
= parent
->xp_verf
;
343 if ((r
= calloc(1, sizeof (*r
))) == NULL
) {
344 svc_vc_xprtfree(xprt
);
347 xprt
->xp_p1
= (caddr_t
)r
;
348 /* LINTED pointer alignment */
349 pr
= (struct cf_rendezvous
*)parent
->xp_p1
;
350 r
->sendsize
= pr
->sendsize
;
351 r
->recvsize
= pr
->recvsize
;
352 r
->cf_tsdu
= pr
->cf_tsdu
;
353 r
->cf_cache
= pr
->cf_cache
;
354 r
->tcp_flag
= pr
->tcp_flag
;
355 r
->tcp_keepalive
= pr
->tcp_keepalive
;
356 r
->cf_connmaxrec
= pr
->cf_connmaxrec
;
357 /* LINTED pointer alignment */
358 r
->t_call
= (struct t_call
*)t_alloc(fd
, T_CALL
, T_ADDR
| T_OPT
);
359 if (r
->t_call
== NULL
) {
360 svc_vc_xprtfree(xprt
);
363 /* LINTED pointer alignment */
364 r
->t_bind
= (struct t_bind
*)t_alloc(fd
, T_BIND
, T_ADDR
);
365 if (r
->t_bind
== NULL
) {
366 svc_vc_xprtfree(xprt
);
374 * XXX : Used for setting flag to indicate that this is TCP
379 __svc_vc_setflag(SVCXPRT
*xprt
, int flag
)
381 struct cf_rendezvous
*r
;
383 /* LINTED pointer alignment */
384 r
= (struct cf_rendezvous
*)xprt
->xp_p1
;
390 * used for the actual connection.
393 svc_fd_create_private(int fd
, uint_t sendsize
, uint_t recvsize
)
397 struct netbuf tres
= {0};
399 if (RPC_FD_NOTIN_FDSET(fd
)) {
402 (void) syslog(LOG_ERR
, errstring
,
403 svc_fd_create_str
, svc_vc_fderr
);
406 if (t_getinfo(fd
, &tinfo
) == -1) {
409 __tli_sys_strerror(errorstr
, sizeof (errorstr
),
411 (void) syslog(LOG_ERR
, "%s : %s : %s",
412 svc_fd_create_str
, no_tinfo_str
, errorstr
);
416 * Find the receive and the send size
418 sendsize
= __rpc_get_t_size((int)sendsize
, tinfo
.tsdu
);
419 recvsize
= __rpc_get_t_size((int)recvsize
, tinfo
.tsdu
);
420 if ((sendsize
== 0) || (recvsize
== 0)) {
421 syslog(LOG_ERR
, errstring
, svc_fd_create_str
,
422 "transport does not support data transfer");
425 dummy
= makefd_xprt(fd
, sendsize
, recvsize
, tinfo
.tsdu
, NULL
);
426 /* NULL signifies no dup cache */
427 /* Assign the local bind address */
428 if (t_getname(fd
, &tres
, LOCALNAME
) == -1)
430 dummy
->xp_ltaddr
= tres
;
431 /* Fill in type of service */
432 dummy
->xp_type
= tinfo
.servtype
;
437 svc_fd_create(const int fd
, const uint_t sendsize
, const uint_t recvsize
)
441 if ((xprt
= svc_fd_create_private(fd
, sendsize
, recvsize
)) != NULL
)
447 svc_fd_xprtfree(SVCXPRT
*xprt
)
449 /* LINTED pointer alignment */
450 SVCXPRT_EXT
*xt
= xprt
? SVCEXT(xprt
) : NULL
;
451 /* LINTED pointer alignment */
452 struct cf_conn
*cd
= xprt
? (struct cf_conn
*)xprt
->xp_p1
: NULL
;
460 free(xprt
->xp_netid
);
461 if (xt
&& (xt
->parent
== NULL
)) {
462 if (xprt
->xp_ltaddr
.buf
)
463 free(xprt
->xp_ltaddr
.buf
);
464 if (xprt
->xp_rtaddr
.buf
)
465 free(xprt
->xp_rtaddr
.buf
);
468 XDR_DESTROY(&(cd
->xdrs
));
471 if (xt
&& (xt
->parent
== NULL
) && xprt
->xp_p2
) {
472 /* LINTED pointer alignment */
473 free(((struct netbuf
*)xprt
->xp_p2
)->buf
);
480 makefd_xprt(int fd
, uint_t sendsize
, uint_t recvsize
, t_scalar_t tsdu
,
486 xprt
= svc_xprt_alloc();
488 (void) syslog(LOG_ERR
, errstring
, makefd_xprt_str
, no_mem_str
);
491 /* LINTED pointer alignment */
492 svc_flags(xprt
) |= SVC_CONNECTION
;
494 cd
= malloc(sizeof (struct cf_conn
));
496 (void) syslog(LOG_ERR
, errstring
, makefd_xprt_str
, no_mem_str
);
497 svc_fd_xprtfree(xprt
);
500 cd
->sendsize
= sendsize
;
501 cd
->recvsize
= recvsize
;
502 cd
->strm_stat
= XPRT_IDLE
;
504 cd
->cf_cache
= cache
;
505 cd
->cf_conn_nonblock
= FALSE
;
506 cd
->cf_conn_nonblock_timestamp
= 0;
507 cd
->xdrs
.x_ops
= NULL
;
508 xdrrec_create(&(cd
->xdrs
), sendsize
, 0, (caddr_t
)xprt
,
509 (int(*)())NULL
, (int(*)(void *, char *, int))write_vc
);
510 if (cd
->xdrs
.x_ops
== NULL
) {
511 (void) syslog(LOG_ERR
, errstring
, makefd_xprt_str
, no_mem_str
);
513 svc_fd_xprtfree(xprt
);
517 (void) rw_wrlock(&svc_fd_lock
);
518 if (svc_xdrs
== NULL
) {
519 svc_xdrs
= calloc(FD_INCREMENT
, sizeof (XDR
*));
520 if (svc_xdrs
== NULL
) {
521 (void) syslog(LOG_ERR
, errstring
, makefd_xprt_str
,
523 XDR_DESTROY(&(cd
->xdrs
));
525 svc_fd_xprtfree(xprt
);
526 (void) rw_unlock(&svc_fd_lock
);
529 nsvc_xdrs
= FD_INCREMENT
;
532 while (fd
>= nsvc_xdrs
) {
533 XDR
**tmp_xdrs
= reallocarray(svc_xdrs
,
534 nsvc_xdrs
+ FD_INCREMENT
, sizeof (XDR
*));
535 if (tmp_xdrs
== NULL
) {
536 (void) syslog(LOG_ERR
, errstring
, makefd_xprt_str
,
538 XDR_DESTROY(&(cd
->xdrs
));
540 svc_fd_xprtfree(xprt
);
541 (void) rw_unlock(&svc_fd_lock
);
546 /* initial the new array to 0 from the last allocated array */
547 (void) memset(&svc_xdrs
[nsvc_xdrs
], 0,
548 sizeof (XDR
*) * FD_INCREMENT
);
549 nsvc_xdrs
+= FD_INCREMENT
;
552 if (svc_xdrs
[fd
] != NULL
) {
553 XDR_DESTROY(svc_xdrs
[fd
]);
554 } else if ((svc_xdrs
[fd
] = malloc(sizeof (XDR
))) == NULL
) {
555 (void) syslog(LOG_ERR
, errstring
, makefd_xprt_str
, no_mem_str
);
556 XDR_DESTROY(&(cd
->xdrs
));
558 svc_fd_xprtfree(xprt
);
559 (void) rw_unlock(&svc_fd_lock
);
562 (void) memset(svc_xdrs
[fd
], 0, sizeof (XDR
));
563 xdrrec_create(svc_xdrs
[fd
], 0, recvsize
, (caddr_t
)xprt
,
564 (int(*)(void *, char *, int))read_vc
, (int(*)())NULL
);
565 if (svc_xdrs
[fd
]->x_ops
== NULL
) {
568 XDR_DESTROY(&(cd
->xdrs
));
570 svc_fd_xprtfree(xprt
);
571 (void) rw_unlock(&svc_fd_lock
);
574 (void) rw_unlock(&svc_fd_lock
);
576 xprt
->xp_p1
= (caddr_t
)cd
;
578 xprt
->xp_verf
.oa_base
= cd
->verf_body
;
579 xprt
->xp_ops
= svc_vc_ops(); /* truely deals with calls */
585 svc_fd_xprtcopy(SVCXPRT
*parent
)
588 struct cf_conn
*cd
, *pcd
;
590 if ((xprt
= svc_xprt_alloc()) == NULL
)
593 /* LINTED pointer alignment */
594 SVCEXT(xprt
)->parent
= parent
;
595 /* LINTED pointer alignment */
596 SVCEXT(xprt
)->flags
= SVCEXT(parent
)->flags
;
598 xprt
->xp_fd
= parent
->xp_fd
;
599 xprt
->xp_ops
= svc_vc_ops();
601 xprt
->xp_tp
= (char *)strdup(parent
->xp_tp
);
602 if (xprt
->xp_tp
== NULL
) {
603 syslog(LOG_ERR
, "svc_fd_xprtcopy: strdup failed");
604 svc_fd_xprtfree(xprt
);
608 if (parent
->xp_netid
) {
609 xprt
->xp_netid
= (char *)strdup(parent
->xp_netid
);
610 if (xprt
->xp_netid
== NULL
) {
611 syslog(LOG_ERR
, "svc_fd_xprtcopy: strdup failed");
614 svc_fd_xprtfree(xprt
);
619 * share local and remote addresses with parent
621 xprt
->xp_ltaddr
= parent
->xp_ltaddr
;
622 xprt
->xp_rtaddr
= parent
->xp_rtaddr
;
623 xprt
->xp_type
= parent
->xp_type
;
625 if ((cd
= malloc(sizeof (struct cf_conn
))) == NULL
) {
626 svc_fd_xprtfree(xprt
);
629 /* LINTED pointer alignment */
630 pcd
= (struct cf_conn
*)parent
->xp_p1
;
631 cd
->sendsize
= pcd
->sendsize
;
632 cd
->recvsize
= pcd
->recvsize
;
633 cd
->strm_stat
= pcd
->strm_stat
;
634 cd
->x_id
= pcd
->x_id
;
635 cd
->cf_tsdu
= pcd
->cf_tsdu
;
636 cd
->cf_cache
= pcd
->cf_cache
;
637 cd
->cf_conn_nonblock
= pcd
->cf_conn_nonblock
;
638 cd
->cf_conn_nonblock_timestamp
= pcd
->cf_conn_nonblock_timestamp
;
639 cd
->xdrs
.x_ops
= NULL
;
640 xdrrec_create(&(cd
->xdrs
), cd
->sendsize
, 0, (caddr_t
)xprt
,
641 (int(*)())NULL
, (int(*)(void *, char *, int))write_vc
);
642 if (cd
->xdrs
.x_ops
== NULL
) {
644 svc_fd_xprtfree(xprt
);
647 xprt
->xp_verf
.oa_base
= cd
->verf_body
;
648 xprt
->xp_p1
= (char *)cd
;
649 xprt
->xp_p2
= parent
->xp_p2
; /* shared */
654 static void do_accept();
657 * This routine is called by svc_getreqset(), when a packet is recd.
658 * The listener process creates another end point on which the actual
659 * connection is carried. It returns FALSE to indicate that it was
660 * not a rpc packet (falsely though), but as a side effect creates
661 * another endpoint which is also registered, which then always
662 * has a request ready to be served.
666 rendezvous_request(SVCXPRT
*xprt
, struct rpc_msg
*msg
)
668 struct cf_rendezvous
*r
;
672 /* LINTED pointer alignment */
673 r
= (struct cf_rendezvous
*)xprt
->xp_p1
;
676 switch (t_look(xprt
->xp_fd
)) {
678 (void) t_rcvdis(xprt
->xp_fd
, NULL
);
683 if (t_listen(xprt
->xp_fd
, r
->t_call
) == -1) {
684 if ((t_errno
== TSYSERR
) && (errno
== EINTR
))
687 if (t_errno
== TLOOK
) {
688 if (t_look(xprt
->xp_fd
) == T_DISCONNECT
)
689 (void) t_rcvdis(xprt
->xp_fd
, NULL
);
698 * Now create another endpoint, and accept the connection
703 tpname
= xprt
->xp_tp
;
706 * If xprt->xp_tp is NULL, then try to extract the
707 * transport protocol information from the transport
708 * protcol corresponding to xprt->xp_fd
710 struct netconfig
*nconf
;
712 if ((nconf
= __rpcfd_to_nconf(xprt
->xp_fd
, xprt
->xp_type
))
714 (void) syslog(LOG_ERR
, errstring
,
715 rendezvous_request_str
, "no suitable transport");
718 (void) strcpy(tpname
, nconf
->nc_device
);
719 freenetconfigent(nconf
);
722 do_accept(xprt
->xp_fd
, tpname
, xprt
->xp_netid
, r
);
725 return (FALSE
); /* there is never an rpc msg to be processed */
729 struct t_call
*t_call
;
734 do_accept(int srcfd
, char *tpname
, char *netid
, struct cf_rendezvous
*r
)
737 struct t_call t_call
;
738 struct t_call
*tcp2
= NULL
;
742 struct entry
*head
= NULL
;
743 struct entry
*tail
= NULL
;
750 destfd
= t_open(tpname
, O_RDWR
, &tinfo
);
751 if (check_nonblock_timestamps
) {
752 if (destfd
== -1 && t_errno
== TSYSERR
&& errno
== EMFILE
) {
754 * Since there are nonblocking connection xprts and
755 * too many open files, the LRU connection xprt should
756 * get destroyed in case an attacker has been creating
759 (void) mutex_lock(&svc_mutex
);
760 svc_timeout_nonblock_xprt_and_LRU(TRUE
);
761 (void) mutex_unlock(&svc_mutex
);
762 destfd
= t_open(tpname
, O_RDWR
, &tinfo
);
765 * Destroy/timeout all nonblock connection xprts
766 * that have not had recent activity.
767 * Do not destroy LRU xprt unless there are
768 * too many open files.
770 (void) mutex_lock(&svc_mutex
);
771 svc_timeout_nonblock_xprt_and_LRU(FALSE
);
772 (void) mutex_unlock(&svc_mutex
);
778 __tli_sys_strerror(errorstr
, sizeof (errorstr
), t_errno
, errno
);
779 (void) syslog(LOG_ERR
, "%s : %s : %s", do_accept_str
,
780 "can't open connection", errorstr
);
781 (void) t_snddis(srcfd
, tcp
);
785 if (RPC_FD_NOTIN_FDSET(destfd
)) {
786 (void) syslog(LOG_ERR
, errstring
, do_accept_str
, svc_vc_fderr
);
787 (void) t_close(destfd
);
788 (void) t_snddis(srcfd
, tcp
);
792 (void) fcntl(destfd
, F_SETFD
, FD_CLOEXEC
);
793 if ((tinfo
.servtype
!= T_COTS
) && (tinfo
.servtype
!= T_COTS_ORD
)) {
794 /* Not a connection oriented mode */
795 (void) syslog(LOG_ERR
, errstring
, do_accept_str
,
796 "do_accept: illegal transport");
797 (void) t_close(destfd
);
798 (void) t_snddis(srcfd
, tcp
);
804 if (t_bind(destfd
, NULL
, r
->t_bind
) == -1) {
807 __tli_sys_strerror(errorstr
, sizeof (errorstr
), t_errno
, errno
);
808 (void) syslog(LOG_ERR
, " %s : %s : %s", do_accept_str
,
809 "t_bind failed", errorstr
);
810 (void) t_close(destfd
);
811 (void) t_snddis(srcfd
, tcp
);
816 if (r
->tcp_flag
) /* if TCP, set NODELAY flag */
817 (void) __td_setnodelay(destfd
);
820 * This connection is not listening, hence no need to set
825 * XXX: The local transport chokes on its own listen
826 * options so we zero them for now
830 t_call
.opt
.maxlen
= 0;
831 t_call
.opt
.buf
= NULL
;
833 while (t_accept(srcfd
, destfd
, &t_call
) == -1) {
839 switch (t_look(srcfd
)) {
843 /* this should not happen */
847 (void) t_rcvdis(srcfd
, NULL
);
852 /* LINTED pointer alignment */
853 tcp2
= (struct t_call
*)t_alloc(srcfd
,
854 T_CALL
, T_ADDR
| T_OPT
);
856 (void) t_close(destfd
);
857 (void) t_snddis(srcfd
, tcp
);
858 syslog(LOG_ERR
, errstring
,
859 do_accept_str
, no_mem_str
);
863 if (t_listen(srcfd
, tcp2
) == -1) {
873 (void) t_close(destfd
);
874 (void) t_snddis(srcfd
, tcp
);
879 e
= malloc(sizeof (struct entry
));
881 (void) t_snddis(srcfd
, tcp2
);
882 (void) t_free((char *)tcp2
, T_CALL
);
901 (void) t_rcvrel(srcfd
);
902 (void) t_sndrel(srcfd
);
909 * This can happen if the remote side has
910 * disconnected before the connection is
911 * accepted. In this case, a disconnect
912 * should not be sent on srcfd (important!
913 * the listening fd will be hosed otherwise!).
914 * This error is not logged since this is an
915 * operational situation that is recoverable.
917 (void) t_close(destfd
);
923 * This can happen if the t_rcvdis() or t_rcvrel()/
924 * t_sndrel() put srcfd into the T_IDLE state.
926 if (t_getstate(srcfd
) == T_IDLE
) {
927 (void) t_close(destfd
);
928 (void) t_snddis(srcfd
, tcp
);
932 /* else FALL THROUGH TO */
935 __tli_sys_strerror(errorstr
, sizeof (errorstr
),
937 (void) syslog(LOG_ERR
,
938 "cannot accept connection: %s (current state %d)",
939 errorstr
, t_getstate(srcfd
));
940 (void) t_close(destfd
);
941 (void) t_snddis(srcfd
, tcp
);
947 if (r
->tcp_flag
&& r
->tcp_keepalive
) {
951 option
= malloc(sizeof (struct opthdr
) + sizeof (int));
952 option_ret
= malloc(sizeof (struct opthdr
) + sizeof (int));
953 if (option
!= NULL
&& option_ret
!= NULL
) {
955 struct t_optmgmt optreq
, optret
;
958 /* LINTED pointer cast */
959 opt
= (struct opthdr
*)option
;
960 opt
->level
= SOL_SOCKET
;
961 opt
->name
= SO_KEEPALIVE
;
962 opt
->len
= sizeof (int);
963 p_optval
= (int *)(opt
+ 1);
964 *p_optval
= SO_KEEPALIVE
;
965 optreq
.opt
.maxlen
= optreq
.opt
.len
=
966 sizeof (struct opthdr
) + sizeof (int);
967 optreq
.opt
.buf
= (char *)option
;
968 optreq
.flags
= T_NEGOTIATE
;
969 optret
.opt
.maxlen
= sizeof (struct opthdr
)
971 optret
.opt
.buf
= (char *)option_ret
;
972 (void) t_optmgmt(destfd
, &optreq
, &optret
);
980 * make a new transporter
982 xprt
= makefd_xprt(destfd
, r
->sendsize
, r
->recvsize
, r
->cf_tsdu
,
986 * makefd_xprt() returns a NULL xprt only when
987 * it's out of memory.
993 * Copy the new local and remote bind information
996 xprt
->xp_rtaddr
.len
= tcp
->addr
.len
;
997 xprt
->xp_rtaddr
.maxlen
= tcp
->addr
.len
;
998 if ((xprt
->xp_rtaddr
.buf
= malloc(tcp
->addr
.len
)) == NULL
)
1000 (void) memcpy(xprt
->xp_rtaddr
.buf
, tcp
->addr
.buf
, tcp
->addr
.len
);
1002 if (strcmp(netid
, "tcp") == 0) {
1003 xprt
->xp_ltaddr
.maxlen
= sizeof (struct sockaddr_in
);
1004 if ((xprt
->xp_ltaddr
.buf
=
1005 malloc(xprt
->xp_ltaddr
.maxlen
)) == NULL
)
1007 if (t_getname(destfd
, &xprt
->xp_ltaddr
, LOCALNAME
) < 0) {
1008 (void) syslog(LOG_ERR
,
1009 "do_accept: t_getname for tcp failed!");
1012 } else if (strcmp(netid
, "tcp6") == 0) {
1013 xprt
->xp_ltaddr
.maxlen
= sizeof (struct sockaddr_in6
);
1014 if ((xprt
->xp_ltaddr
.buf
=
1015 malloc(xprt
->xp_ltaddr
.maxlen
)) == NULL
)
1017 if (t_getname(destfd
, &xprt
->xp_ltaddr
, LOCALNAME
) < 0) {
1018 (void) syslog(LOG_ERR
,
1019 "do_accept: t_getname for tcp6 failed!");
1024 xprt
->xp_tp
= strdup(tpname
);
1025 xprt
->xp_netid
= strdup(netid
);
1026 if ((xprt
->xp_tp
== NULL
) ||
1027 (xprt
->xp_netid
== NULL
)) {
1030 if (tcp
->opt
.len
> 0) {
1031 xprt
->xp_p2
= malloc(sizeof (struct netbuf
));
1033 if (xprt
->xp_p2
!= NULL
) {
1034 /* LINTED pointer alignment */
1035 struct netbuf
*netptr
= (struct netbuf
*)xprt
->xp_p2
;
1037 netptr
->len
= tcp
->opt
.len
;
1038 netptr
->maxlen
= tcp
->opt
.len
;
1039 if ((netptr
->buf
= malloc(tcp
->opt
.len
)) == NULL
)
1041 (void) memcpy(netptr
->buf
, tcp
->opt
.buf
, tcp
->opt
.len
);
1045 /* (void) ioctl(destfd, I_POP, NULL); */
1048 * If a nonblocked connection fd has been requested,
1049 * perform the necessary operations.
1051 xprt_srcfd
= svc_xports
[srcfd
];
1052 /* LINTED pointer cast */
1053 if (((struct cf_rendezvous
*)(xprt_srcfd
->xp_p1
))->cf_connmaxrec
) {
1054 if (!svc_vc_nonblock(xprt_srcfd
, xprt
))
1059 * Copy the call back declared for the service to the current
1062 xprt
->xp_closeclnt
= xprt_srcfd
->xp_closeclnt
;
1063 xprt_register(xprt
);
1067 (void) t_free((char *)r
->t_call
, T_CALL
);
1068 r
->t_call
= head
->t_call
;
1076 (void) t_free((char *)tcp2
, T_CALL
);
1081 (void) syslog(LOG_ERR
, errstring
, do_accept_str
, no_mem_str
);
1084 svc_vc_destroy(xprt
);
1085 (void) t_close(destfd
);
1091 * This routine performs the necessary fcntl() operations to create
1092 * a nonblocked connection fd.
1093 * It also adjusts the sizes and allocates the buffer
1094 * for the nonblocked operations, and updates the associated
1095 * timestamp field in struct cf_conn for timeout bookkeeping.
1098 svc_vc_nonblock(SVCXPRT
*xprt_rendezvous
, SVCXPRT
*xprt_conn
)
1101 int fdconn
= xprt_conn
->xp_fd
;
1102 struct cf_rendezvous
*r
=
1103 /* LINTED pointer cast */
1104 (struct cf_rendezvous
*)xprt_rendezvous
->xp_p1
;
1105 /* LINTED pointer cast */
1106 struct cf_conn
*cd
= (struct cf_conn
*)xprt_conn
->xp_p1
;
1109 if ((nn
= fcntl(fdconn
, F_GETFL
, 0)) < 0) {
1110 (void) syslog(LOG_ERR
, "%s : %s : %m", do_accept_str
,
1111 no_fcntl_getfl_str
);
1115 if (fcntl(fdconn
, F_SETFL
, nn
|O_NONBLOCK
) != 0) {
1116 (void) syslog(LOG_ERR
, "%s : %s : %m", do_accept_str
,
1121 cd
->cf_conn_nonblock
= TRUE
;
1123 * If the max fragment size has not been set via
1124 * rpc_control(), use the default.
1126 if ((maxrecsz
= r
->cf_connmaxrec
) == 0)
1127 maxrecsz
= r
->recvsize
;
1128 /* Set XDR stream to use non-blocking semantics. */
1129 if (__xdrrec_set_conn_nonblock(svc_xdrs
[fdconn
], maxrecsz
)) {
1130 check_nonblock_timestamps
= TRUE
;
1131 update_nonblock_timestamps(xprt_conn
);
1138 static enum xprt_stat
1139 rendezvous_stat(SVCXPRT
*xprt
)
1145 svc_vc_destroy(SVCXPRT
*xprt
)
1147 (void) mutex_lock(&svc_mutex
);
1148 _svc_vc_destroy_private(xprt
, TRUE
);
1149 (void) svc_timeout_nonblock_xprt_and_LRU(FALSE
);
1150 (void) mutex_unlock(&svc_mutex
);
1154 _svc_vc_destroy_private(SVCXPRT
*xprt
, bool_t lock_not_held
)
1156 if (svc_mt_mode
!= RPC_SVC_MT_NONE
) {
1157 /* LINTED pointer alignment */
1158 if (SVCEXT(xprt
)->parent
)
1159 /* LINTED pointer alignment */
1160 xprt
= SVCEXT(xprt
)->parent
;
1161 /* LINTED pointer alignment */
1162 svc_flags(xprt
) |= SVC_DEFUNCT
;
1163 /* LINTED pointer alignment */
1164 if (SVCEXT(xprt
)->refcnt
> 0)
1168 if (xprt
->xp_closeclnt
!= NULL
) {
1169 svc_errorhandler_t cb
= xprt
->xp_closeclnt
;
1172 * Reset the pointer here to avoid reentrance on the same
1175 xprt
->xp_closeclnt
= NULL
;
1176 cb(xprt
, (xprt
->xp_rtaddr
.len
!= 0));
1179 __xprt_unregister_private(xprt
, lock_not_held
);
1180 (void) t_close(xprt
->xp_fd
);
1182 if (svc_mt_mode
!= RPC_SVC_MT_NONE
) {
1183 svc_xprt_destroy(xprt
);
1185 /* LINTED pointer alignment */
1186 if (svc_type(xprt
) == SVC_RENDEZVOUS
)
1187 svc_vc_xprtfree(xprt
);
1189 svc_fd_xprtfree(xprt
);
1195 svc_vc_control(SVCXPRT
*xprt
, const uint_t rq
, void *in
)
1198 case SVCSET_RECVERRHANDLER
:
1199 xprt
->xp_closeclnt
= (svc_errorhandler_t
)in
;
1201 case SVCGET_RECVERRHANDLER
:
1202 *(svc_errorhandler_t
*)in
= xprt
->xp_closeclnt
;
1205 if (xprt
->xp_p1
== NULL
)
1207 /* LINTED pointer alignment */
1208 *(uint32_t *)in
= ((struct cf_conn
*)(xprt
->xp_p1
))->x_id
;
1216 rendezvous_control(SVCXPRT
*xprt
, const uint_t rq
, void *in
)
1218 struct cf_rendezvous
*r
;
1222 case SVCSET_RECVERRHANDLER
:
1223 xprt
->xp_closeclnt
= (svc_errorhandler_t
)in
;
1225 case SVCGET_RECVERRHANDLER
:
1226 *(svc_errorhandler_t
*)in
= xprt
->xp_closeclnt
;
1228 case SVCSET_KEEPALIVE
:
1229 /* LINTED pointer cast */
1230 r
= (struct cf_rendezvous
*)xprt
->xp_p1
;
1232 r
->tcp_keepalive
= (int)(intptr_t)in
;
1236 case SVCSET_CONNMAXREC
:
1238 * Override the default maximum record size, set via
1239 * rpc_control(), for this connection. Only appropriate
1240 * for connection oriented transports, but is ignored for
1241 * the connectionless case, so no need to check the
1242 * connection type here.
1244 /* LINTED pointer cast */
1245 r
= (struct cf_rendezvous
*)xprt
->xp_p1
;
1246 tmp
= __rpc_legal_connmaxrec(*(int *)in
);
1247 if (r
!= 0 && tmp
>= 0) {
1248 r
->cf_connmaxrec
= tmp
;
1252 case SVCGET_CONNMAXREC
:
1253 /* LINTED pointer cast */
1254 r
= (struct cf_rendezvous
*)xprt
->xp_p1
;
1256 *(int *)in
= r
->cf_connmaxrec
;
1260 case SVCGET_XID
: /* fall through for now */
1267 * All read operations timeout after 35 seconds.
1268 * A timeout is fatal for the connection.
1269 * update_nonblock_timestamps() is used for nonblocked
1272 #define WAIT_PER_TRY 35000 /* milliseconds */
1275 update_nonblock_timestamps(SVCXPRT
*xprt_conn
)
1278 /* LINTED pointer cast */
1279 struct cf_conn
*cd
= (struct cf_conn
*)xprt_conn
->xp_p1
;
1281 (void) gettimeofday(&tv
, NULL
);
1282 cd
->cf_conn_nonblock_timestamp
= tv
.tv_sec
;
1286 * reads data from the vc conection.
1287 * any error is fatal and the connection is closed.
1288 * (And a read of zero bytes is a half closed stream => error.)
1291 read_vc(SVCXPRT
*xprt
, caddr_t buf
, int len
)
1293 int fd
= xprt
->xp_fd
;
1294 XDR
*xdrs
= svc_xdrs
[fd
];
1299 * Make sure the connection is not already dead.
1301 /* LINTED pointer alignment */
1302 if (svc_failed(xprt
))
1305 /* LINTED pointer cast */
1306 if (((struct cf_conn
*)(xprt
->xp_p1
))->cf_conn_nonblock
) {
1308 * For nonblocked reads, only update the
1309 * timestamps to record the activity so the
1310 * connection will not be timedout.
1311 * Up to "len" bytes are requested.
1312 * If fewer than "len" bytes are received, the
1313 * connection is poll()ed again.
1314 * The poll() for the connection fd is performed
1315 * in the main poll() so that all outstanding fds
1316 * are polled rather than just the vc connection.
1317 * Polling on only the vc connection until the entire
1318 * fragment has been read can be exploited in
1319 * a Denial of Service Attack such as telnet <host> 111.
1321 if ((len
= t_rcvnonblock(xprt
, buf
, len
)) >= 0) {
1323 update_nonblock_timestamps(xprt
);
1330 if (!__is_xdrrec_first(xdrs
)) {
1333 pfd
.events
= MASKVAL
;
1336 if ((ret
= poll(&pfd
, 1, WAIT_PER_TRY
)) <= 0) {
1338 * If errno is EINTR, ERESTART, or EAGAIN
1339 * ignore error and repeat poll
1341 if (ret
< 0 && (errno
== EINTR
||
1342 errno
== ERESTART
|| errno
== EAGAIN
))
1346 } while (pfd
.revents
== 0);
1347 if (pfd
.revents
& POLLNVAL
)
1350 (void) __xdrrec_resetfirst(xdrs
);
1351 if ((len
= t_rcvall(fd
, buf
, len
)) > 0) {
1356 /* LINTED pointer alignment */
1357 ((struct cf_conn
*)(xprt
->xp_p1
))->strm_stat
= XPRT_DIED
;
1358 /* LINTED pointer alignment */
1359 svc_flags(xprt
) |= SVC_FAILED
;
1364 * Requests up to "len" bytes of data.
1365 * Returns number of bytes actually received, or error indication.
1368 t_rcvnonblock(SVCXPRT
*xprt
, caddr_t buf
, int len
)
1370 int fd
= xprt
->xp_fd
;
1374 res
= t_rcv(fd
, buf
, (unsigned)len
, &flag
);
1378 switch (t_look(fd
)) {
1380 (void) t_rcvdis(fd
, NULL
);
1383 (void) t_rcvrel(fd
);
1384 (void) t_sndrel(fd
);
1392 * Either poll() lied, or the xprt/fd was closed and
1393 * re-opened under our feet. Return 0, so that we go
1394 * back to waiting for data.
1398 /* Should handle TBUFOVFLW TSYSERR ? */
1407 * Timeout out nonblocked connection fds
1408 * If there has been no activity on the fd for __rpc_irtimeout
1409 * seconds, timeout the fd by destroying its xprt.
1410 * If the caller gets an EMFILE error, the caller may also request
1411 * that the least busy xprt gets destroyed as well.
1412 * svc_thr_mutex is held when this is called.
1413 * svc_mutex is held when this is called.
1416 svc_timeout_nonblock_xprt_and_LRU(bool_t destroy_lru
)
1419 SVCXPRT
*dead_xprt
[CLEANUP_SIZE
];
1420 SVCXPRT
*candidate_xprt
= NULL
;
1422 int i
, fd_idx
= 0, dead_idx
= 0;
1424 time_t lasttime
, maxctime
= 0;
1425 extern rwlock_t svc_fd_lock
;
1427 if (!check_nonblock_timestamps
)
1430 (void) gettimeofday(&now
, NULL
);
1431 if (svc_xports
== NULL
)
1434 * Hold svc_fd_lock to protect
1435 * svc_xports, svc_maxpollfd, svc_max_pollfd
1437 (void) rw_wrlock(&svc_fd_lock
);
1440 * Timeout upto CLEANUP_SIZE connection fds per
1441 * iteration for the while(1) loop
1443 for (dead_idx
= 0; fd_idx
< svc_max_pollfd
; fd_idx
++) {
1444 if ((xprt
= svc_xports
[fd_idx
]) == NULL
) {
1447 /* Only look at connection fds */
1448 /* LINTED pointer cast */
1449 if (svc_type(xprt
) != SVC_CONNECTION
) {
1452 /* LINTED pointer cast */
1453 cd
= (struct cf_conn
*)xprt
->xp_p1
;
1454 if (!cd
->cf_conn_nonblock
)
1456 lasttime
= now
.tv_sec
- cd
->cf_conn_nonblock_timestamp
;
1457 if (lasttime
>= __rpc_irtimeout
&&
1458 __rpc_irtimeout
!= 0) {
1459 /* Enter in timedout/dead array */
1460 dead_xprt
[dead_idx
++] = xprt
;
1461 if (dead_idx
>= CLEANUP_SIZE
)
1464 if (lasttime
> maxctime
) {
1465 /* Possible LRU xprt */
1466 candidate_xprt
= xprt
;
1467 maxctime
= lasttime
;
1471 for (i
= 0; i
< dead_idx
; i
++) {
1472 /* Still holding svc_fd_lock */
1473 _svc_vc_destroy_private(dead_xprt
[i
], FALSE
);
1477 * If all the nonblocked fds have been checked, we're done.
1479 if (fd_idx
++ >= svc_max_pollfd
)
1482 if ((destroy_lru
) && (candidate_xprt
!= NULL
)) {
1483 _svc_vc_destroy_private(candidate_xprt
, FALSE
);
1485 (void) rw_unlock(&svc_fd_lock
);
1488 * Receive the required bytes of data, even if it is fragmented.
1491 t_rcvall(int fd
, char *buf
, int len
)
1498 res
= t_rcv(fd
, buf
, (unsigned)len
, &flag
);
1500 if (t_errno
== TLOOK
) {
1501 switch (t_look(fd
)) {
1503 (void) t_rcvdis(fd
, NULL
);
1506 (void) t_rcvrel(fd
);
1507 (void) t_sndrel(fd
);
1518 } while (len
&& (flag
& T_MORE
));
1519 return (res
== -1 ? -1 : final
);
1523 * writes data to the vc connection.
1524 * Any error is fatal and the connection is closed.
1527 write_vc(SVCXPRT
*xprt
, caddr_t buf
, int len
)
1535 /* LINTED pointer alignment */
1536 maxsz
= ((struct cf_conn
*)(xprt
->xp_p1
))->cf_tsdu
;
1537 /* LINTED pointer cast */
1538 nonblock
= ((struct cf_conn
*)(xprt
->xp_p1
))->cf_conn_nonblock
;
1539 if (nonblock
&& maxsz
<= 0)
1541 if ((maxsz
== 0) || (maxsz
== -1)) {
1542 if ((len
= t_snd(xprt
->xp_fd
, buf
, (unsigned)len
,
1544 if (t_errno
== TLOOK
) {
1545 switch (t_look(xprt
->xp_fd
)) {
1547 (void) t_rcvdis(xprt
->xp_fd
, NULL
);
1550 (void) t_rcvrel(xprt
->xp_fd
);
1551 (void) t_sndrel(xprt
->xp_fd
);
1557 /* LINTED pointer alignment */
1558 ((struct cf_conn
*)(xprt
->xp_p1
))->strm_stat
=
1560 /* LINTED pointer alignment */
1561 svc_flags(xprt
) |= SVC_FAILED
;
1567 * Setup for polling. We want to be able to write normal
1568 * data to the transport
1570 pfd
.fd
= xprt
->xp_fd
;
1571 pfd
.events
= POLLWRNORM
;
1574 * This for those transports which have a max size for data,
1575 * and for the non-blocking case, where t_snd() may send less
1578 for (cnt
= len
, i
= 0; cnt
> 0; cnt
-= i
, buf
+= i
) {
1579 flag
= cnt
> maxsz
? T_MORE
: 0;
1580 if ((i
= t_snd(xprt
->xp_fd
, buf
,
1581 (unsigned)MIN(cnt
, maxsz
), flag
)) == -1) {
1582 if (t_errno
== TLOOK
) {
1583 switch (t_look(xprt
->xp_fd
)) {
1585 (void) t_rcvdis(xprt
->xp_fd
, NULL
);
1588 (void) t_rcvrel(xprt
->xp_fd
);
1593 } else if (t_errno
== TFLOW
) {
1596 /* Wait till we can write to the transport */
1598 if (poll(&pfd
, 1, WAIT_PER_TRY
) < 0) {
1600 * If errno is ERESTART, or
1601 * EAGAIN ignore error and
1604 if (errno
== ERESTART
||
1610 } while (pfd
.revents
== 0);
1611 if (pfd
.revents
& (POLLNVAL
| POLLERR
|
1617 /* LINTED pointer alignment */
1618 ((struct cf_conn
*)(xprt
->xp_p1
))->strm_stat
=
1620 /* LINTED pointer alignment */
1621 svc_flags(xprt
) |= SVC_FAILED
;
1628 static enum xprt_stat
1629 svc_vc_stat(SVCXPRT
*xprt
)
1631 /* LINTED pointer alignment */
1632 SVCXPRT
*parent
= SVCEXT(xprt
)->parent
? SVCEXT(xprt
)->parent
: xprt
;
1634 /* LINTED pointer alignment */
1635 if (svc_failed(parent
) || svc_failed(xprt
))
1637 if (!xdrrec_eof(svc_xdrs
[xprt
->xp_fd
]))
1638 return (XPRT_MOREREQS
);
1640 * xdrrec_eof could have noticed that the connection is dead, so
1641 * check status again.
1643 /* LINTED pointer alignment */
1644 if (svc_failed(parent
) || svc_failed(xprt
))
1652 svc_vc_recv(SVCXPRT
*xprt
, struct rpc_msg
*msg
)
1654 /* LINTED pointer alignment */
1655 struct cf_conn
*cd
= (struct cf_conn
*)(xprt
->xp_p1
);
1656 XDR
*xdrs
= svc_xdrs
[xprt
->xp_fd
];
1658 xdrs
->x_op
= XDR_DECODE
;
1660 if (cd
->cf_conn_nonblock
) {
1661 /* Get the next input */
1662 if (!__xdrrec_getbytes_nonblock(xdrs
, &cd
->strm_stat
)) {
1664 * The entire record has not been received.
1665 * If the xprt has died, pass it along in svc_flags.
1666 * Return FALSE; For nonblocked vc connection,
1667 * xdr_callmsg() is called only after the entire
1668 * record has been received. For blocked vc
1669 * connection, the data is received on the fly as it
1670 * is being processed through the xdr routines.
1672 if (cd
->strm_stat
== XPRT_DIED
)
1673 /* LINTED pointer cast */
1674 svc_flags(xprt
) |= SVC_FAILED
;
1678 if (!xdrrec_skiprecord(xdrs
))
1680 (void) __xdrrec_setfirst(xdrs
);
1683 if (xdr_callmsg(xdrs
, msg
)) {
1684 cd
->x_id
= msg
->rm_xid
;
1689 * If a non-blocking connection, drop it when message decode fails.
1690 * We are either under attack, or we're talking to a broken client.
1692 if (cd
->cf_conn_nonblock
) {
1693 /* LINTED pointer cast */
1694 svc_flags(xprt
) |= SVC_FAILED
;
1701 svc_vc_getargs(SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
1705 /* LINTED pointer alignment */
1706 dummy
= SVCAUTH_UNWRAP(&SVC_XP_AUTH(xprt
), svc_xdrs
[xprt
->xp_fd
],
1707 xdr_args
, args_ptr
);
1708 if (svc_mt_mode
!= RPC_SVC_MT_NONE
)
1709 svc_args_done(xprt
);
1714 svc_vc_freeargs(SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
1716 /* LINTED pointer alignment */
1717 XDR
*xdrs
= &(((struct cf_conn
*)(xprt
->xp_p1
))->xdrs
);
1719 xdrs
->x_op
= XDR_FREE
;
1720 return ((*xdr_args
)(xdrs
, args_ptr
));
1724 svc_vc_reply(SVCXPRT
*xprt
, struct rpc_msg
*msg
)
1726 /* LINTED pointer alignment */
1727 struct cf_conn
*cd
= (struct cf_conn
*)(xprt
->xp_p1
);
1728 XDR
*xdrs
= &(cd
->xdrs
);
1729 bool_t stat
= FALSE
;
1730 xdrproc_t xdr_results
;
1731 caddr_t xdr_location
;
1734 if (svc_mt_mode
!= RPC_SVC_MT_NONE
)
1735 /* LINTED pointer alignment */
1736 (void) mutex_lock(&svc_send_mutex(SVCEXT(xprt
)->parent
));
1738 if (msg
->rm_reply
.rp_stat
== MSG_ACCEPTED
&&
1739 msg
->rm_reply
.rp_acpt
.ar_stat
== SUCCESS
) {
1741 xdr_results
= msg
->acpted_rply
.ar_results
.proc
;
1742 xdr_location
= msg
->acpted_rply
.ar_results
.where
;
1743 msg
->acpted_rply
.ar_results
.proc
= xdr_void
;
1744 msg
->acpted_rply
.ar_results
.where
= NULL
;
1748 xdrs
->x_op
= XDR_ENCODE
;
1749 msg
->rm_xid
= cd
->x_id
;
1750 /* LINTED pointer alignment */
1751 if (xdr_replymsg(xdrs
, msg
) && (!has_args
|| SVCAUTH_WRAP(
1752 &SVC_XP_AUTH(xprt
), xdrs
, xdr_results
, xdr_location
))) {
1755 (void) xdrrec_endofrecord(xdrs
, TRUE
);
1757 if (svc_mt_mode
!= RPC_SVC_MT_NONE
)
1758 /* LINTED pointer alignment */
1759 (void) mutex_unlock(&svc_send_mutex(SVCEXT(xprt
)->parent
));
1764 static struct xp_ops
*
1767 static struct xp_ops ops
;
1768 extern mutex_t ops_lock
;
1770 /* VARIABLES PROTECTED BY ops_lock: ops */
1772 (void) mutex_lock(&ops_lock
);
1773 if (ops
.xp_recv
== NULL
) {
1774 ops
.xp_recv
= svc_vc_recv
;
1775 ops
.xp_stat
= svc_vc_stat
;
1776 ops
.xp_getargs
= svc_vc_getargs
;
1777 ops
.xp_reply
= svc_vc_reply
;
1778 ops
.xp_freeargs
= svc_vc_freeargs
;
1779 ops
.xp_destroy
= svc_vc_destroy
;
1780 ops
.xp_control
= svc_vc_control
;
1782 (void) mutex_unlock(&ops_lock
);
1786 static struct xp_ops
*
1787 svc_vc_rendezvous_ops(void)
1789 static struct xp_ops ops
;
1790 extern mutex_t ops_lock
;
1792 (void) mutex_lock(&ops_lock
);
1793 if (ops
.xp_recv
== NULL
) {
1794 ops
.xp_recv
= rendezvous_request
;
1795 ops
.xp_stat
= rendezvous_stat
;
1796 ops
.xp_getargs
= (bool_t (*)())abort
;
1797 ops
.xp_reply
= (bool_t (*)())abort
;
1798 ops
.xp_freeargs
= (bool_t (*)())abort
;
1799 ops
.xp_destroy
= svc_vc_destroy
;
1800 ops
.xp_control
= rendezvous_control
;
1802 (void) mutex_unlock(&ops_lock
);
1807 * dup cache wrapper functions for vc requests. The set of dup
1808 * functions were written with the view that they may be expanded
1809 * during creation of a generic svc_vc_enablecache routine
1810 * which would have a size based cache, rather than a time based cache.
1811 * The real work is done in generic svc.c
1814 __svc_vc_dupcache_init(SVCXPRT
*xprt
, void *condition
, int basis
)
1816 return (__svc_dupcache_init(condition
, basis
,
1817 /* LINTED pointer alignment */
1818 &(((struct cf_rendezvous
*)xprt
->xp_p1
)->cf_cache
)));
1822 __svc_vc_dup(struct svc_req
*req
, caddr_t
*resp_buf
, uint_t
*resp_bufsz
)
1824 return (__svc_dup(req
, resp_buf
, resp_bufsz
,
1825 /* LINTED pointer alignment */
1826 ((struct cf_conn
*)req
->rq_xprt
->xp_p1
)->cf_cache
));
1830 __svc_vc_dupdone(struct svc_req
*req
, caddr_t resp_buf
, uint_t resp_bufsz
,
1833 return (__svc_dupdone(req
, resp_buf
, resp_bufsz
, status
,
1834 /* LINTED pointer alignment */
1835 ((struct cf_conn
*)req
->rq_xprt
->xp_p1
)->cf_cache
));