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 1990 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * Copyright (c) 1984, 1986, 1987, 1988, 1989, 1996 AT&T
     29  * All Rights Reserved
     30  */
     31 
     32 /*
     33  * University Copyright- Copyright (c) 1982, 1986, 1988
     34  * The Regents of the University of California
     35  * All Rights Reserved
     36  *
     37  * University Acknowledgment- Portions of this document are derived from
     38  * software developed by the University of California, Berkeley, and its
     39  * contributors.
     40  */
     41 
     42 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     43 
     44 /*
     45  * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
     46  *
     47  * TCP based RPC supports 'batched calls'.
     48  * A sequence of calls may be batched-up in a send buffer.  The rpc call
     49  * return immediately to the client even though the call was not necessarily
     50  * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
     51  * the rpc timeout value is zero (see clnt.h, rpc).
     52  *
     53  * Clients should NOT casually batch calls that in fact return results; that is,
     54  * the server side should be aware that a call is batched and not produce any
     55  * return message.  Batched calls that produce many result messages can
     56  * deadlock (netlock) the client and the server....
     57  *
     58  * Now go hang yourself.
     59  */
     60 
     61 #include <rpc/rpc.h>
     62 #include <sys/socket.h>
     63 #include <sys/time.h>
     64 #include <netdb.h>
     65 #include <errno.h>
     66 #include <rpc/pmap_clnt.h>
     67 #include <syslog.h>
     68 #include <malloc.h>
     69 #include <stdio.h>
     70 
     71 #define	MCALL_MSG_SIZE 24
     72 
     73 extern int errno;
     74 
     75 static int	readtcp();
     76 static int	writetcp();
     77 extern int _socket(int, int, int);
     78 extern pid_t getpid();
     79 extern int bindresvport(int, struct sockaddr_in *);
     80 extern bool_t   xdr_opaque_auth(XDR *, struct opaque_auth *);
     81 static struct clnt_ops *clnttcp_ops();
     82 
     83 struct ct_data {
     84 	int		ct_sock;
     85 	bool_t		ct_closeit;
     86 	struct timeval	ct_wait;
     87 	bool_t		ct_waitset;	/* wait set by clnt_control? */
     88 	struct sockaddr_in ct_addr;
     89 	struct rpc_err	ct_error;
     90 	char		ct_mcall[MCALL_MSG_SIZE];	/* marshalled callmsg */
     91 	u_int		ct_mpos;			/* pos after marshal */
     92 	XDR		ct_xdrs;
     93 };
     94 
     95 /*
     96  * Create a client handle for a tcp/ip connection.
     97  * If *sockp<0, *sockp is set to a newly created TCP socket and it is
     98  * connected to raddr.  If *sockp non-negative then
     99  * raddr is ignored.  The rpc/tcp package does buffering
    100  * similar to stdio, so the client must pick send and receive buffer sizes
    101  * 0 => use the default.
    102  * If raddr->sin_port is 0, then a binder on the remote machine is
    103  * consulted for the right port number.
    104  * NB: *sockp is copied into a private area.
    105  * NB: It is the clients responsibility to close *sockp.
    106  * NB: The rpch->cl_auth is set null authentication.  Caller may wish to
    107  * set this something more useful.
    108  */
    109 CLIENT *
    110 clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz)
    111 	struct sockaddr_in *raddr;
    112 	rpcprog_t prog;
    113 	rpcvers_t vers;
    114 	register int *sockp;
    115 	u_int sendsz;
    116 	u_int recvsz;
    117 {
    118 	CLIENT *h;
    119 	register struct ct_data *ct;
    120 	struct timeval now;
    121 	struct rpc_msg call_msg;
    122 	int i;
    123 
    124 	h  = (CLIENT *)mem_alloc(sizeof (*h));
    125 	if (h == NULL) {
    126 		(void) syslog(LOG_ERR, "clnttcp_create: out of memory");
    127 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
    128 		rpc_createerr.cf_error.re_errno = errno;
    129 		goto fooy;
    130 	}
    131 	ct = (struct ct_data *)mem_alloc(sizeof (*ct));
    132 	if (ct == NULL) {
    133 		(void) syslog(LOG_ERR, "clnttcp_create: out of memory");
    134 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
    135 		rpc_createerr.cf_error.re_errno = errno;
    136 		goto fooy;
    137 	}
    138 
    139 	/*
    140 	 * If no port number given ask the pmap for one
    141 	 */
    142 	if (raddr->sin_port == 0) {
    143 		u_short port;
    144 		if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP))
    145 		    == 0) {
    146 			mem_free((caddr_t)ct, sizeof (struct ct_data));
    147 			mem_free((caddr_t)h, sizeof (CLIENT));
    148 			return ((CLIENT *)NULL);
    149 		}
    150 		raddr->sin_port = htons(port);
    151 	}
    152 
    153 	/*
    154 	 * If no socket given, open one
    155 	 */
    156 	if (*sockp < 0) {
    157 		*sockp = _socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    158 		i = bindresvport(*sockp, (struct sockaddr_in *)0);
    159 		if ((*sockp < 0)||
    160 			(connect(*sockp, (struct sockaddr *)raddr,
    161 			sizeof (*raddr)) < 0)) {
    162 			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
    163 			rpc_createerr.cf_error.re_errno = errno;
    164 			(void) close(*sockp);
    165 			goto fooy;
    166 		}
    167 		ct->ct_closeit = TRUE;
    168 	} else {
    169 		ct->ct_closeit = FALSE;
    170 	}
    171 
    172 	/*
    173 	 * Set up private data struct
    174 	 */
    175 	ct->ct_sock = *sockp;
    176 	ct->ct_wait.tv_usec = 0;
    177 	ct->ct_waitset = FALSE;
    178 	ct->ct_addr = *raddr;
    179 
    180 	/*
    181 	 * Initialize call message
    182 	 */
    183 	(void) gettimeofday(&now, (struct timezone *)0);
    184 	call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
    185 	call_msg.rm_direction = CALL;
    186 	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
    187 	call_msg.rm_call.cb_prog = prog;
    188 	call_msg.rm_call.cb_vers = vers;
    189 
    190 	/*
    191 	 * pre-serialize the staic part of the call msg and stash it away
    192 	 */
    193 	xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
    194 	    XDR_ENCODE);
    195 	if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
    196 		if (ct->ct_closeit) {
    197 			(void) close(*sockp);
    198 		}
    199 		goto fooy;
    200 	}
    201 	ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
    202 	XDR_DESTROY(&(ct->ct_xdrs));
    203 
    204 	/*
    205 	 * Create a client handle which uses xdrrec for serialization
    206 	 * and authnone for authentication.
    207 	 */
    208 	xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
    209 	    (caddr_t)ct, readtcp, writetcp);
    210 	h->cl_ops = clnttcp_ops();
    211 	h->cl_private = (caddr_t) ct;
    212 	h->cl_auth = authnone_create();
    213 	return (h);
    214 
    215 fooy:
    216 	/*
    217 	 * Something goofed, free stuff and barf
    218 	 */
    219 	mem_free((caddr_t)ct, sizeof (struct ct_data));
    220 	mem_free((caddr_t)h, sizeof (CLIENT));
    221 	return ((CLIENT *)NULL);
    222 }
    223 
    224 static enum clnt_stat
    225 clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
    226 	register CLIENT *h;
    227 	rpcproc_t proc;
    228 	xdrproc_t xdr_args;
    229 	caddr_t args_ptr;
    230 	xdrproc_t xdr_results;
    231 	caddr_t results_ptr;
    232 	struct timeval timeout;
    233 {
    234 	register struct ct_data *ct = (struct ct_data *) h->cl_private;
    235 	register XDR *xdrs = &(ct->ct_xdrs);
    236 	struct rpc_msg reply_msg;
    237 	uint32_t x_id;
    238 	uint32_t *msg_x_id = (uint32_t *)(ct->ct_mcall);	/* yuk */
    239 	register bool_t shipnow;
    240 	int refreshes = 2;
    241 
    242 	if (!ct->ct_waitset) {
    243 		ct->ct_wait = timeout;
    244 	}
    245 
    246 	shipnow =
    247 	    (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 &&
    248 	    timeout.tv_usec == 0) ? FALSE : TRUE;
    249 
    250 call_again:
    251 	xdrs->x_op = XDR_ENCODE;
    252 	ct->ct_error.re_status = RPC_SUCCESS;
    253 	x_id = ntohl(--(*msg_x_id));
    254 	if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
    255 	    (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
    256 	    (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
    257 	    (! (*xdr_args)(xdrs, args_ptr))) {
    258 		if (ct->ct_error.re_status == RPC_SUCCESS)
    259 			ct->ct_error.re_status = RPC_CANTENCODEARGS;
    260 		(void) xdrrec_endofrecord(xdrs, TRUE);
    261 		return (ct->ct_error.re_status);
    262 	}
    263 	if (! xdrrec_endofrecord(xdrs, shipnow))
    264 		return (ct->ct_error.re_status = RPC_CANTSEND);
    265 	if (! shipnow)
    266 		return (RPC_SUCCESS);
    267 	/*
    268 	 * Hack to provide rpc-based message passing
    269 	 */
    270 	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
    271 		return (ct->ct_error.re_status = RPC_TIMEDOUT);
    272 	}
    273 
    274 
    275 	/*
    276 	 * Keep receiving until we get a valid transaction id
    277 	 */
    278 	xdrs->x_op = XDR_DECODE;
    279 	while (TRUE) {
    280 		reply_msg.acpted_rply.ar_verf = _null_auth;
    281 		reply_msg.acpted_rply.ar_results.where = NULL;
    282 		reply_msg.acpted_rply.ar_results.proc = xdr_void;
    283 		if (! xdrrec_skiprecord(xdrs))
    284 			return (ct->ct_error.re_status);
    285 			/* now decode and validate the response header */
    286 		if (! xdr_replymsg(xdrs, &reply_msg)) {
    287 			if (ct->ct_error.re_status == RPC_SUCCESS)
    288 				continue;
    289 			return (ct->ct_error.re_status);
    290 		}
    291 		if (reply_msg.rm_xid == x_id)
    292 			break;
    293 	}
    294 
    295 	/*
    296 	 * process header
    297 	 */
    298 	__seterr_reply(&reply_msg, &(ct->ct_error));
    299 	if (ct->ct_error.re_status == RPC_SUCCESS) {
    300 		if (! AUTH_VALIDATE(h->cl_auth,
    301 		    &reply_msg.acpted_rply.ar_verf)) {
    302 			ct->ct_error.re_status = RPC_AUTHERROR;
    303 			ct->ct_error.re_why = AUTH_INVALIDRESP;
    304 		} else if (! (*xdr_results)(xdrs, results_ptr)) {
    305 			if (ct->ct_error.re_status == RPC_SUCCESS)
    306 				ct->ct_error.re_status = RPC_CANTDECODERES;
    307 		}
    308 		/* free verifier ... */
    309 		if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
    310 			xdrs->x_op = XDR_FREE;
    311 			(void) xdr_opaque_auth(xdrs,
    312 			    &(reply_msg.acpted_rply.ar_verf));
    313 		}
    314 	}  /* end successful completion */
    315 	else {
    316 		/* maybe our credentials need to be refreshed ... */
    317 		if (refreshes-- && AUTH_REFRESH(h->cl_auth, &reply_msg))
    318 			goto call_again;
    319 	}  /* end of unsuccessful completion */
    320 	return (ct->ct_error.re_status);
    321 }
    322 
    323 static void
    324 clnttcp_geterr(h, errp)
    325 	CLIENT *h;
    326 	struct rpc_err *errp;
    327 {
    328 	register struct ct_data *ct =
    329 	    (struct ct_data *) h->cl_private;
    330 
    331 	*errp = ct->ct_error;
    332 }
    333 
    334 static bool_t
    335 clnttcp_freeres(cl, xdr_res, res_ptr)
    336 	CLIENT *cl;
    337 	xdrproc_t xdr_res;
    338 	caddr_t res_ptr;
    339 {
    340 	register struct ct_data *ct = (struct ct_data *)cl->cl_private;
    341 	register XDR *xdrs = &(ct->ct_xdrs);
    342 
    343 	xdrs->x_op = XDR_FREE;
    344 	return ((*xdr_res)(xdrs, res_ptr));
    345 }
    346 
    347 static void
    348 clnttcp_abort()
    349 {
    350 }
    351 
    352 static bool_t
    353 clnttcp_control(cl, request, info)
    354 	CLIENT *cl;
    355 	int request;
    356 	char *info;
    357 {
    358 	register struct ct_data *ct = (struct ct_data *)cl->cl_private;
    359 
    360 	switch (request) {
    361 	case CLSET_TIMEOUT:
    362 		ct->ct_wait = *(struct timeval *)info;
    363 		ct->ct_waitset = TRUE;
    364 		break;
    365 	case CLGET_TIMEOUT:
    366 		*(struct timeval *)info = ct->ct_wait;
    367 		break;
    368 	case CLGET_SERVER_ADDR:
    369 		*(struct sockaddr_in *)info = ct->ct_addr;
    370 		break;
    371 	case CLGET_FD:
    372 		*(int *)info = ct->ct_sock;
    373 		break;
    374 	case CLSET_FD_CLOSE:
    375 		ct->ct_closeit = TRUE;
    376 		break;
    377 	case CLSET_FD_NCLOSE:
    378 		ct->ct_closeit = FALSE;
    379 		break;
    380 	default:
    381 		return (FALSE);
    382 	}
    383 	return (TRUE);
    384 }
    385 
    386 
    387 static void
    388 clnttcp_destroy(h)
    389 	CLIENT *h;
    390 {
    391 	register struct ct_data *ct =
    392 	    (struct ct_data *) h->cl_private;
    393 
    394 	if (ct->ct_closeit) {
    395 		(void) close(ct->ct_sock);
    396 	}
    397 	XDR_DESTROY(&(ct->ct_xdrs));
    398 	mem_free((caddr_t)ct, sizeof (struct ct_data));
    399 	mem_free((caddr_t)h, sizeof (CLIENT));
    400 }
    401 
    402 /*
    403  * Interface between xdr serializer and tcp connection.
    404  * Behaves like the system calls, read & write, but keeps some error state
    405  * around for the rpc level.
    406  */
    407 static int
    408 readtcp(ct, buf, len)
    409 	register struct ct_data *ct;
    410 	caddr_t buf;
    411 	register int len;
    412 {
    413 	fd_set mask;
    414 	fd_set readfds;
    415 
    416 	if (len == 0)
    417 		return (0);
    418 	FD_ZERO(&mask);
    419 	FD_SET(ct->ct_sock, &mask);
    420 	while (TRUE) {
    421 		readfds = mask;
    422 		switch (select(__rpc_dtbsize(),
    423 		    &readfds, NULL, NULL, &(ct->ct_wait))) {
    424 		case 0:
    425 			ct->ct_error.re_status = RPC_TIMEDOUT;
    426 			return (-1);
    427 
    428 		case -1:
    429 			if (errno == EINTR)
    430 				continue;
    431 			ct->ct_error.re_status = RPC_CANTRECV;
    432 			ct->ct_error.re_errno = errno;
    433 			return (-1);
    434 		}
    435 		break;
    436 	}
    437 	switch (len = read(ct->ct_sock, buf, len)) {
    438 
    439 	case 0:
    440 		/* premature eof */
    441 		ct->ct_error.re_errno = ECONNRESET;
    442 		ct->ct_error.re_status = RPC_CANTRECV;
    443 		len = -1;  /* it's really an error */
    444 		break;
    445 
    446 	case -1:
    447 		ct->ct_error.re_errno = errno;
    448 		ct->ct_error.re_status = RPC_CANTRECV;
    449 		break;
    450 	}
    451 	return (len);
    452 }
    453 
    454 static int
    455 writetcp(ct, buf, len)
    456 	struct ct_data *ct;
    457 	caddr_t buf;
    458 	int len;
    459 {
    460 	register int i, cnt;
    461 
    462 	for (cnt = len; cnt > 0; cnt -= i, buf += i) {
    463 		if ((i = write(ct->ct_sock, buf, cnt)) == -1) {
    464 			ct->ct_error.re_errno = errno;
    465 			ct->ct_error.re_status = RPC_CANTSEND;
    466 			return (-1);
    467 		}
    468 	}
    469 	return (len);
    470 }
    471 
    472 static struct clnt_ops *
    473 clnttcp_ops()
    474 {
    475 	static struct clnt_ops ops;
    476 
    477 	if (ops.cl_call == NULL) {
    478 		ops.cl_call = clnttcp_call;
    479 		ops.cl_abort = clnttcp_abort;
    480 		ops.cl_geterr = clnttcp_geterr;
    481 		ops.cl_freeres = clnttcp_freeres;
    482 		ops.cl_destroy = clnttcp_destroy;
    483 		ops.cl_control = clnttcp_control;
    484 	}
    485 	return (&ops);
    486 }
    487