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
73extern int errno;
74
75static int	readtcp();
76static int	writetcp();
77extern int _socket(int, int, int);
78extern pid_t getpid();
79extern int bindresvport(int, struct sockaddr_in *);
80extern bool_t   xdr_opaque_auth(XDR *, struct opaque_auth *);
81static struct clnt_ops *clnttcp_ops();
82
83struct 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 */
109CLIENT *
110clnttcp_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
215fooy:
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
224static enum clnt_stat
225clnttcp_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
250call_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
323static void
324clnttcp_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
334static bool_t
335clnttcp_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
347static void
348clnttcp_abort()
349{
350}
351
352static bool_t
353clnttcp_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
387static void
388clnttcp_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 */
407static int
408readtcp(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
454static int
455writetcp(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
472static struct clnt_ops *
473clnttcp_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