2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3 * unrestricted use provided that this legend is included on all tape
4 * media and as a part of the software program in whole or part. Users
5 * may copy or modify Sun RPC without charge, but are not authorized
6 * to license or distribute it to anyone else except as part of a product or
7 * program developed by the user.
9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13 * Sun RPC is provided with no support and without any obligation on the
14 * part of Sun Microsystems, Inc. to assist in its use, correction,
15 * modification or enhancement.
17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19 * OR ANY PART THEREOF.
21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22 * or profits or other special, indirect and consequential damages, even if
23 * Sun has been advised of the possibility of such damages.
25 * Sun Microsystems, Inc.
27 * Mountain View, California 94043
29 * @(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro
30 * @(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC
31 * $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $
32 * $FreeBSD: src/lib/libc/rpc/svc_vc.c,v 1.27 2008/03/30 09:36:17 dfr Exp $
37 * svc_vc.c, Server side for Connection Oriented based RPC.
39 * Actually implements two flavors of transporter -
40 * a tcp rendezvouser (a listner and connection establisher)
41 * and a record/tcp stream.
44 #include "namespace.h"
45 #include "reentrant.h"
46 #include <sys/types.h>
47 #include <sys/param.h>
49 #include <sys/socket.h>
53 #include <netinet/in.h>
54 #include <netinet/tcp.h>
69 #include "un-namespace.h"
71 static SVCXPRT
*makefd_xprt(int, u_int
, u_int
);
72 static bool_t
rendezvous_request(SVCXPRT
*, struct rpc_msg
*);
73 static enum xprt_stat
rendezvous_stat(SVCXPRT
*);
74 static void svc_vc_destroy(SVCXPRT
*);
75 static void __svc_vc_dodestroy (SVCXPRT
*);
76 static int read_vc(void *, void *, int);
77 static int write_vc(void *, void *, int);
78 static enum xprt_stat
svc_vc_stat(SVCXPRT
*);
79 static bool_t
svc_vc_recv(SVCXPRT
*, struct rpc_msg
*);
80 static bool_t
svc_vc_getargs(SVCXPRT
*, xdrproc_t
, void *);
81 static bool_t
svc_vc_freeargs(SVCXPRT
*, xdrproc_t
, void *);
82 static bool_t
svc_vc_reply(SVCXPRT
*, struct rpc_msg
*);
83 static void svc_vc_rendezvous_ops(SVCXPRT
*);
84 static void svc_vc_ops(SVCXPRT
*);
85 static bool_t
svc_vc_control(SVCXPRT
*xprt
, const u_int rq
, void *in
);
86 static bool_t
svc_vc_rendezvous_control(SVCXPRT
*xprt
, const u_int rq
,
89 struct cf_rendezvous
{ /* kept in xprt->xp_p1 for rendezvouser */
95 struct cf_conn
{ /* kept in xprt->xp_p1 for actual connection */
96 enum xprt_stat strm_stat
;
99 char verf_body
[MAX_AUTH_BYTES
];
104 struct timeval last_recv_time
;
109 * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
111 * Creates, registers, and returns a (rpc) tcp based transporter.
112 * Once *xprt is initialized, it is registered as a transporter
113 * see (svc.h, xprt_register). This routine returns
114 * a NULL if a problem occurred.
116 * The filedescriptor passed in is expected to refer to a bound, but
117 * not yet connected socket.
119 * Since streams do buffered io similar to stdio, the caller can specify
120 * how big the send and receive buffers are via the second and third parms;
121 * 0 => use the system default.
124 svc_vc_create(int fd
, u_int sendsize
, u_int recvsize
)
127 struct cf_rendezvous
*r
= NULL
;
128 struct __rpc_sockinfo si
;
129 struct sockaddr_storage sslocal
;
132 if (!__rpc_fd2sockinfo(fd
, &si
))
135 r
= mem_alloc(sizeof(*r
));
137 warnx("svc_vc_create: out of memory");
138 goto cleanup_svc_vc_create
;
140 r
->sendsize
= __rpc_get_t_size(si
.si_af
, si
.si_proto
, (int)sendsize
);
141 r
->recvsize
= __rpc_get_t_size(si
.si_af
, si
.si_proto
, (int)recvsize
);
142 r
->maxrec
= __svc_maxrec
;
143 xprt
= mem_alloc(sizeof(SVCXPRT
));
145 warnx("svc_vc_create: out of memory");
146 goto cleanup_svc_vc_create
;
152 xprt
->xp_verf
= _null_auth
;
153 svc_vc_rendezvous_ops(xprt
);
154 xprt
->xp_port
= (u_short
)-1; /* It is the rendezvouser */
157 slen
= sizeof (struct sockaddr_storage
);
158 if (_getsockname(fd
, (struct sockaddr
*)(void *)&sslocal
, &slen
) < 0) {
159 warnx("svc_vc_create: could not retrieve local addr");
160 goto cleanup_svc_vc_create
;
163 xprt
->xp_ltaddr
.maxlen
= xprt
->xp_ltaddr
.len
= sslocal
.ss_len
;
164 xprt
->xp_ltaddr
.buf
= mem_alloc((size_t)sslocal
.ss_len
);
165 if (xprt
->xp_ltaddr
.buf
== NULL
) {
166 warnx("svc_vc_create: no mem for local addr");
167 goto cleanup_svc_vc_create
;
169 memcpy(xprt
->xp_ltaddr
.buf
, &sslocal
, (size_t)sslocal
.ss_len
);
171 xprt
->xp_rtaddr
.maxlen
= sizeof (struct sockaddr_storage
);
174 cleanup_svc_vc_create
:
176 mem_free(xprt
, sizeof(*xprt
));
178 mem_free(r
, sizeof(*r
));
183 * Like svtcp_create(), except the routine takes any *open* UNIX file
184 * descriptor as its first input.
187 svc_fd_create(int fd
, u_int sendsize
, u_int recvsize
)
189 struct sockaddr_storage ss
;
195 ret
= makefd_xprt(fd
, sendsize
, recvsize
);
199 slen
= sizeof (struct sockaddr_storage
);
200 if (_getsockname(fd
, (struct sockaddr
*)(void *)&ss
, &slen
) < 0) {
201 warnx("svc_fd_create: could not retrieve local addr");
204 ret
->xp_ltaddr
.maxlen
= ret
->xp_ltaddr
.len
= ss
.ss_len
;
205 ret
->xp_ltaddr
.buf
= mem_alloc((size_t)ss
.ss_len
);
206 if (ret
->xp_ltaddr
.buf
== NULL
) {
207 warnx("svc_fd_create: no mem for local addr");
210 memcpy(ret
->xp_ltaddr
.buf
, &ss
, (size_t)ss
.ss_len
);
212 slen
= sizeof (struct sockaddr_storage
);
213 if (_getpeername(fd
, (struct sockaddr
*)(void *)&ss
, &slen
) < 0) {
214 warnx("svc_fd_create: could not retrieve remote addr");
217 ret
->xp_rtaddr
.maxlen
= ret
->xp_rtaddr
.len
= ss
.ss_len
;
218 ret
->xp_rtaddr
.buf
= mem_alloc((size_t)ss
.ss_len
);
219 if (ret
->xp_rtaddr
.buf
== NULL
) {
220 warnx("svc_fd_create: no mem for local addr");
223 memcpy(ret
->xp_rtaddr
.buf
, &ss
, (size_t)ss
.ss_len
);
225 if (ss
.ss_family
== AF_INET
|| ss
.ss_family
== AF_LOCAL
) {
226 ret
->xp_raddr
= *(struct sockaddr_in
*)ret
->xp_rtaddr
.buf
;
227 ret
->xp_addrlen
= sizeof (struct sockaddr_in
);
234 if (ret
->xp_ltaddr
.buf
!= NULL
)
235 mem_free(ret
->xp_ltaddr
.buf
, rep
->xp_ltaddr
.maxlen
);
241 makefd_xprt(int fd
, u_int sendsize
, u_int recvsize
)
246 struct __rpc_sockinfo si
;
250 xprt
= mem_alloc(sizeof(SVCXPRT
));
252 warnx("svc_vc: makefd_xprt: out of memory");
255 memset(xprt
, 0, sizeof *xprt
);
256 cd
= mem_alloc(sizeof(struct cf_conn
));
258 warnx("svc_tcp: makefd_xprt: out of memory");
259 mem_free(xprt
, sizeof(SVCXPRT
));
263 cd
->strm_stat
= XPRT_IDLE
;
264 xdrrec_create(&(cd
->xdrs
), sendsize
, recvsize
,
265 xprt
, read_vc
, write_vc
);
267 xprt
->xp_verf
.oa_base
= cd
->verf_body
;
268 svc_vc_ops(xprt
); /* truely deals with calls */
269 xprt
->xp_port
= 0; /* this is a connection, not a rendezvouser */
271 if (__rpc_fd2sockinfo(fd
, &si
) && __rpc_sockinfo2netid(&si
, &netid
))
272 xprt
->xp_netid
= strdup(netid
);
281 rendezvous_request(SVCXPRT
*xprt
, struct rpc_msg
*msg
)
284 struct cf_rendezvous
*r
;
286 struct sockaddr_storage addr
;
288 struct __rpc_sockinfo si
;
292 assert(xprt
!= NULL
);
295 r
= (struct cf_rendezvous
*)xprt
->xp_p1
;
298 if ((sock
= _accept(xprt
->xp_fd
, (struct sockaddr
*)(void *)&addr
,
303 * Clean out the most idle file descriptor when we're
306 if (errno
== EMFILE
|| errno
== ENFILE
) {
307 cleanfds
= svc_fdset
;
308 __svc_clean_idle(&cleanfds
, 0, FALSE
);
314 * make a new transporter (re-uses xprt)
316 newxprt
= makefd_xprt(sock
, r
->sendsize
, r
->recvsize
);
317 newxprt
->xp_rtaddr
.buf
= mem_alloc(len
);
318 if (newxprt
->xp_rtaddr
.buf
== NULL
)
320 memcpy(newxprt
->xp_rtaddr
.buf
, &addr
, len
);
321 newxprt
->xp_rtaddr
.len
= len
;
323 if (addr
.ss_family
== AF_INET
|| addr
.ss_family
== AF_LOCAL
) {
324 newxprt
->xp_raddr
= *(struct sockaddr_in
*)newxprt
->xp_rtaddr
.buf
;
325 newxprt
->xp_addrlen
= sizeof (struct sockaddr_in
);
328 if (__rpc_fd2sockinfo(sock
, &si
) && si
.si_proto
== IPPROTO_TCP
) {
330 /* XXX fvdl - is this useful? */
331 _setsockopt(sock
, IPPROTO_TCP
, TCP_NODELAY
, &len
, sizeof (len
));
334 cd
= (struct cf_conn
*)newxprt
->xp_p1
;
336 cd
->recvsize
= r
->recvsize
;
337 cd
->sendsize
= r
->sendsize
;
338 cd
->maxrec
= r
->maxrec
;
340 if (cd
->maxrec
!= 0) {
341 flags
= _fcntl(sock
, F_GETFL
, 0);
344 if (_fcntl(sock
, F_SETFL
, flags
| O_NONBLOCK
) == -1)
346 if (cd
->recvsize
> cd
->maxrec
)
347 cd
->recvsize
= cd
->maxrec
;
349 __xdrrec_setnonblock(&cd
->xdrs
, cd
->maxrec
);
351 cd
->nonblock
= FALSE
;
353 gettimeofday(&cd
->last_recv_time
, NULL
);
355 return (FALSE
); /* there is never an rpc msg to be processed */
359 static enum xprt_stat
360 rendezvous_stat(SVCXPRT
*xprt
)
367 svc_vc_destroy(SVCXPRT
*xprt
)
369 assert(xprt
!= NULL
);
371 xprt_unregister(xprt
);
372 __svc_vc_dodestroy(xprt
);
376 __svc_vc_dodestroy(SVCXPRT
*xprt
)
379 struct cf_rendezvous
*r
;
381 cd
= (struct cf_conn
*)xprt
->xp_p1
;
383 if (xprt
->xp_fd
!= RPC_ANYFD
)
385 if (xprt
->xp_port
!= 0) {
386 /* a rendezvouser socket */
387 r
= (struct cf_rendezvous
*)xprt
->xp_p1
;
388 mem_free(r
, sizeof (struct cf_rendezvous
));
391 /* an actual connection socket */
392 XDR_DESTROY(&(cd
->xdrs
));
393 mem_free(cd
, sizeof(struct cf_conn
));
395 if (xprt
->xp_rtaddr
.buf
)
396 mem_free(xprt
->xp_rtaddr
.buf
, xprt
->xp_rtaddr
.maxlen
);
397 if (xprt
->xp_ltaddr
.buf
)
398 mem_free(xprt
->xp_ltaddr
.buf
, xprt
->xp_ltaddr
.maxlen
);
402 free(xprt
->xp_netid
);
403 mem_free(xprt
, sizeof(SVCXPRT
));
408 svc_vc_control(SVCXPRT
*xprt
, const u_int rq
, void *in
)
414 svc_vc_rendezvous_control(SVCXPRT
*xprt
, const u_int rq
, void *in
)
416 struct cf_rendezvous
*cfp
;
418 cfp
= (struct cf_rendezvous
*)xprt
->xp_p1
;
422 case SVCGET_CONNMAXREC
:
423 *(int *)in
= cfp
->maxrec
;
425 case SVCSET_CONNMAXREC
:
426 cfp
->maxrec
= *(int *)in
;
435 * reads data from the tcp or uip connection.
436 * any error is fatal and the connection is closed.
437 * (And a read of zero bytes is a half closed stream => error.)
438 * All read operations timeout after 35 seconds. A timeout is
439 * fatal for the connection.
442 read_vc(void *xprtp
, void *buf
, int len
)
446 int milliseconds
= 35 * 1000;
447 struct pollfd pollfd
;
450 xprt
= (SVCXPRT
*)xprtp
;
451 assert(xprt
!= NULL
);
455 cfp
= (struct cf_conn
*)xprt
->xp_p1
;
458 len
= _read(sock
, buf
, (size_t)len
);
466 gettimeofday(&cfp
->last_recv_time
, NULL
);
472 pollfd
.events
= POLLIN
;
474 switch (_poll(&pollfd
, 1, milliseconds
)) {
485 } while ((pollfd
.revents
& POLLIN
) == 0);
487 if ((len
= _read(sock
, buf
, (size_t)len
)) > 0) {
488 gettimeofday(&cfp
->last_recv_time
, NULL
);
493 ((struct cf_conn
*)(xprt
->xp_p1
))->strm_stat
= XPRT_DIED
;
498 * writes data to the tcp connection.
499 * Any error is fatal and the connection is closed.
502 write_vc(void *xprtp
, void *buf
, int len
)
507 struct timeval tv0
, tv1
;
509 xprt
= (SVCXPRT
*)xprtp
;
510 assert(xprt
!= NULL
);
512 cd
= (struct cf_conn
*)xprt
->xp_p1
;
515 gettimeofday(&tv0
, NULL
);
517 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
= (char *)buf
+ i
) {
518 i
= _write(xprt
->xp_fd
, buf
, (size_t)cnt
);
520 if (errno
!= EAGAIN
|| !cd
->nonblock
) {
521 cd
->strm_stat
= XPRT_DIED
;
524 if (cd
->nonblock
&& i
!= cnt
) {
526 * For non-blocking connections, do not
527 * take more than 2 seconds writing the
530 * XXX 2 is an arbitrary amount.
532 gettimeofday(&tv1
, NULL
);
533 if (tv1
.tv_sec
- tv0
.tv_sec
>= 2) {
534 cd
->strm_stat
= XPRT_DIED
;
544 static enum xprt_stat
545 svc_vc_stat(SVCXPRT
*xprt
)
549 assert(xprt
!= NULL
);
551 cd
= (struct cf_conn
*)(xprt
->xp_p1
);
553 if (cd
->strm_stat
== XPRT_DIED
)
555 if (! xdrrec_eof(&(cd
->xdrs
)))
556 return (XPRT_MOREREQS
);
561 svc_vc_recv(SVCXPRT
*xprt
, struct rpc_msg
*msg
)
566 assert(xprt
!= NULL
);
569 cd
= (struct cf_conn
*)(xprt
->xp_p1
);
573 if (!__xdrrec_getrec(xdrs
, &cd
->strm_stat
, TRUE
))
576 xdrrec_skiprecord(xdrs
);
579 xdrs
->x_op
= XDR_DECODE
;
580 if (xdr_callmsg(xdrs
, msg
)) {
581 cd
->x_id
= msg
->rm_xid
;
584 cd
->strm_stat
= XPRT_DIED
;
589 svc_vc_getargs(SVCXPRT
*xprt
, xdrproc_t xdr_args
, void *args_ptr
)
592 assert(xprt
!= NULL
);
593 /* args_ptr may be NULL */
594 return ((*xdr_args
)(&(((struct cf_conn
*)(xprt
->xp_p1
))->xdrs
),
599 svc_vc_freeargs(SVCXPRT
*xprt
, xdrproc_t xdr_args
, void *args_ptr
)
603 assert(xprt
!= NULL
);
604 /* args_ptr may be NULL */
606 xdrs
= &(((struct cf_conn
*)(xprt
->xp_p1
))->xdrs
);
608 xdrs
->x_op
= XDR_FREE
;
609 return ((*xdr_args
)(xdrs
, args_ptr
));
613 svc_vc_reply(SVCXPRT
*xprt
, struct rpc_msg
*msg
)
619 assert(xprt
!= NULL
);
622 cd
= (struct cf_conn
*)(xprt
->xp_p1
);
625 xdrs
->x_op
= XDR_ENCODE
;
626 msg
->rm_xid
= cd
->x_id
;
627 rstat
= xdr_replymsg(xdrs
, msg
);
628 xdrrec_endofrecord(xdrs
, TRUE
);
633 svc_vc_ops(SVCXPRT
*xprt
)
635 static struct xp_ops ops
;
636 static struct xp_ops2 ops2
;
638 /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */
640 mutex_lock(&ops_lock
);
641 if (ops
.xp_recv
== NULL
) {
642 ops
.xp_recv
= svc_vc_recv
;
643 ops
.xp_stat
= svc_vc_stat
;
644 ops
.xp_getargs
= svc_vc_getargs
;
645 ops
.xp_reply
= svc_vc_reply
;
646 ops
.xp_freeargs
= svc_vc_freeargs
;
647 ops
.xp_destroy
= svc_vc_destroy
;
648 ops2
.xp_control
= svc_vc_control
;
651 xprt
->xp_ops2
= &ops2
;
652 mutex_unlock(&ops_lock
);
656 svc_vc_rendezvous_ops(SVCXPRT
*xprt
)
658 static struct xp_ops ops
;
659 static struct xp_ops2 ops2
;
661 mutex_lock(&ops_lock
);
662 if (ops
.xp_recv
== NULL
) {
663 ops
.xp_recv
= rendezvous_request
;
664 ops
.xp_stat
= rendezvous_stat
;
666 (bool_t (*)(SVCXPRT
*, xdrproc_t
, void *))abort
;
668 (bool_t (*)(SVCXPRT
*, struct rpc_msg
*))abort
;
670 (bool_t (*)(SVCXPRT
*, xdrproc_t
, void *))abort
,
671 ops
.xp_destroy
= svc_vc_destroy
;
672 ops2
.xp_control
= svc_vc_rendezvous_control
;
675 xprt
->xp_ops2
= &ops2
;
676 mutex_unlock(&ops_lock
);
680 * Get the effective UID of the sending process. Used by rpcbind, keyserv
681 * and rpc.yppasswdd on AF_LOCAL.
684 __rpc_get_local_uid(SVCXPRT
*transp
, uid_t
*uid
)
691 sock
= transp
->xp_fd
;
692 sa
= (struct sockaddr
*)transp
->xp_rtaddr
.buf
;
693 if (sa
->sa_family
== AF_LOCAL
) {
694 ret
= getpeereid(sock
, &euid
, &egid
);
703 * Destroy xprts that have not have had any activity in 'timeout' seconds.
704 * If 'cleanblock' is true, blocking connections (the default) are also
705 * cleaned. If timeout is 0, the least active connection is picked.
708 __svc_clean_idle(fd_set
*fds
, int timeout
, bool_t cleanblock
)
711 SVCXPRT
*xprt
, *least_active
;
712 struct timeval tv
, tdiff
, tmax
;
715 gettimeofday(&tv
, NULL
);
716 tmax
.tv_sec
= tmax
.tv_usec
= 0;
718 rwlock_wrlock(&svc_fd_lock
);
719 for (i
= ncleaned
= 0; i
<= svc_maxfd
; i
++) {
720 if (FD_ISSET(i
, fds
)) {
721 xprt
= __svc_xports
[i
];
722 if (xprt
== NULL
|| xprt
->xp_ops
== NULL
||
723 xprt
->xp_ops
->xp_recv
!= svc_vc_recv
)
725 cd
= (struct cf_conn
*)xprt
->xp_p1
;
726 if (!cleanblock
&& !cd
->nonblock
)
729 timersub(&tv
, &cd
->last_recv_time
, &tdiff
);
730 if (timercmp(&tdiff
, &tmax
, >)) {
736 if (tv
.tv_sec
- cd
->last_recv_time
.tv_sec
> timeout
) {
737 __xprt_unregister_unlocked(xprt
);
738 __svc_vc_dodestroy(xprt
);
743 if (timeout
== 0 && least_active
!= NULL
) {
744 __xprt_unregister_unlocked(least_active
);
745 __svc_vc_dodestroy(least_active
);
748 rwlock_unlock(&svc_fd_lock
);
749 return ncleaned
> 0 ? TRUE
: FALSE
;