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