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 $
36 * svc_vc.c, Server side for Connection Oriented based RPC.
38 * Actually implements two flavors of transporter -
39 * a tcp rendezvouser (a listner and connection establisher)
40 * and a record/tcp stream.
43 #include "namespace.h"
44 #include "reentrant.h"
45 #include <sys/types.h>
46 #include <sys/param.h>
48 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <netinet/tcp.h>
68 #include "un-namespace.h"
70 static SVCXPRT
*makefd_xprt(int, u_int
, u_int
);
71 static bool_t
rendezvous_request(SVCXPRT
*, struct rpc_msg
*);
72 static enum xprt_stat
rendezvous_stat(SVCXPRT
*);
73 static void svc_vc_destroy(SVCXPRT
*);
74 static void __svc_vc_dodestroy (SVCXPRT
*);
75 static int read_vc(void *, void *, int);
76 static int write_vc(void *, void *, int);
77 static enum xprt_stat
svc_vc_stat(SVCXPRT
*);
78 static bool_t
svc_vc_recv(SVCXPRT
*, struct rpc_msg
*);
79 static bool_t
svc_vc_getargs(SVCXPRT
*, xdrproc_t
, void *);
80 static bool_t
svc_vc_freeargs(SVCXPRT
*, xdrproc_t
, void *);
81 static bool_t
svc_vc_reply(SVCXPRT
*, struct rpc_msg
*);
82 static void svc_vc_rendezvous_ops(SVCXPRT
*);
83 static void svc_vc_ops(SVCXPRT
*);
84 static bool_t
svc_vc_control(SVCXPRT
*xprt
, const u_int rq
, void *in
);
85 static bool_t
svc_vc_rendezvous_control(SVCXPRT
*xprt
, const u_int rq
,
88 struct cf_rendezvous
{ /* kept in xprt->xp_p1 for rendezvouser */
94 struct cf_conn
{ /* kept in xprt->xp_p1 for actual connection */
95 enum xprt_stat strm_stat
;
98 char verf_body
[MAX_AUTH_BYTES
];
103 struct timeval last_recv_time
;
108 * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
110 * Creates, registers, and returns a (rpc) tcp based transporter.
111 * Once *xprt is initialized, it is registered as a transporter
112 * see (svc.h, xprt_register). This routine returns
113 * a NULL if a problem occurred.
115 * The filedescriptor passed in is expected to refer to a bound, but
116 * not yet connected socket.
118 * Since streams do buffered io similar to stdio, the caller can specify
119 * how big the send and receive buffers are via the second and third parms;
120 * 0 => use the system default.
123 svc_vc_create(int fd
, u_int sendsize
, u_int recvsize
)
126 struct cf_rendezvous
*r
= NULL
;
127 struct __rpc_sockinfo si
;
128 struct sockaddr_storage sslocal
;
131 if (!__rpc_fd2sockinfo(fd
, &si
))
134 r
= mem_alloc(sizeof(*r
));
136 warnx("svc_vc_create: out of memory");
137 goto cleanup_svc_vc_create
;
139 r
->sendsize
= __rpc_get_t_size(si
.si_af
, si
.si_proto
, (int)sendsize
);
140 r
->recvsize
= __rpc_get_t_size(si
.si_af
, si
.si_proto
, (int)recvsize
);
141 r
->maxrec
= __svc_maxrec
;
142 xprt
= mem_alloc(sizeof(SVCXPRT
));
144 warnx("svc_vc_create: out of memory");
145 goto cleanup_svc_vc_create
;
151 xprt
->xp_verf
= _null_auth
;
152 svc_vc_rendezvous_ops(xprt
);
153 xprt
->xp_port
= (u_short
)-1; /* It is the rendezvouser */
156 slen
= sizeof (struct sockaddr_storage
);
157 if (_getsockname(fd
, (struct sockaddr
*)(void *)&sslocal
, &slen
) < 0) {
158 warnx("svc_vc_create: could not retrieve local addr");
159 goto cleanup_svc_vc_create
;
162 xprt
->xp_ltaddr
.maxlen
= xprt
->xp_ltaddr
.len
= sslocal
.ss_len
;
163 xprt
->xp_ltaddr
.buf
= mem_alloc((size_t)sslocal
.ss_len
);
164 if (xprt
->xp_ltaddr
.buf
== NULL
) {
165 warnx("svc_vc_create: no mem for local addr");
166 goto cleanup_svc_vc_create
;
168 memcpy(xprt
->xp_ltaddr
.buf
, &sslocal
, (size_t)sslocal
.ss_len
);
170 xprt
->xp_rtaddr
.maxlen
= sizeof (struct sockaddr_storage
);
173 cleanup_svc_vc_create
:
175 mem_free(xprt
, sizeof(*xprt
));
177 mem_free(r
, sizeof(*r
));
182 * Like svtcp_create(), except the routine takes any *open* UNIX file
183 * descriptor as its first input.
186 svc_fd_create(int fd
, u_int sendsize
, u_int recvsize
)
188 struct sockaddr_storage ss
;
194 ret
= makefd_xprt(fd
, sendsize
, recvsize
);
198 slen
= sizeof (struct sockaddr_storage
);
199 if (_getsockname(fd
, (struct sockaddr
*)(void *)&ss
, &slen
) < 0) {
200 warnx("svc_fd_create: could not retrieve local addr");
203 ret
->xp_ltaddr
.maxlen
= ret
->xp_ltaddr
.len
= ss
.ss_len
;
204 ret
->xp_ltaddr
.buf
= mem_alloc((size_t)ss
.ss_len
);
205 if (ret
->xp_ltaddr
.buf
== NULL
) {
206 warnx("svc_fd_create: no mem for local addr");
209 memcpy(ret
->xp_ltaddr
.buf
, &ss
, (size_t)ss
.ss_len
);
211 slen
= sizeof (struct sockaddr_storage
);
212 if (_getpeername(fd
, (struct sockaddr
*)(void *)&ss
, &slen
) < 0) {
213 warnx("svc_fd_create: could not retrieve remote addr");
216 ret
->xp_rtaddr
.maxlen
= ret
->xp_rtaddr
.len
= ss
.ss_len
;
217 ret
->xp_rtaddr
.buf
= mem_alloc((size_t)ss
.ss_len
);
218 if (ret
->xp_rtaddr
.buf
== NULL
) {
219 warnx("svc_fd_create: no mem for local addr");
222 memcpy(ret
->xp_rtaddr
.buf
, &ss
, (size_t)ss
.ss_len
);
224 if (ss
.ss_family
== AF_INET
|| ss
.ss_family
== AF_LOCAL
) {
225 ret
->xp_raddr
= *(struct sockaddr_in
*)ret
->xp_rtaddr
.buf
;
226 ret
->xp_addrlen
= sizeof (struct sockaddr_in
);
233 if (ret
->xp_ltaddr
.buf
!= NULL
)
234 mem_free(ret
->xp_ltaddr
.buf
, rep
->xp_ltaddr
.maxlen
);
240 makefd_xprt(int fd
, u_int sendsize
, u_int recvsize
)
245 struct __rpc_sockinfo si
;
249 xprt
= mem_alloc(sizeof(SVCXPRT
));
251 warnx("svc_vc: makefd_xprt: out of memory");
254 memset(xprt
, 0, sizeof *xprt
);
255 cd
= mem_alloc(sizeof(struct cf_conn
));
257 warnx("svc_tcp: makefd_xprt: out of memory");
258 mem_free(xprt
, sizeof(SVCXPRT
));
262 cd
->strm_stat
= XPRT_IDLE
;
263 xdrrec_create(&(cd
->xdrs
), sendsize
, recvsize
,
264 xprt
, read_vc
, write_vc
);
266 xprt
->xp_verf
.oa_base
= cd
->verf_body
;
267 svc_vc_ops(xprt
); /* truely deals with calls */
268 xprt
->xp_port
= 0; /* this is a connection, not a rendezvouser */
270 if (__rpc_fd2sockinfo(fd
, &si
) && __rpc_sockinfo2netid(&si
, &netid
))
271 xprt
->xp_netid
= strdup(netid
);
280 rendezvous_request(SVCXPRT
*xprt
, struct rpc_msg
*msg
)
283 struct cf_rendezvous
*r
;
285 struct sockaddr_storage addr
;
287 struct __rpc_sockinfo si
;
291 assert(xprt
!= NULL
);
294 r
= (struct cf_rendezvous
*)xprt
->xp_p1
;
297 if ((sock
= _accept(xprt
->xp_fd
, (struct sockaddr
*)(void *)&addr
,
302 * Clean out the most idle file descriptor when we're
305 if (errno
== EMFILE
|| errno
== ENFILE
) {
306 cleanfds
= svc_fdset
;
307 __svc_clean_idle(&cleanfds
, 0, FALSE
);
313 * make a new transporter (re-uses xprt)
315 newxprt
= makefd_xprt(sock
, r
->sendsize
, r
->recvsize
);
316 newxprt
->xp_rtaddr
.buf
= mem_alloc(len
);
317 if (newxprt
->xp_rtaddr
.buf
== NULL
)
319 memcpy(newxprt
->xp_rtaddr
.buf
, &addr
, len
);
320 newxprt
->xp_rtaddr
.len
= len
;
322 if (addr
.ss_family
== AF_INET
|| addr
.ss_family
== AF_LOCAL
) {
323 newxprt
->xp_raddr
= *(struct sockaddr_in
*)newxprt
->xp_rtaddr
.buf
;
324 newxprt
->xp_addrlen
= sizeof (struct sockaddr_in
);
327 if (__rpc_fd2sockinfo(sock
, &si
) && si
.si_proto
== IPPROTO_TCP
) {
329 /* XXX fvdl - is this useful? */
330 _setsockopt(sock
, IPPROTO_TCP
, TCP_NODELAY
, &len
, sizeof (len
));
333 cd
= (struct cf_conn
*)newxprt
->xp_p1
;
335 cd
->recvsize
= r
->recvsize
;
336 cd
->sendsize
= r
->sendsize
;
337 cd
->maxrec
= r
->maxrec
;
339 if (cd
->maxrec
!= 0) {
340 flags
= _fcntl(sock
, F_GETFL
, 0);
343 if (_fcntl(sock
, F_SETFL
, flags
| O_NONBLOCK
) == -1)
345 if (cd
->recvsize
> cd
->maxrec
)
346 cd
->recvsize
= cd
->maxrec
;
348 __xdrrec_setnonblock(&cd
->xdrs
, cd
->maxrec
);
350 cd
->nonblock
= FALSE
;
352 gettimeofday(&cd
->last_recv_time
, NULL
);
354 return (FALSE
); /* there is never an rpc msg to be processed */
358 static enum xprt_stat
359 rendezvous_stat(SVCXPRT
*xprt
)
366 svc_vc_destroy(SVCXPRT
*xprt
)
368 assert(xprt
!= NULL
);
370 xprt_unregister(xprt
);
371 __svc_vc_dodestroy(xprt
);
375 __svc_vc_dodestroy(SVCXPRT
*xprt
)
378 struct cf_rendezvous
*r
;
380 cd
= (struct cf_conn
*)xprt
->xp_p1
;
382 if (xprt
->xp_fd
!= RPC_ANYFD
)
384 if (xprt
->xp_port
!= 0) {
385 /* a rendezvouser socket */
386 r
= (struct cf_rendezvous
*)xprt
->xp_p1
;
387 mem_free(r
, sizeof (struct cf_rendezvous
));
390 /* an actual connection socket */
391 XDR_DESTROY(&(cd
->xdrs
));
392 mem_free(cd
, sizeof(struct cf_conn
));
394 if (xprt
->xp_rtaddr
.buf
)
395 mem_free(xprt
->xp_rtaddr
.buf
, xprt
->xp_rtaddr
.maxlen
);
396 if (xprt
->xp_ltaddr
.buf
)
397 mem_free(xprt
->xp_ltaddr
.buf
, xprt
->xp_ltaddr
.maxlen
);
401 free(xprt
->xp_netid
);
402 mem_free(xprt
, sizeof(SVCXPRT
));
407 svc_vc_control(SVCXPRT
*xprt
, const u_int rq
, void *in
)
413 svc_vc_rendezvous_control(SVCXPRT
*xprt
, const u_int rq
, void *in
)
415 struct cf_rendezvous
*cfp
;
417 cfp
= (struct cf_rendezvous
*)xprt
->xp_p1
;
421 case SVCGET_CONNMAXREC
:
422 *(int *)in
= cfp
->maxrec
;
424 case SVCSET_CONNMAXREC
:
425 cfp
->maxrec
= *(int *)in
;
434 * reads data from the tcp or uip connection.
435 * any error is fatal and the connection is closed.
436 * (And a read of zero bytes is a half closed stream => error.)
437 * All read operations timeout after 35 seconds. A timeout is
438 * fatal for the connection.
441 read_vc(void *xprtp
, void *buf
, int len
)
445 int milliseconds
= 35 * 1000;
446 struct pollfd pollfd
;
449 xprt
= (SVCXPRT
*)xprtp
;
450 assert(xprt
!= NULL
);
454 cfp
= (struct cf_conn
*)xprt
->xp_p1
;
457 len
= _read(sock
, buf
, (size_t)len
);
465 gettimeofday(&cfp
->last_recv_time
, NULL
);
471 pollfd
.events
= POLLIN
;
473 switch (_poll(&pollfd
, 1, milliseconds
)) {
484 } while ((pollfd
.revents
& POLLIN
) == 0);
486 if ((len
= _read(sock
, buf
, (size_t)len
)) > 0) {
487 gettimeofday(&cfp
->last_recv_time
, NULL
);
492 ((struct cf_conn
*)(xprt
->xp_p1
))->strm_stat
= XPRT_DIED
;
497 * writes data to the tcp connection.
498 * Any error is fatal and the connection is closed.
501 write_vc(void *xprtp
, void *buf
, int len
)
506 struct timeval tv0
, tv1
;
508 xprt
= (SVCXPRT
*)xprtp
;
509 assert(xprt
!= NULL
);
511 cd
= (struct cf_conn
*)xprt
->xp_p1
;
514 gettimeofday(&tv0
, NULL
);
516 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
= (char *)buf
+ i
) {
517 i
= _write(xprt
->xp_fd
, buf
, (size_t)cnt
);
519 if (errno
!= EAGAIN
|| !cd
->nonblock
) {
520 cd
->strm_stat
= XPRT_DIED
;
523 if (cd
->nonblock
&& i
!= cnt
) {
525 * For non-blocking connections, do not
526 * take more than 2 seconds writing the
529 * XXX 2 is an arbitrary amount.
531 gettimeofday(&tv1
, NULL
);
532 if (tv1
.tv_sec
- tv0
.tv_sec
>= 2) {
533 cd
->strm_stat
= XPRT_DIED
;
543 static enum xprt_stat
544 svc_vc_stat(SVCXPRT
*xprt
)
548 assert(xprt
!= NULL
);
550 cd
= (struct cf_conn
*)(xprt
->xp_p1
);
552 if (cd
->strm_stat
== XPRT_DIED
)
554 if (! xdrrec_eof(&(cd
->xdrs
)))
555 return (XPRT_MOREREQS
);
560 svc_vc_recv(SVCXPRT
*xprt
, struct rpc_msg
*msg
)
565 assert(xprt
!= NULL
);
568 cd
= (struct cf_conn
*)(xprt
->xp_p1
);
572 if (!__xdrrec_getrec(xdrs
, &cd
->strm_stat
, TRUE
))
575 xdrrec_skiprecord(xdrs
);
578 xdrs
->x_op
= XDR_DECODE
;
579 if (xdr_callmsg(xdrs
, msg
)) {
580 cd
->x_id
= msg
->rm_xid
;
583 cd
->strm_stat
= XPRT_DIED
;
588 svc_vc_getargs(SVCXPRT
*xprt
, xdrproc_t xdr_args
, void *args_ptr
)
591 assert(xprt
!= NULL
);
592 /* args_ptr may be NULL */
593 return ((*xdr_args
)(&(((struct cf_conn
*)(xprt
->xp_p1
))->xdrs
),
598 svc_vc_freeargs(SVCXPRT
*xprt
, xdrproc_t xdr_args
, void *args_ptr
)
602 assert(xprt
!= NULL
);
603 /* args_ptr may be NULL */
605 xdrs
= &(((struct cf_conn
*)(xprt
->xp_p1
))->xdrs
);
607 xdrs
->x_op
= XDR_FREE
;
608 return ((*xdr_args
)(xdrs
, args_ptr
));
612 svc_vc_reply(SVCXPRT
*xprt
, struct rpc_msg
*msg
)
618 assert(xprt
!= NULL
);
621 cd
= (struct cf_conn
*)(xprt
->xp_p1
);
624 xdrs
->x_op
= XDR_ENCODE
;
625 msg
->rm_xid
= cd
->x_id
;
626 rstat
= xdr_replymsg(xdrs
, msg
);
627 xdrrec_endofrecord(xdrs
, TRUE
);
632 svc_vc_ops(SVCXPRT
*xprt
)
634 static struct xp_ops ops
;
635 static struct xp_ops2 ops2
;
637 /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */
639 mutex_lock(&ops_lock
);
640 if (ops
.xp_recv
== NULL
) {
641 ops
.xp_recv
= svc_vc_recv
;
642 ops
.xp_stat
= svc_vc_stat
;
643 ops
.xp_getargs
= svc_vc_getargs
;
644 ops
.xp_reply
= svc_vc_reply
;
645 ops
.xp_freeargs
= svc_vc_freeargs
;
646 ops
.xp_destroy
= svc_vc_destroy
;
647 ops2
.xp_control
= svc_vc_control
;
650 xprt
->xp_ops2
= &ops2
;
651 mutex_unlock(&ops_lock
);
655 svc_vc_rendezvous_ops(SVCXPRT
*xprt
)
657 static struct xp_ops ops
;
658 static struct xp_ops2 ops2
;
660 mutex_lock(&ops_lock
);
661 if (ops
.xp_recv
== NULL
) {
662 ops
.xp_recv
= rendezvous_request
;
663 ops
.xp_stat
= rendezvous_stat
;
665 (bool_t (*)(SVCXPRT
*, xdrproc_t
, void *))abort
;
667 (bool_t (*)(SVCXPRT
*, struct rpc_msg
*))abort
;
669 (bool_t (*)(SVCXPRT
*, xdrproc_t
, void *))abort
,
670 ops
.xp_destroy
= svc_vc_destroy
;
671 ops2
.xp_control
= svc_vc_rendezvous_control
;
674 xprt
->xp_ops2
= &ops2
;
675 mutex_unlock(&ops_lock
);
679 * Get the effective UID of the sending process. Used by rpcbind, keyserv
680 * and rpc.yppasswdd on AF_LOCAL.
683 __rpc_get_local_uid(SVCXPRT
*transp
, uid_t
*uid
)
690 sock
= transp
->xp_fd
;
691 sa
= (struct sockaddr
*)transp
->xp_rtaddr
.buf
;
692 if (sa
->sa_family
== AF_LOCAL
) {
693 ret
= getpeereid(sock
, &euid
, &egid
);
702 * Destroy xprts that have not have had any activity in 'timeout' seconds.
703 * If 'cleanblock' is true, blocking connections (the default) are also
704 * cleaned. If timeout is 0, the least active connection is picked.
707 __svc_clean_idle(fd_set
*fds
, int timeout
, bool_t cleanblock
)
710 SVCXPRT
*xprt
, *least_active
;
711 struct timeval tv
, tdiff
, tmax
;
714 gettimeofday(&tv
, NULL
);
715 tmax
.tv_sec
= tmax
.tv_usec
= 0;
717 rwlock_wrlock(&svc_fd_lock
);
718 for (i
= ncleaned
= 0; i
<= svc_maxfd
; i
++) {
719 if (FD_ISSET(i
, fds
)) {
720 xprt
= __svc_xports
[i
];
721 if (xprt
== NULL
|| xprt
->xp_ops
== NULL
||
722 xprt
->xp_ops
->xp_recv
!= svc_vc_recv
)
724 cd
= (struct cf_conn
*)xprt
->xp_p1
;
725 if (!cleanblock
&& !cd
->nonblock
)
728 timersub(&tv
, &cd
->last_recv_time
, &tdiff
);
729 if (timercmp(&tdiff
, &tmax
, >)) {
735 if (tv
.tv_sec
- cd
->last_recv_time
.tv_sec
> timeout
) {
736 __xprt_unregister_unlocked(xprt
);
737 __svc_vc_dodestroy(xprt
);
742 if (timeout
== 0 && least_active
!= NULL
) {
743 __xprt_unregister_unlocked(least_active
);
744 __svc_vc_dodestroy(least_active
);
747 rwlock_unlock(&svc_fd_lock
);
748 return ncleaned
> 0 ? TRUE
: FALSE
;