xref: /csrg-svn/lib/librpc/rpc/svc_tcp.c (revision 54678)
145093Smckusick /* @(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC */
245093Smckusick /*
345093Smckusick  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
445093Smckusick  * unrestricted use provided that this legend is included on all tape
545093Smckusick  * media and as a part of the software program in whole or part.  Users
645093Smckusick  * may copy or modify Sun RPC without charge, but are not authorized
745093Smckusick  * to license or distribute it to anyone else except as part of a product or
845093Smckusick  * program developed by the user.
945093Smckusick  *
1045093Smckusick  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
1145093Smckusick  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
1245093Smckusick  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
1345093Smckusick  *
1445093Smckusick  * Sun RPC is provided with no support and without any obligation on the
1545093Smckusick  * part of Sun Microsystems, Inc. to assist in its use, correction,
1645093Smckusick  * modification or enhancement.
1745093Smckusick  *
1845093Smckusick  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
1945093Smckusick  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
2045093Smckusick  * OR ANY PART THEREOF.
2145093Smckusick  *
2245093Smckusick  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
2345093Smckusick  * or profits or other special, indirect and consequential damages, even if
2445093Smckusick  * Sun has been advised of the possibility of such damages.
2545093Smckusick  *
2645093Smckusick  * Sun Microsystems, Inc.
2745093Smckusick  * 2550 Garcia Avenue
2845093Smckusick  * Mountain View, California  94043
2945093Smckusick  */
3045093Smckusick #if !defined(lint) && defined(SCCSIDS)
3145093Smckusick static char sccsid[] = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
3245093Smckusick #endif
3345093Smckusick 
3445093Smckusick /*
3545093Smckusick  * svc_tcp.c, Server side for TCP/IP based RPC.
3645093Smckusick  *
3745093Smckusick  * Copyright (C) 1984, Sun Microsystems, Inc.
3845093Smckusick  *
3945093Smckusick  * Actually implements two flavors of transporter -
4045093Smckusick  * a tcp rendezvouser (a listner and connection establisher)
4145093Smckusick  * and a record/tcp stream.
4245093Smckusick  */
4345093Smckusick 
4445093Smckusick #include <stdio.h>
45*54678Storek #include <stdlib.h>
4645093Smckusick #include <rpc/rpc.h>
4745093Smckusick #include <sys/socket.h>
4845093Smckusick #include <errno.h>
4945093Smckusick extern errno;
5045093Smckusick 
5145093Smckusick /*
5245093Smckusick  * Ops vector for TCP/IP based rpc service handle
5345093Smckusick  */
5445093Smckusick static bool_t		svctcp_recv();
5545093Smckusick static enum xprt_stat	svctcp_stat();
5645093Smckusick static bool_t		svctcp_getargs();
5745093Smckusick static bool_t		svctcp_reply();
5845093Smckusick static bool_t		svctcp_freeargs();
5945093Smckusick static void		svctcp_destroy();
6045093Smckusick 
6145093Smckusick static struct xp_ops svctcp_op = {
6245093Smckusick 	svctcp_recv,
6345093Smckusick 	svctcp_stat,
6445093Smckusick 	svctcp_getargs,
6545093Smckusick 	svctcp_reply,
6645093Smckusick 	svctcp_freeargs,
6745093Smckusick 	svctcp_destroy
6845093Smckusick };
6945093Smckusick 
7045093Smckusick /*
7145093Smckusick  * Ops vector for TCP/IP rendezvous handler
7245093Smckusick  */
7345093Smckusick static bool_t		rendezvous_request();
7445093Smckusick static enum xprt_stat	rendezvous_stat();
7545093Smckusick 
7645093Smckusick static struct xp_ops svctcp_rendezvous_op = {
7745093Smckusick 	rendezvous_request,
7845093Smckusick 	rendezvous_stat,
79*54678Storek 	(bool_t (*)())abort,
80*54678Storek 	(bool_t (*)())abort,
81*54678Storek 	(bool_t (*)())abort,
8245093Smckusick 	svctcp_destroy
8345093Smckusick };
8445093Smckusick 
8545093Smckusick static int readtcp(), writetcp();
8645093Smckusick static SVCXPRT *makefd_xprt();
8745093Smckusick 
8845093Smckusick struct tcp_rendezvous { /* kept in xprt->xp_p1 */
8945093Smckusick 	u_int sendsize;
9045093Smckusick 	u_int recvsize;
9145093Smckusick };
9245093Smckusick 
9345093Smckusick struct tcp_conn {  /* kept in xprt->xp_p1 */
9445093Smckusick 	enum xprt_stat strm_stat;
9545093Smckusick 	u_long x_id;
9645093Smckusick 	XDR xdrs;
9745093Smckusick 	char verf_body[MAX_AUTH_BYTES];
9845093Smckusick };
9945093Smckusick 
10045093Smckusick /*
10145093Smckusick  * Usage:
10245093Smckusick  *	xprt = svctcp_create(sock, send_buf_size, recv_buf_size);
10345093Smckusick  *
10445093Smckusick  * Creates, registers, and returns a (rpc) tcp based transporter.
10545093Smckusick  * Once *xprt is initialized, it is registered as a transporter
10645093Smckusick  * see (svc.h, xprt_register).  This routine returns
10745093Smckusick  * a NULL if a problem occurred.
10845093Smckusick  *
10945093Smckusick  * If sock<0 then a socket is created, else sock is used.
11045093Smckusick  * If the socket, sock is not bound to a port then svctcp_create
11145093Smckusick  * binds it to an arbitrary port.  The routine then starts a tcp
11245093Smckusick  * listener on the socket's associated port.  In any (successful) case,
11345093Smckusick  * xprt->xp_sock is the registered socket number and xprt->xp_port is the
11445093Smckusick  * associated port number.
11545093Smckusick  *
11645093Smckusick  * Since tcp streams do buffered io similar to stdio, the caller can specify
11745093Smckusick  * how big the send and receive buffers are via the second and third parms;
11845093Smckusick  * 0 => use the system default.
11945093Smckusick  */
12045093Smckusick SVCXPRT *
svctcp_create(sock,sendsize,recvsize)12145093Smckusick svctcp_create(sock, sendsize, recvsize)
12245093Smckusick 	register int sock;
12345093Smckusick 	u_int sendsize;
12445093Smckusick 	u_int recvsize;
12545093Smckusick {
12645093Smckusick 	bool_t madesock = FALSE;
12745093Smckusick 	register SVCXPRT *xprt;
12845093Smckusick 	register struct tcp_rendezvous *r;
12945093Smckusick 	struct sockaddr_in addr;
13045093Smckusick 	int len = sizeof(struct sockaddr_in);
13145093Smckusick 
13245093Smckusick 	if (sock == RPC_ANYSOCK) {
13345093Smckusick 		if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
13445093Smckusick 			perror("svctcp_.c - udp socket creation problem");
13545093Smckusick 			return ((SVCXPRT *)NULL);
13645093Smckusick 		}
13745093Smckusick 		madesock = TRUE;
13845093Smckusick 	}
13945093Smckusick 	bzero((char *)&addr, sizeof (addr));
14045093Smckusick 	addr.sin_family = AF_INET;
14145093Smckusick 	if (bindresvport(sock, &addr)) {
14245093Smckusick 		addr.sin_port = 0;
14345093Smckusick 		(void)bind(sock, (struct sockaddr *)&addr, len);
14445093Smckusick 	}
14545093Smckusick 	if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0)  ||
14645093Smckusick 	    (listen(sock, 2) != 0)) {
14745093Smckusick 		perror("svctcp_.c - cannot getsockname or listen");
14845093Smckusick 		if (madesock)
14945093Smckusick 		       (void)close(sock);
15045093Smckusick 		return ((SVCXPRT *)NULL);
15145093Smckusick 	}
15245093Smckusick 	r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r));
15345093Smckusick 	if (r == NULL) {
15445093Smckusick 		(void) fprintf(stderr, "svctcp_create: out of memory\n");
15545093Smckusick 		return (NULL);
15645093Smckusick 	}
15745093Smckusick 	r->sendsize = sendsize;
15845093Smckusick 	r->recvsize = recvsize;
15945093Smckusick 	xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
16045093Smckusick 	if (xprt == NULL) {
16145093Smckusick 		(void) fprintf(stderr, "svctcp_create: out of memory\n");
16245093Smckusick 		return (NULL);
16345093Smckusick 	}
16445093Smckusick 	xprt->xp_p2 = NULL;
16545093Smckusick 	xprt->xp_p1 = (caddr_t)r;
16645093Smckusick 	xprt->xp_verf = _null_auth;
16745093Smckusick 	xprt->xp_ops = &svctcp_rendezvous_op;
16845093Smckusick 	xprt->xp_port = ntohs(addr.sin_port);
16945093Smckusick 	xprt->xp_sock = sock;
17045093Smckusick 	xprt_register(xprt);
17145093Smckusick 	return (xprt);
17245093Smckusick }
17345093Smckusick 
17445093Smckusick /*
17545093Smckusick  * Like svtcp_create(), except the routine takes any *open* UNIX file
17645093Smckusick  * descriptor as its first input.
17745093Smckusick  */
17845093Smckusick SVCXPRT *
svcfd_create(fd,sendsize,recvsize)17945093Smckusick svcfd_create(fd, sendsize, recvsize)
18045093Smckusick 	int fd;
18145093Smckusick 	u_int sendsize;
18245093Smckusick 	u_int recvsize;
18345093Smckusick {
18445093Smckusick 
18545093Smckusick 	return (makefd_xprt(fd, sendsize, recvsize));
18645093Smckusick }
18745093Smckusick 
18845093Smckusick static SVCXPRT *
makefd_xprt(fd,sendsize,recvsize)18945093Smckusick makefd_xprt(fd, sendsize, recvsize)
19045093Smckusick 	int fd;
19145093Smckusick 	u_int sendsize;
19245093Smckusick 	u_int recvsize;
19345093Smckusick {
19445093Smckusick 	register SVCXPRT *xprt;
19545093Smckusick 	register struct tcp_conn *cd;
19645093Smckusick 
19745093Smckusick 	xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
19845093Smckusick 	if (xprt == (SVCXPRT *)NULL) {
19945093Smckusick 		(void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
20045093Smckusick 		goto done;
20145093Smckusick 	}
20245093Smckusick 	cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn));
20345093Smckusick 	if (cd == (struct tcp_conn *)NULL) {
20445093Smckusick 		(void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
20545093Smckusick 		mem_free((char *) xprt, sizeof(SVCXPRT));
20645093Smckusick 		xprt = (SVCXPRT *)NULL;
20745093Smckusick 		goto done;
20845093Smckusick 	}
20945093Smckusick 	cd->strm_stat = XPRT_IDLE;
21045093Smckusick 	xdrrec_create(&(cd->xdrs), sendsize, recvsize,
21145093Smckusick 	    (caddr_t)xprt, readtcp, writetcp);
21245093Smckusick 	xprt->xp_p2 = NULL;
21345093Smckusick 	xprt->xp_p1 = (caddr_t)cd;
21445093Smckusick 	xprt->xp_verf.oa_base = cd->verf_body;
21545093Smckusick 	xprt->xp_addrlen = 0;
21645093Smckusick 	xprt->xp_ops = &svctcp_op;  /* truely deals with calls */
21745093Smckusick 	xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
21845093Smckusick 	xprt->xp_sock = fd;
21945093Smckusick 	xprt_register(xprt);
22045093Smckusick     done:
22145093Smckusick 	return (xprt);
22245093Smckusick }
22345093Smckusick 
22445093Smckusick static bool_t
rendezvous_request(xprt)22545093Smckusick rendezvous_request(xprt)
22645093Smckusick 	register SVCXPRT *xprt;
22745093Smckusick {
22845093Smckusick 	int sock;
22945093Smckusick 	struct tcp_rendezvous *r;
23045093Smckusick 	struct sockaddr_in addr;
23145093Smckusick 	int len;
23245093Smckusick 
23345093Smckusick 	r = (struct tcp_rendezvous *)xprt->xp_p1;
23445093Smckusick     again:
23545093Smckusick 	len = sizeof(struct sockaddr_in);
23645093Smckusick 	if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr,
23745093Smckusick 	    &len)) < 0) {
23845093Smckusick 		if (errno == EINTR)
23945093Smckusick 			goto again;
24045093Smckusick 	       return (FALSE);
24145093Smckusick 	}
24245093Smckusick 	/*
24345093Smckusick 	 * make a new transporter (re-uses xprt)
24445093Smckusick 	 */
24545093Smckusick 	xprt = makefd_xprt(sock, r->sendsize, r->recvsize);
24645093Smckusick 	xprt->xp_raddr = addr;
24745093Smckusick 	xprt->xp_addrlen = len;
24845093Smckusick 	return (FALSE); /* there is never an rpc msg to be processed */
24945093Smckusick }
25045093Smckusick 
25145093Smckusick static enum xprt_stat
rendezvous_stat()25245093Smckusick rendezvous_stat()
25345093Smckusick {
25445093Smckusick 
25545093Smckusick 	return (XPRT_IDLE);
25645093Smckusick }
25745093Smckusick 
25845093Smckusick static void
svctcp_destroy(xprt)25945093Smckusick svctcp_destroy(xprt)
26045093Smckusick 	register SVCXPRT *xprt;
26145093Smckusick {
26245093Smckusick 	register struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1;
26345093Smckusick 
26445093Smckusick 	xprt_unregister(xprt);
26545093Smckusick 	(void)close(xprt->xp_sock);
26645093Smckusick 	if (xprt->xp_port != 0) {
26745093Smckusick 		/* a rendezvouser socket */
26845093Smckusick 		xprt->xp_port = 0;
26945093Smckusick 	} else {
27045093Smckusick 		/* an actual connection socket */
27145093Smckusick 		XDR_DESTROY(&(cd->xdrs));
27245093Smckusick 	}
27345093Smckusick 	mem_free((caddr_t)cd, sizeof(struct tcp_conn));
27445093Smckusick 	mem_free((caddr_t)xprt, sizeof(SVCXPRT));
27545093Smckusick }
27645093Smckusick 
27745093Smckusick /*
27845093Smckusick  * All read operations timeout after 35 seconds.
27945093Smckusick  * A timeout is fatal for the connection.
28045093Smckusick  */
28145093Smckusick static struct timeval wait_per_try = { 35, 0 };
28245093Smckusick 
28345093Smckusick /*
28445093Smckusick  * reads data from the tcp conection.
28545093Smckusick  * any error is fatal and the connection is closed.
28645093Smckusick  * (And a read of zero bytes is a half closed stream => error.)
28745093Smckusick  */
28845093Smckusick static int
readtcp(xprt,buf,len)28945093Smckusick readtcp(xprt, buf, len)
29045093Smckusick 	register SVCXPRT *xprt;
29145093Smckusick 	caddr_t buf;
29245093Smckusick 	register int len;
29345093Smckusick {
29445093Smckusick 	register int sock = xprt->xp_sock;
29545093Smckusick #ifdef FD_SETSIZE
29645093Smckusick 	fd_set mask;
29745093Smckusick 	fd_set readfds;
29845093Smckusick 
29945093Smckusick 	FD_ZERO(&mask);
30045093Smckusick 	FD_SET(sock, &mask);
30145093Smckusick #else
30245093Smckusick 	register int mask = 1 << sock;
30345093Smckusick 	int readfds;
30445093Smckusick #endif /* def FD_SETSIZE */
30545093Smckusick 	do {
30645093Smckusick 		readfds = mask;
30745093Smckusick 		if (select(_rpc_dtablesize(), &readfds, (int*)NULL, (int*)NULL,
30845093Smckusick 			   &wait_per_try) <= 0) {
30945093Smckusick 			if (errno == EINTR) {
31045093Smckusick 				continue;
31145093Smckusick 			}
31245093Smckusick 			goto fatal_err;
31345093Smckusick 		}
31445093Smckusick #ifdef FD_SETSIZE
31545093Smckusick 	} while (!FD_ISSET(sock, &readfds));
31645093Smckusick #else
31745093Smckusick 	} while (readfds != mask);
31845093Smckusick #endif /* def FD_SETSIZE */
31945093Smckusick 	if ((len = read(sock, buf, len)) > 0) {
32045093Smckusick 		return (len);
32145093Smckusick 	}
32245093Smckusick fatal_err:
32345093Smckusick 	((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
32445093Smckusick 	return (-1);
32545093Smckusick }
32645093Smckusick 
32745093Smckusick /*
32845093Smckusick  * writes data to the tcp connection.
32945093Smckusick  * Any error is fatal and the connection is closed.
33045093Smckusick  */
33145093Smckusick static int
writetcp(xprt,buf,len)33245093Smckusick writetcp(xprt, buf, len)
33345093Smckusick 	register SVCXPRT *xprt;
33445093Smckusick 	caddr_t buf;
33545093Smckusick 	int len;
33645093Smckusick {
33745093Smckusick 	register int i, cnt;
33845093Smckusick 
33945093Smckusick 	for (cnt = len; cnt > 0; cnt -= i, buf += i) {
34045093Smckusick 		if ((i = write(xprt->xp_sock, buf, cnt)) < 0) {
34145093Smckusick 			((struct tcp_conn *)(xprt->xp_p1))->strm_stat =
34245093Smckusick 			    XPRT_DIED;
34345093Smckusick 			return (-1);
34445093Smckusick 		}
34545093Smckusick 	}
34645093Smckusick 	return (len);
34745093Smckusick }
34845093Smckusick 
34945093Smckusick static enum xprt_stat
svctcp_stat(xprt)35045093Smckusick svctcp_stat(xprt)
35145093Smckusick 	SVCXPRT *xprt;
35245093Smckusick {
35345093Smckusick 	register struct tcp_conn *cd =
35445093Smckusick 	    (struct tcp_conn *)(xprt->xp_p1);
35545093Smckusick 
35645093Smckusick 	if (cd->strm_stat == XPRT_DIED)
35745093Smckusick 		return (XPRT_DIED);
35845093Smckusick 	if (! xdrrec_eof(&(cd->xdrs)))
35945093Smckusick 		return (XPRT_MOREREQS);
36045093Smckusick 	return (XPRT_IDLE);
36145093Smckusick }
36245093Smckusick 
36345093Smckusick static bool_t
svctcp_recv(xprt,msg)36445093Smckusick svctcp_recv(xprt, msg)
36545093Smckusick 	SVCXPRT *xprt;
36645093Smckusick 	register struct rpc_msg *msg;
36745093Smckusick {
36845093Smckusick 	register struct tcp_conn *cd =
36945093Smckusick 	    (struct tcp_conn *)(xprt->xp_p1);
37045093Smckusick 	register XDR *xdrs = &(cd->xdrs);
37145093Smckusick 
37245093Smckusick 	xdrs->x_op = XDR_DECODE;
37345093Smckusick 	(void)xdrrec_skiprecord(xdrs);
37445093Smckusick 	if (xdr_callmsg(xdrs, msg)) {
37545093Smckusick 		cd->x_id = msg->rm_xid;
37645093Smckusick 		return (TRUE);
37745093Smckusick 	}
37845093Smckusick 	return (FALSE);
37945093Smckusick }
38045093Smckusick 
38145093Smckusick static bool_t
svctcp_getargs(xprt,xdr_args,args_ptr)38245093Smckusick svctcp_getargs(xprt, xdr_args, args_ptr)
38345093Smckusick 	SVCXPRT *xprt;
38445093Smckusick 	xdrproc_t xdr_args;
38545093Smckusick 	caddr_t args_ptr;
38645093Smckusick {
38745093Smckusick 
38845093Smckusick 	return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), args_ptr));
38945093Smckusick }
39045093Smckusick 
39145093Smckusick static bool_t
svctcp_freeargs(xprt,xdr_args,args_ptr)39245093Smckusick svctcp_freeargs(xprt, xdr_args, args_ptr)
39345093Smckusick 	SVCXPRT *xprt;
39445093Smckusick 	xdrproc_t xdr_args;
39545093Smckusick 	caddr_t args_ptr;
39645093Smckusick {
39745093Smckusick 	register XDR *xdrs =
39845093Smckusick 	    &(((struct tcp_conn *)(xprt->xp_p1))->xdrs);
39945093Smckusick 
40045093Smckusick 	xdrs->x_op = XDR_FREE;
40145093Smckusick 	return ((*xdr_args)(xdrs, args_ptr));
40245093Smckusick }
40345093Smckusick 
40445093Smckusick static bool_t
svctcp_reply(xprt,msg)40545093Smckusick svctcp_reply(xprt, msg)
40645093Smckusick 	SVCXPRT *xprt;
40745093Smckusick 	register struct rpc_msg *msg;
40845093Smckusick {
40945093Smckusick 	register struct tcp_conn *cd =
41045093Smckusick 	    (struct tcp_conn *)(xprt->xp_p1);
41145093Smckusick 	register XDR *xdrs = &(cd->xdrs);
41245093Smckusick 	register bool_t stat;
41345093Smckusick 
41445093Smckusick 	xdrs->x_op = XDR_ENCODE;
41545093Smckusick 	msg->rm_xid = cd->x_id;
41645093Smckusick 	stat = xdr_replymsg(xdrs, msg);
41745093Smckusick 	(void)xdrrec_endofrecord(xdrs, TRUE);
41845093Smckusick 	return (stat);
41945093Smckusick }
420