Home | History | Annotate | Download | only in librpcsoc
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     28 /*	  All Rights Reserved  	*/
     29 
     30 /*
     31  * University Copyright- Copyright (c) 1982, 1986, 1988
     32  * The Regents of the University of California
     33  * All Rights Reserved
     34  *
     35  * University Acknowledgment- Portions of this document are derived from
     36  * software developed by the University of California, Berkeley, and its
     37  * contributors.
     38  */
     39 
     40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     41 
     42 /*
     43  * svc_tcp.c, Server side for TCP/IP based RPC.
     44  *
     45  * Actually implements two flavors of transporter -
     46  * a tcp rendezvouser (a listner and connection establisher)
     47  * and a record/tcp stream.
     48  */
     49 
     50 #include <rpc/rpc.h>
     51 #include <sys/socket.h>
     52 #include <sys/time.h>
     53 #include <errno.h>
     54 #include <syslog.h>
     55 #include <malloc.h>
     56 #include <stdio.h>
     57 
     58 extern bool_t abort();
     59 extern int errno;
     60 extern SVCXPRT *svc_xprt_alloc();
     61 extern void svc_xprt_free();
     62 extern int _socket(int, int, int);
     63 extern int _bind(int, const struct sockaddr *, int);
     64 extern int _getsockname(int, struct sockaddr *, int *);
     65 extern int _listen(int, int);
     66 extern int _accept(int, struct sockaddr *, int *);
     67 extern int bindresvport(int, struct sockaddr_in *);
     68 
     69 static struct xp_ops *svctcp_ops();
     70 static struct xp_ops *svctcp_rendezvous_ops();
     71 
     72 static int readtcp(), writetcp();
     73 static SVCXPRT *makefd_xprt();
     74 
     75 struct tcp_rendezvous { /* kept in xprt->xp_p1 */
     76 	u_int sendsize;
     77 	u_int recvsize;
     78 };
     79 
     80 struct tcp_conn {  /* kept in xprt->xp_p1 */
     81 	enum xprt_stat strm_stat;
     82 	uint32_t x_id;
     83 	XDR xdrs;
     84 	char verf_body[MAX_AUTH_BYTES];
     85 };
     86 
     87 /*
     88  * Usage:
     89  *	xprt = svctcp_create(sock, send_buf_size, recv_buf_size);
     90  *
     91  * Creates, registers, and returns a (rpc) tcp based transporter.
     92  * Once *xprt is initialized, it is registered as a transporter
     93  * see (svc.h, xprt_register).  This routine returns
     94  * a NULL if a problem occurred.
     95  *
     96  * If sock<0 then a socket is created, else sock is used.
     97  * If the socket, sock is not bound to a port then svctcp_create
     98  * binds it to an arbitrary port.  The routine then starts a tcp
     99  * listener on the socket's associated port.  In any (successful) case,
    100  * xprt->xp_sock is the registered socket number and xprt->xp_port is the
    101  * associated port number.
    102  *
    103  * Since tcp streams do buffered io similar to stdio, the caller can specify
    104  * how big the send and receive buffers are via the second and third parms;
    105  * 0 => use the system default.
    106  */
    107 SVCXPRT *
    108 svctcp_create(sock, sendsize, recvsize)
    109 	register int sock;
    110 	u_int sendsize;
    111 	u_int recvsize;
    112 {
    113 	bool_t madesock = FALSE;
    114 	register SVCXPRT *xprt;
    115 	register struct tcp_rendezvous *r;
    116 	struct sockaddr_in addr;
    117 	int len = sizeof (struct sockaddr_in);
    118 
    119 	if (sock == RPC_ANYSOCK) {
    120 		if ((sock = _socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
    121 			(void) syslog(LOG_ERR, "svctcp_create - tcp",
    122 				" socket creation problem: %m");
    123 			return ((SVCXPRT *)NULL);
    124 		}
    125 		madesock = TRUE;
    126 	}
    127 	memset((char *)&addr, 0, sizeof (addr));
    128 	addr.sin_family = AF_INET;
    129 	if (bindresvport(sock, &addr)) {
    130 		addr.sin_port = 0;
    131 		(void) _bind(sock, (struct sockaddr *)&addr, len);
    132 	}
    133 	if ((_getsockname(sock, (struct sockaddr *)&addr, &len) != 0) ||
    134 	    (_listen(sock, 2) != 0)) {
    135 		(void) syslog(LOG_ERR, "svctcp_create - cannot",
    136 			" getsockname or listen: %m");
    137 		if (madesock)
    138 			(void) close(sock);
    139 		return ((SVCXPRT *)NULL);
    140 	}
    141 	r = (struct tcp_rendezvous *)mem_alloc(sizeof (*r));
    142 	if (r == NULL) {
    143 		(void) syslog(LOG_ERR, "svctcp_create: out of memory");
    144 		if (madesock)
    145 			(void) close(sock);
    146 		return (NULL);
    147 	}
    148 	r->sendsize = sendsize;
    149 	r->recvsize = recvsize;
    150 	xprt = svc_xprt_alloc();
    151 	if (xprt == NULL) {
    152 		(void) syslog(LOG_ERR, "svctcp_create: out of memory");
    153 		mem_free((char *) r, sizeof (*r));
    154 		if (madesock)
    155 			(void) close(sock);
    156 		return (NULL);
    157 	}
    158 	xprt->xp_p2 = NULL;
    159 	xprt->xp_netid = NULL;
    160 	xprt->xp_p1 = (caddr_t)r;
    161 	xprt->xp_verf = _null_auth;
    162 	xprt->xp_ops = svctcp_rendezvous_ops();
    163 	xprt->xp_port = ntohs(addr.sin_port);
    164 	xprt->xp_sock = sock;
    165 	xprt->xp_rtaddr.buf = xprt->xp_raddr;
    166 	xprt_register(xprt);
    167 	return (xprt);
    168 }
    169 
    170 /*
    171  * Like svtcp_create(), except the routine takes any *open* UNIX file
    172  * descriptor as its first input.
    173  */
    174 SVCXPRT *
    175 svcfd_create(fd, sendsize, recvsize)
    176 	int fd;
    177 	u_int sendsize;
    178 	u_int recvsize;
    179 {
    180 
    181 	return (makefd_xprt(fd, sendsize, recvsize));
    182 }
    183 
    184 static SVCXPRT *
    185 makefd_xprt(fd, sendsize, recvsize)
    186 	int fd;
    187 	u_int sendsize;
    188 	u_int recvsize;
    189 {
    190 	register SVCXPRT *xprt;
    191 	register struct tcp_conn *cd;
    192 
    193 	xprt = svc_xprt_alloc();
    194 	if (xprt == (SVCXPRT *)NULL) {
    195 		(void) syslog(LOG_ERR, "svc_tcp: makefd_xprt: out of memory");
    196 		goto done;
    197 	}
    198 	cd = (struct tcp_conn *)mem_alloc(sizeof (struct tcp_conn));
    199 	if (cd == (struct tcp_conn *)NULL) {
    200 		(void) syslog(LOG_ERR, "svc_tcp: makefd_xprt: out of memory");
    201 		svc_xprt_free(xprt);
    202 		xprt = (SVCXPRT *)NULL;
    203 		goto done;
    204 	}
    205 	cd->strm_stat = XPRT_IDLE;
    206 	xdrrec_create(&(cd->xdrs), sendsize, recvsize,
    207 	    (caddr_t)xprt, readtcp, writetcp);
    208 	xprt->xp_p2 = NULL;
    209 	xprt->xp_netid = NULL;
    210 	xprt->xp_p1 = (caddr_t)cd;
    211 	xprt->xp_verf.oa_base = cd->verf_body;
    212 	xprt->xp_addrlen = 0;
    213 	xprt->xp_ops = svctcp_ops();  /* truely deals with calls */
    214 	xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
    215 	xprt->xp_sock = fd;
    216 	/* to handle svc_getcaller() properly */
    217 	xprt->xp_rtaddr.buf = xprt->xp_raddr;
    218 	xprt_register(xprt);
    219 	done:
    220 	return (xprt);
    221 }
    222 
    223 static bool_t
    224 rendezvous_request(xprt, rpc_msg)
    225 	register SVCXPRT *xprt;
    226 	struct rpc_msg	*rpc_msg;
    227 {
    228 	int sock;
    229 	struct tcp_rendezvous *r;
    230 	struct sockaddr_in addr;
    231 	int len;
    232 
    233 	r = (struct tcp_rendezvous *)xprt->xp_p1;
    234 	again:
    235 	len = sizeof (struct sockaddr_in);
    236 	if ((sock = _accept(xprt->xp_sock, (struct sockaddr *)&addr,
    237 	    &len)) < 0) {
    238 		if (errno == EINTR)
    239 			goto again;
    240 		return (FALSE);
    241 	}
    242 	/*
    243 	 * make a new transporter (re-uses xprt)
    244 	 */
    245 	xprt = makefd_xprt(sock, r->sendsize, r->recvsize);
    246 
    247 	memcpy((char *)&xprt->xp_raddr, (char *)&addr, len);
    248 	xprt->xp_addrlen = len;
    249 	return (FALSE); /* there is never an rpc msg to be processed */
    250 }
    251 
    252 static enum xprt_stat
    253 rendezvous_stat(xprt)
    254 	SVCXPRT *xprt;
    255 {
    256 
    257 	return (XPRT_IDLE);
    258 }
    259 
    260 static void
    261 svctcp_destroy(xprt)
    262 	register SVCXPRT *xprt;
    263 {
    264 	register struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1;
    265 
    266 	xprt_unregister(xprt);
    267 	(void) close(xprt->xp_sock);
    268 	if (xprt->xp_port != 0) {
    269 		/* a rendezvouser socket */
    270 		xprt->xp_port = 0;
    271 	} else {
    272 		/* an actual connection socket */
    273 		XDR_DESTROY(&(cd->xdrs));
    274 	}
    275 	mem_free((caddr_t)cd, sizeof (struct tcp_conn));
    276 	svc_xprt_free(xprt);
    277 }
    278 
    279 /*
    280  * All read operations timeout after 35 seconds.
    281  * A timeout is fatal for the connection.
    282  */
    283 static struct timeval wait_per_try = { 35, 0 };
    284 
    285 /*
    286  * reads data from the tcp conection.
    287  * any error is fatal and the connection is closed.
    288  * (And a read of zero bytes is a half closed stream => error.)
    289  */
    290 static int
    291 readtcp(xprt, buf, len)
    292 	register SVCXPRT *xprt;
    293 	caddr_t buf;
    294 	register int len;
    295 {
    296 	register int sock = xprt->xp_sock;
    297 	fd_set mask;
    298 	fd_set readfds;
    299 
    300 	FD_ZERO(&mask);
    301 	FD_SET(sock, &mask);
    302 	do {
    303 		readfds = mask;
    304 		if (select(__rpc_dtbsize(), &readfds, NULL, NULL,
    305 			&wait_per_try) <= 0) {
    306 			if (errno == EINTR) {
    307 				continue;
    308 			}
    309 			goto fatal_err;
    310 		}
    311 	} while (!FD_ISSET(sock, &readfds));
    312 	if ((len = read(sock, buf, len)) > 0) {
    313 		return (len);
    314 	}
    315 fatal_err:
    316 	((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
    317 	return (-1);
    318 }
    319 
    320 /*
    321  * writes data to the tcp connection.
    322  * Any error is fatal and the connection is closed.
    323  */
    324 static int
    325 writetcp(xprt, buf, len)
    326 	register SVCXPRT *xprt;
    327 	caddr_t buf;
    328 	int len;
    329 {
    330 	register int i, cnt;
    331 
    332 	for (cnt = len; cnt > 0; cnt -= i, buf += i) {
    333 		if ((i = write(xprt->xp_sock, buf, cnt)) < 0) {
    334 			((struct tcp_conn *)(xprt->xp_p1))->strm_stat =
    335 			    XPRT_DIED;
    336 			return (-1);
    337 		}
    338 	}
    339 	return (len);
    340 }
    341 
    342 static enum xprt_stat
    343 svctcp_stat(xprt)
    344 	SVCXPRT *xprt;
    345 {
    346 	register struct tcp_conn *cd =
    347 	    (struct tcp_conn *)(xprt->xp_p1);
    348 
    349 	if (cd->strm_stat == XPRT_DIED)
    350 		return (XPRT_DIED);
    351 	if (! xdrrec_eof(&(cd->xdrs)))
    352 		return (XPRT_MOREREQS);
    353 	return (XPRT_IDLE);
    354 }
    355 
    356 static bool_t
    357 svctcp_recv(xprt, msg)
    358 	SVCXPRT *xprt;
    359 	register struct rpc_msg *msg;
    360 {
    361 	register struct tcp_conn *cd =
    362 	    (struct tcp_conn *)(xprt->xp_p1);
    363 	register XDR *xdrs = &(cd->xdrs);
    364 
    365 	xdrs->x_op = XDR_DECODE;
    366 	(void) xdrrec_skiprecord(xdrs);
    367 	if (xdr_callmsg(xdrs, msg)) {
    368 		cd->x_id = msg->rm_xid;
    369 		return (TRUE);
    370 	}
    371 	return (FALSE);
    372 }
    373 
    374 static bool_t
    375 svctcp_getargs(xprt, xdr_args, args_ptr)
    376 	SVCXPRT *xprt;
    377 	xdrproc_t xdr_args;
    378 	caddr_t args_ptr;
    379 {
    380 
    381 	return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs),
    382 		args_ptr));
    383 }
    384 
    385 static bool_t
    386 svctcp_freeargs(xprt, xdr_args, args_ptr)
    387 	SVCXPRT *xprt;
    388 	xdrproc_t xdr_args;
    389 	caddr_t args_ptr;
    390 {
    391 	register XDR *xdrs =
    392 	    &(((struct tcp_conn *)(xprt->xp_p1))->xdrs);
    393 
    394 	xdrs->x_op = XDR_FREE;
    395 	return ((*xdr_args)(xdrs, args_ptr));
    396 }
    397 
    398 static bool_t
    399 svctcp_reply(xprt, msg)
    400 	SVCXPRT *xprt;
    401 	register struct rpc_msg *msg;
    402 {
    403 	register struct tcp_conn *cd =
    404 	    (struct tcp_conn *)(xprt->xp_p1);
    405 	register XDR *xdrs = &(cd->xdrs);
    406 	register bool_t stat;
    407 
    408 	xdrs->x_op = XDR_ENCODE;
    409 	msg->rm_xid = cd->x_id;
    410 	stat = xdr_replymsg(xdrs, msg);
    411 	(void) xdrrec_endofrecord(xdrs, TRUE);
    412 	return (stat);
    413 }
    414 
    415 
    416 static struct xp_ops *
    417 svctcp_ops()
    418 {
    419 	static struct xp_ops ops;
    420 
    421 	if (ops.xp_recv == NULL) {
    422 		ops.xp_recv = svctcp_recv;
    423 		ops.xp_stat = svctcp_stat;
    424 		ops.xp_getargs = svctcp_getargs;
    425 		ops.xp_reply = svctcp_reply;
    426 		ops.xp_freeargs = svctcp_freeargs;
    427 		ops.xp_destroy = svctcp_destroy;
    428 	}
    429 	return (&ops);
    430 }
    431 
    432 
    433 static struct xp_ops *
    434 svctcp_rendezvous_ops()
    435 {
    436 	static struct xp_ops ops;
    437 
    438 	if (ops.xp_recv == NULL) {
    439 		ops.xp_recv = rendezvous_request;
    440 		ops.xp_stat = rendezvous_stat;
    441 		ops.xp_getargs = abort;
    442 		ops.xp_reply = abort;
    443 		ops.xp_freeargs = abort,
    444 		ops.xp_destroy = svctcp_destroy;
    445 	}
    446 	return (&ops);
    447 }
    448