xref: /csrg-svn/lib/librpc/rpc/svc_tcp.c (revision 45093)
1*45093Smckusick /* @(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC */
2*45093Smckusick /*
3*45093Smckusick  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
4*45093Smckusick  * unrestricted use provided that this legend is included on all tape
5*45093Smckusick  * media and as a part of the software program in whole or part.  Users
6*45093Smckusick  * may copy or modify Sun RPC without charge, but are not authorized
7*45093Smckusick  * to license or distribute it to anyone else except as part of a product or
8*45093Smckusick  * program developed by the user.
9*45093Smckusick  *
10*45093Smckusick  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
11*45093Smckusick  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
12*45093Smckusick  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13*45093Smckusick  *
14*45093Smckusick  * Sun RPC is provided with no support and without any obligation on the
15*45093Smckusick  * part of Sun Microsystems, Inc. to assist in its use, correction,
16*45093Smckusick  * modification or enhancement.
17*45093Smckusick  *
18*45093Smckusick  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
19*45093Smckusick  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
20*45093Smckusick  * OR ANY PART THEREOF.
21*45093Smckusick  *
22*45093Smckusick  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
23*45093Smckusick  * or profits or other special, indirect and consequential damages, even if
24*45093Smckusick  * Sun has been advised of the possibility of such damages.
25*45093Smckusick  *
26*45093Smckusick  * Sun Microsystems, Inc.
27*45093Smckusick  * 2550 Garcia Avenue
28*45093Smckusick  * Mountain View, California  94043
29*45093Smckusick  */
30*45093Smckusick #if !defined(lint) && defined(SCCSIDS)
31*45093Smckusick static char sccsid[] = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
32*45093Smckusick #endif
33*45093Smckusick 
34*45093Smckusick /*
35*45093Smckusick  * svc_tcp.c, Server side for TCP/IP based RPC.
36*45093Smckusick  *
37*45093Smckusick  * Copyright (C) 1984, Sun Microsystems, Inc.
38*45093Smckusick  *
39*45093Smckusick  * Actually implements two flavors of transporter -
40*45093Smckusick  * a tcp rendezvouser (a listner and connection establisher)
41*45093Smckusick  * and a record/tcp stream.
42*45093Smckusick  */
43*45093Smckusick 
44*45093Smckusick #include <stdio.h>
45*45093Smckusick #include <rpc/rpc.h>
46*45093Smckusick #include <sys/socket.h>
47*45093Smckusick #include <errno.h>
48*45093Smckusick extern bool_t abort();
49*45093Smckusick extern errno;
50*45093Smckusick 
51*45093Smckusick /*
52*45093Smckusick  * Ops vector for TCP/IP based rpc service handle
53*45093Smckusick  */
54*45093Smckusick static bool_t		svctcp_recv();
55*45093Smckusick static enum xprt_stat	svctcp_stat();
56*45093Smckusick static bool_t		svctcp_getargs();
57*45093Smckusick static bool_t		svctcp_reply();
58*45093Smckusick static bool_t		svctcp_freeargs();
59*45093Smckusick static void		svctcp_destroy();
60*45093Smckusick 
61*45093Smckusick static struct xp_ops svctcp_op = {
62*45093Smckusick 	svctcp_recv,
63*45093Smckusick 	svctcp_stat,
64*45093Smckusick 	svctcp_getargs,
65*45093Smckusick 	svctcp_reply,
66*45093Smckusick 	svctcp_freeargs,
67*45093Smckusick 	svctcp_destroy
68*45093Smckusick };
69*45093Smckusick 
70*45093Smckusick /*
71*45093Smckusick  * Ops vector for TCP/IP rendezvous handler
72*45093Smckusick  */
73*45093Smckusick static bool_t		rendezvous_request();
74*45093Smckusick static enum xprt_stat	rendezvous_stat();
75*45093Smckusick 
76*45093Smckusick static struct xp_ops svctcp_rendezvous_op = {
77*45093Smckusick 	rendezvous_request,
78*45093Smckusick 	rendezvous_stat,
79*45093Smckusick 	abort,
80*45093Smckusick 	abort,
81*45093Smckusick 	abort,
82*45093Smckusick 	svctcp_destroy
83*45093Smckusick };
84*45093Smckusick 
85*45093Smckusick static int readtcp(), writetcp();
86*45093Smckusick static SVCXPRT *makefd_xprt();
87*45093Smckusick 
88*45093Smckusick struct tcp_rendezvous { /* kept in xprt->xp_p1 */
89*45093Smckusick 	u_int sendsize;
90*45093Smckusick 	u_int recvsize;
91*45093Smckusick };
92*45093Smckusick 
93*45093Smckusick struct tcp_conn {  /* kept in xprt->xp_p1 */
94*45093Smckusick 	enum xprt_stat strm_stat;
95*45093Smckusick 	u_long x_id;
96*45093Smckusick 	XDR xdrs;
97*45093Smckusick 	char verf_body[MAX_AUTH_BYTES];
98*45093Smckusick };
99*45093Smckusick 
100*45093Smckusick /*
101*45093Smckusick  * Usage:
102*45093Smckusick  *	xprt = svctcp_create(sock, send_buf_size, recv_buf_size);
103*45093Smckusick  *
104*45093Smckusick  * Creates, registers, and returns a (rpc) tcp based transporter.
105*45093Smckusick  * Once *xprt is initialized, it is registered as a transporter
106*45093Smckusick  * see (svc.h, xprt_register).  This routine returns
107*45093Smckusick  * a NULL if a problem occurred.
108*45093Smckusick  *
109*45093Smckusick  * If sock<0 then a socket is created, else sock is used.
110*45093Smckusick  * If the socket, sock is not bound to a port then svctcp_create
111*45093Smckusick  * binds it to an arbitrary port.  The routine then starts a tcp
112*45093Smckusick  * listener on the socket's associated port.  In any (successful) case,
113*45093Smckusick  * xprt->xp_sock is the registered socket number and xprt->xp_port is the
114*45093Smckusick  * associated port number.
115*45093Smckusick  *
116*45093Smckusick  * Since tcp streams do buffered io similar to stdio, the caller can specify
117*45093Smckusick  * how big the send and receive buffers are via the second and third parms;
118*45093Smckusick  * 0 => use the system default.
119*45093Smckusick  */
120*45093Smckusick SVCXPRT *
121*45093Smckusick svctcp_create(sock, sendsize, recvsize)
122*45093Smckusick 	register int sock;
123*45093Smckusick 	u_int sendsize;
124*45093Smckusick 	u_int recvsize;
125*45093Smckusick {
126*45093Smckusick 	bool_t madesock = FALSE;
127*45093Smckusick 	register SVCXPRT *xprt;
128*45093Smckusick 	register struct tcp_rendezvous *r;
129*45093Smckusick 	struct sockaddr_in addr;
130*45093Smckusick 	int len = sizeof(struct sockaddr_in);
131*45093Smckusick 
132*45093Smckusick 	if (sock == RPC_ANYSOCK) {
133*45093Smckusick 		if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
134*45093Smckusick 			perror("svctcp_.c - udp socket creation problem");
135*45093Smckusick 			return ((SVCXPRT *)NULL);
136*45093Smckusick 		}
137*45093Smckusick 		madesock = TRUE;
138*45093Smckusick 	}
139*45093Smckusick 	bzero((char *)&addr, sizeof (addr));
140*45093Smckusick 	addr.sin_family = AF_INET;
141*45093Smckusick 	if (bindresvport(sock, &addr)) {
142*45093Smckusick 		addr.sin_port = 0;
143*45093Smckusick 		(void)bind(sock, (struct sockaddr *)&addr, len);
144*45093Smckusick 	}
145*45093Smckusick 	if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0)  ||
146*45093Smckusick 	    (listen(sock, 2) != 0)) {
147*45093Smckusick 		perror("svctcp_.c - cannot getsockname or listen");
148*45093Smckusick 		if (madesock)
149*45093Smckusick 		       (void)close(sock);
150*45093Smckusick 		return ((SVCXPRT *)NULL);
151*45093Smckusick 	}
152*45093Smckusick 	r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r));
153*45093Smckusick 	if (r == NULL) {
154*45093Smckusick 		(void) fprintf(stderr, "svctcp_create: out of memory\n");
155*45093Smckusick 		return (NULL);
156*45093Smckusick 	}
157*45093Smckusick 	r->sendsize = sendsize;
158*45093Smckusick 	r->recvsize = recvsize;
159*45093Smckusick 	xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
160*45093Smckusick 	if (xprt == NULL) {
161*45093Smckusick 		(void) fprintf(stderr, "svctcp_create: out of memory\n");
162*45093Smckusick 		return (NULL);
163*45093Smckusick 	}
164*45093Smckusick 	xprt->xp_p2 = NULL;
165*45093Smckusick 	xprt->xp_p1 = (caddr_t)r;
166*45093Smckusick 	xprt->xp_verf = _null_auth;
167*45093Smckusick 	xprt->xp_ops = &svctcp_rendezvous_op;
168*45093Smckusick 	xprt->xp_port = ntohs(addr.sin_port);
169*45093Smckusick 	xprt->xp_sock = sock;
170*45093Smckusick 	xprt_register(xprt);
171*45093Smckusick 	return (xprt);
172*45093Smckusick }
173*45093Smckusick 
174*45093Smckusick /*
175*45093Smckusick  * Like svtcp_create(), except the routine takes any *open* UNIX file
176*45093Smckusick  * descriptor as its first input.
177*45093Smckusick  */
178*45093Smckusick SVCXPRT *
179*45093Smckusick svcfd_create(fd, sendsize, recvsize)
180*45093Smckusick 	int fd;
181*45093Smckusick 	u_int sendsize;
182*45093Smckusick 	u_int recvsize;
183*45093Smckusick {
184*45093Smckusick 
185*45093Smckusick 	return (makefd_xprt(fd, sendsize, recvsize));
186*45093Smckusick }
187*45093Smckusick 
188*45093Smckusick static SVCXPRT *
189*45093Smckusick makefd_xprt(fd, sendsize, recvsize)
190*45093Smckusick 	int fd;
191*45093Smckusick 	u_int sendsize;
192*45093Smckusick 	u_int recvsize;
193*45093Smckusick {
194*45093Smckusick 	register SVCXPRT *xprt;
195*45093Smckusick 	register struct tcp_conn *cd;
196*45093Smckusick 
197*45093Smckusick 	xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
198*45093Smckusick 	if (xprt == (SVCXPRT *)NULL) {
199*45093Smckusick 		(void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
200*45093Smckusick 		goto done;
201*45093Smckusick 	}
202*45093Smckusick 	cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn));
203*45093Smckusick 	if (cd == (struct tcp_conn *)NULL) {
204*45093Smckusick 		(void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
205*45093Smckusick 		mem_free((char *) xprt, sizeof(SVCXPRT));
206*45093Smckusick 		xprt = (SVCXPRT *)NULL;
207*45093Smckusick 		goto done;
208*45093Smckusick 	}
209*45093Smckusick 	cd->strm_stat = XPRT_IDLE;
210*45093Smckusick 	xdrrec_create(&(cd->xdrs), sendsize, recvsize,
211*45093Smckusick 	    (caddr_t)xprt, readtcp, writetcp);
212*45093Smckusick 	xprt->xp_p2 = NULL;
213*45093Smckusick 	xprt->xp_p1 = (caddr_t)cd;
214*45093Smckusick 	xprt->xp_verf.oa_base = cd->verf_body;
215*45093Smckusick 	xprt->xp_addrlen = 0;
216*45093Smckusick 	xprt->xp_ops = &svctcp_op;  /* truely deals with calls */
217*45093Smckusick 	xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
218*45093Smckusick 	xprt->xp_sock = fd;
219*45093Smckusick 	xprt_register(xprt);
220*45093Smckusick     done:
221*45093Smckusick 	return (xprt);
222*45093Smckusick }
223*45093Smckusick 
224*45093Smckusick static bool_t
225*45093Smckusick rendezvous_request(xprt)
226*45093Smckusick 	register SVCXPRT *xprt;
227*45093Smckusick {
228*45093Smckusick 	int sock;
229*45093Smckusick 	struct tcp_rendezvous *r;
230*45093Smckusick 	struct sockaddr_in addr;
231*45093Smckusick 	int len;
232*45093Smckusick 
233*45093Smckusick 	r = (struct tcp_rendezvous *)xprt->xp_p1;
234*45093Smckusick     again:
235*45093Smckusick 	len = sizeof(struct sockaddr_in);
236*45093Smckusick 	if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr,
237*45093Smckusick 	    &len)) < 0) {
238*45093Smckusick 		if (errno == EINTR)
239*45093Smckusick 			goto again;
240*45093Smckusick 	       return (FALSE);
241*45093Smckusick 	}
242*45093Smckusick 	/*
243*45093Smckusick 	 * make a new transporter (re-uses xprt)
244*45093Smckusick 	 */
245*45093Smckusick 	xprt = makefd_xprt(sock, r->sendsize, r->recvsize);
246*45093Smckusick 	xprt->xp_raddr = addr;
247*45093Smckusick 	xprt->xp_addrlen = len;
248*45093Smckusick 	return (FALSE); /* there is never an rpc msg to be processed */
249*45093Smckusick }
250*45093Smckusick 
251*45093Smckusick static enum xprt_stat
252*45093Smckusick rendezvous_stat()
253*45093Smckusick {
254*45093Smckusick 
255*45093Smckusick 	return (XPRT_IDLE);
256*45093Smckusick }
257*45093Smckusick 
258*45093Smckusick static void
259*45093Smckusick svctcp_destroy(xprt)
260*45093Smckusick 	register SVCXPRT *xprt;
261*45093Smckusick {
262*45093Smckusick 	register struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1;
263*45093Smckusick 
264*45093Smckusick 	xprt_unregister(xprt);
265*45093Smckusick 	(void)close(xprt->xp_sock);
266*45093Smckusick 	if (xprt->xp_port != 0) {
267*45093Smckusick 		/* a rendezvouser socket */
268*45093Smckusick 		xprt->xp_port = 0;
269*45093Smckusick 	} else {
270*45093Smckusick 		/* an actual connection socket */
271*45093Smckusick 		XDR_DESTROY(&(cd->xdrs));
272*45093Smckusick 	}
273*45093Smckusick 	mem_free((caddr_t)cd, sizeof(struct tcp_conn));
274*45093Smckusick 	mem_free((caddr_t)xprt, sizeof(SVCXPRT));
275*45093Smckusick }
276*45093Smckusick 
277*45093Smckusick /*
278*45093Smckusick  * All read operations timeout after 35 seconds.
279*45093Smckusick  * A timeout is fatal for the connection.
280*45093Smckusick  */
281*45093Smckusick static struct timeval wait_per_try = { 35, 0 };
282*45093Smckusick 
283*45093Smckusick /*
284*45093Smckusick  * reads data from the tcp conection.
285*45093Smckusick  * any error is fatal and the connection is closed.
286*45093Smckusick  * (And a read of zero bytes is a half closed stream => error.)
287*45093Smckusick  */
288*45093Smckusick static int
289*45093Smckusick readtcp(xprt, buf, len)
290*45093Smckusick 	register SVCXPRT *xprt;
291*45093Smckusick 	caddr_t buf;
292*45093Smckusick 	register int len;
293*45093Smckusick {
294*45093Smckusick 	register int sock = xprt->xp_sock;
295*45093Smckusick #ifdef FD_SETSIZE
296*45093Smckusick 	fd_set mask;
297*45093Smckusick 	fd_set readfds;
298*45093Smckusick 
299*45093Smckusick 	FD_ZERO(&mask);
300*45093Smckusick 	FD_SET(sock, &mask);
301*45093Smckusick #else
302*45093Smckusick 	register int mask = 1 << sock;
303*45093Smckusick 	int readfds;
304*45093Smckusick #endif /* def FD_SETSIZE */
305*45093Smckusick 	do {
306*45093Smckusick 		readfds = mask;
307*45093Smckusick 		if (select(_rpc_dtablesize(), &readfds, (int*)NULL, (int*)NULL,
308*45093Smckusick 			   &wait_per_try) <= 0) {
309*45093Smckusick 			if (errno == EINTR) {
310*45093Smckusick 				continue;
311*45093Smckusick 			}
312*45093Smckusick 			goto fatal_err;
313*45093Smckusick 		}
314*45093Smckusick #ifdef FD_SETSIZE
315*45093Smckusick 	} while (!FD_ISSET(sock, &readfds));
316*45093Smckusick #else
317*45093Smckusick 	} while (readfds != mask);
318*45093Smckusick #endif /* def FD_SETSIZE */
319*45093Smckusick 	if ((len = read(sock, buf, len)) > 0) {
320*45093Smckusick 		return (len);
321*45093Smckusick 	}
322*45093Smckusick fatal_err:
323*45093Smckusick 	((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
324*45093Smckusick 	return (-1);
325*45093Smckusick }
326*45093Smckusick 
327*45093Smckusick /*
328*45093Smckusick  * writes data to the tcp connection.
329*45093Smckusick  * Any error is fatal and the connection is closed.
330*45093Smckusick  */
331*45093Smckusick static int
332*45093Smckusick writetcp(xprt, buf, len)
333*45093Smckusick 	register SVCXPRT *xprt;
334*45093Smckusick 	caddr_t buf;
335*45093Smckusick 	int len;
336*45093Smckusick {
337*45093Smckusick 	register int i, cnt;
338*45093Smckusick 
339*45093Smckusick 	for (cnt = len; cnt > 0; cnt -= i, buf += i) {
340*45093Smckusick 		if ((i = write(xprt->xp_sock, buf, cnt)) < 0) {
341*45093Smckusick 			((struct tcp_conn *)(xprt->xp_p1))->strm_stat =
342*45093Smckusick 			    XPRT_DIED;
343*45093Smckusick 			return (-1);
344*45093Smckusick 		}
345*45093Smckusick 	}
346*45093Smckusick 	return (len);
347*45093Smckusick }
348*45093Smckusick 
349*45093Smckusick static enum xprt_stat
350*45093Smckusick svctcp_stat(xprt)
351*45093Smckusick 	SVCXPRT *xprt;
352*45093Smckusick {
353*45093Smckusick 	register struct tcp_conn *cd =
354*45093Smckusick 	    (struct tcp_conn *)(xprt->xp_p1);
355*45093Smckusick 
356*45093Smckusick 	if (cd->strm_stat == XPRT_DIED)
357*45093Smckusick 		return (XPRT_DIED);
358*45093Smckusick 	if (! xdrrec_eof(&(cd->xdrs)))
359*45093Smckusick 		return (XPRT_MOREREQS);
360*45093Smckusick 	return (XPRT_IDLE);
361*45093Smckusick }
362*45093Smckusick 
363*45093Smckusick static bool_t
364*45093Smckusick svctcp_recv(xprt, msg)
365*45093Smckusick 	SVCXPRT *xprt;
366*45093Smckusick 	register struct rpc_msg *msg;
367*45093Smckusick {
368*45093Smckusick 	register struct tcp_conn *cd =
369*45093Smckusick 	    (struct tcp_conn *)(xprt->xp_p1);
370*45093Smckusick 	register XDR *xdrs = &(cd->xdrs);
371*45093Smckusick 
372*45093Smckusick 	xdrs->x_op = XDR_DECODE;
373*45093Smckusick 	(void)xdrrec_skiprecord(xdrs);
374*45093Smckusick 	if (xdr_callmsg(xdrs, msg)) {
375*45093Smckusick 		cd->x_id = msg->rm_xid;
376*45093Smckusick 		return (TRUE);
377*45093Smckusick 	}
378*45093Smckusick 	return (FALSE);
379*45093Smckusick }
380*45093Smckusick 
381*45093Smckusick static bool_t
382*45093Smckusick svctcp_getargs(xprt, xdr_args, args_ptr)
383*45093Smckusick 	SVCXPRT *xprt;
384*45093Smckusick 	xdrproc_t xdr_args;
385*45093Smckusick 	caddr_t args_ptr;
386*45093Smckusick {
387*45093Smckusick 
388*45093Smckusick 	return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), args_ptr));
389*45093Smckusick }
390*45093Smckusick 
391*45093Smckusick static bool_t
392*45093Smckusick svctcp_freeargs(xprt, xdr_args, args_ptr)
393*45093Smckusick 	SVCXPRT *xprt;
394*45093Smckusick 	xdrproc_t xdr_args;
395*45093Smckusick 	caddr_t args_ptr;
396*45093Smckusick {
397*45093Smckusick 	register XDR *xdrs =
398*45093Smckusick 	    &(((struct tcp_conn *)(xprt->xp_p1))->xdrs);
399*45093Smckusick 
400*45093Smckusick 	xdrs->x_op = XDR_FREE;
401*45093Smckusick 	return ((*xdr_args)(xdrs, args_ptr));
402*45093Smckusick }
403*45093Smckusick 
404*45093Smckusick static bool_t
405*45093Smckusick svctcp_reply(xprt, msg)
406*45093Smckusick 	SVCXPRT *xprt;
407*45093Smckusick 	register struct rpc_msg *msg;
408*45093Smckusick {
409*45093Smckusick 	register struct tcp_conn *cd =
410*45093Smckusick 	    (struct tcp_conn *)(xprt->xp_p1);
411*45093Smckusick 	register XDR *xdrs = &(cd->xdrs);
412*45093Smckusick 	register bool_t stat;
413*45093Smckusick 
414*45093Smckusick 	xdrs->x_op = XDR_ENCODE;
415*45093Smckusick 	msg->rm_xid = cd->x_id;
416*45093Smckusick 	stat = xdr_replymsg(xdrs, msg);
417*45093Smckusick 	(void)xdrrec_endofrecord(xdrs, TRUE);
418*45093Smckusick 	return (stat);
419*45093Smckusick }
420