clnt_raw.c revision 261046
1/*	$NetBSD: clnt_raw.c,v 1.20 2000/12/10 04:12:03 christos Exp $	*/
2
3/*-
4 * Copyright (c) 2009, Sun Microsystems, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * - Redistributions of source code must retain the above copyright notice,
10 *   this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright notice,
12 *   this list of conditions and the following disclaimer in the documentation
13 *   and/or other materials provided with the distribution.
14 * - Neither the name of Sun Microsystems, Inc. nor the names of its
15 *   contributors may be used to endorse or promote products derived
16 *   from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#if defined(LIBC_SCCS) && !defined(lint)
32static char *sccsid2 = "@(#)clnt_raw.c 1.22 87/08/11 Copyr 1984 Sun Micro";
33static char *sccsid = "@(#)clnt_raw.c	2.2 88/08/01 4.0 RPCSRC";
34#endif
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD: stable/10/lib/libc/rpc/clnt_raw.c 261046 2014-01-22 23:45:27Z mav $");
37
38/*
39 * clnt_raw.c
40 *
41 * Copyright (C) 1984, Sun Microsystems, Inc.
42 *
43 * Memory based rpc for simple testing and timing.
44 * Interface to create an rpc client and server in the same process.
45 * This lets us similate rpc and get round trip overhead, without
46 * any interference from the kernel.
47 */
48
49#include "namespace.h"
50#include "reentrant.h"
51#include <assert.h>
52#include <err.h>
53#include <stdio.h>
54#include <stdlib.h>
55
56#include <rpc/rpc.h>
57#include <rpc/raw.h>
58#include "un-namespace.h"
59#include "mt_misc.h"
60
61#define MCALL_MSG_SIZE 24
62
63/*
64 * This is the "network" we will be moving stuff over.
65 */
66static struct clntraw_private {
67	CLIENT	client_object;
68	XDR	xdr_stream;
69	char	*_raw_buf;
70	union {
71	    struct rpc_msg	mashl_rpcmsg;
72	    char 		mashl_callmsg[MCALL_MSG_SIZE];
73	} u;
74	u_int	mcnt;
75} *clntraw_private;
76
77static enum clnt_stat clnt_raw_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
78	xdrproc_t, void *, struct timeval);
79static void clnt_raw_geterr(CLIENT *, struct rpc_err *);
80static bool_t clnt_raw_freeres(CLIENT *, xdrproc_t, void *);
81static void clnt_raw_abort(CLIENT *);
82static bool_t clnt_raw_control(CLIENT *, u_int, void *);
83static void clnt_raw_destroy(CLIENT *);
84static struct clnt_ops *clnt_raw_ops(void);
85
86/*
87 * Create a client handle for memory based rpc.
88 */
89CLIENT *
90clnt_raw_create(prog, vers)
91	rpcprog_t prog;
92	rpcvers_t vers;
93{
94	struct clntraw_private *clp;
95	struct rpc_msg call_msg;
96	XDR *xdrs;
97	CLIENT	*client;
98
99	mutex_lock(&clntraw_lock);
100	if ((clp = clntraw_private) == NULL) {
101		clp = (struct clntraw_private *)calloc(1, sizeof (*clp));
102		if (clp == NULL) {
103			mutex_unlock(&clntraw_lock);
104			return NULL;
105		}
106		if (__rpc_rawcombuf == NULL)
107			__rpc_rawcombuf =
108			    (char *)calloc(UDPMSGSIZE, sizeof (char));
109		clp->_raw_buf = __rpc_rawcombuf;
110		clntraw_private = clp;
111	}
112	xdrs = &clp->xdr_stream;
113	client = &clp->client_object;
114
115	/*
116	 * pre-serialize the static part of the call msg and stash it away
117	 */
118	call_msg.rm_direction = CALL;
119	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
120	/* XXX: prog and vers have been long historically :-( */
121	call_msg.rm_call.cb_prog = (u_int32_t)prog;
122	call_msg.rm_call.cb_vers = (u_int32_t)vers;
123	xdrmem_create(xdrs, clp->u.mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE);
124	if (! xdr_callhdr(xdrs, &call_msg))
125		warnx("clntraw_create - Fatal header serialization error.");
126	clp->mcnt = XDR_GETPOS(xdrs);
127	XDR_DESTROY(xdrs);
128
129	/*
130	 * Set xdrmem for client/server shared buffer
131	 */
132	xdrmem_create(xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE);
133
134	/*
135	 * create client handle
136	 */
137	client->cl_ops = clnt_raw_ops();
138	client->cl_auth = authnone_create();
139	mutex_unlock(&clntraw_lock);
140	return (client);
141}
142
143/* ARGSUSED */
144static enum clnt_stat
145clnt_raw_call(h, proc, xargs, argsp, xresults, resultsp, timeout)
146	CLIENT *h;
147	rpcproc_t proc;
148	xdrproc_t xargs;
149	void *argsp;
150	xdrproc_t xresults;
151	void *resultsp;
152	struct timeval timeout;
153{
154	struct clntraw_private *clp = clntraw_private;
155	XDR *xdrs = &clp->xdr_stream;
156	struct rpc_msg msg;
157	enum clnt_stat status;
158	struct rpc_err error;
159
160	assert(h != NULL);
161
162	mutex_lock(&clntraw_lock);
163	if (clp == NULL) {
164		mutex_unlock(&clntraw_lock);
165		return (RPC_FAILED);
166	}
167	mutex_unlock(&clntraw_lock);
168
169call_again:
170	/*
171	 * send request
172	 */
173	xdrs->x_op = XDR_ENCODE;
174	XDR_SETPOS(xdrs, 0);
175	clp->u.mashl_rpcmsg.rm_xid ++ ;
176	if ((! XDR_PUTBYTES(xdrs, clp->u.mashl_callmsg, clp->mcnt)) ||
177	    (! XDR_PUTINT32(xdrs, &proc)) ||
178	    (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
179	    (! (*xargs)(xdrs, argsp))) {
180		return (RPC_CANTENCODEARGS);
181	}
182	(void)XDR_GETPOS(xdrs);  /* called just to cause overhead */
183
184	/*
185	 * We have to call server input routine here because this is
186	 * all going on in one process. Yuk.
187	 */
188	svc_getreq_common(FD_SETSIZE);
189
190	/*
191	 * get results
192	 */
193	xdrs->x_op = XDR_DECODE;
194	XDR_SETPOS(xdrs, 0);
195	msg.acpted_rply.ar_verf = _null_auth;
196	msg.acpted_rply.ar_results.where = resultsp;
197	msg.acpted_rply.ar_results.proc = xresults;
198	if (! xdr_replymsg(xdrs, &msg)) {
199		/*
200		 * It's possible for xdr_replymsg() to fail partway
201		 * through its attempt to decode the result from the
202		 * server. If this happens, it will leave the reply
203		 * structure partially populated with dynamically
204		 * allocated memory. (This can happen if someone uses
205		 * clntudp_bufcreate() to create a CLIENT handle and
206		 * specifies a receive buffer size that is too small.)
207		 * This memory must be free()ed to avoid a leak.
208		 */
209		int op = xdrs->x_op;
210		xdrs->x_op = XDR_FREE;
211		xdr_replymsg(xdrs, &msg);
212		xdrs->x_op = op;
213		return (RPC_CANTDECODERES);
214	}
215	_seterr_reply(&msg, &error);
216	status = error.re_status;
217
218	if (status == RPC_SUCCESS) {
219		if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) {
220			status = RPC_AUTHERROR;
221		}
222	}  /* end successful completion */
223	else {
224		if (AUTH_REFRESH(h->cl_auth, &msg))
225			goto call_again;
226	}  /* end of unsuccessful completion */
227
228	if (status == RPC_SUCCESS) {
229		if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) {
230			status = RPC_AUTHERROR;
231		}
232		if (msg.acpted_rply.ar_verf.oa_base != NULL) {
233			xdrs->x_op = XDR_FREE;
234			(void)xdr_opaque_auth(xdrs, &(msg.acpted_rply.ar_verf));
235		}
236	}
237
238	return (status);
239}
240
241/*ARGSUSED*/
242static void
243clnt_raw_geterr(cl, err)
244	CLIENT *cl;
245	struct rpc_err *err;
246{
247}
248
249
250/* ARGSUSED */
251static bool_t
252clnt_raw_freeres(cl, xdr_res, res_ptr)
253	CLIENT *cl;
254	xdrproc_t xdr_res;
255	void *res_ptr;
256{
257	struct clntraw_private *clp = clntraw_private;
258	XDR *xdrs = &clp->xdr_stream;
259	bool_t rval;
260
261	mutex_lock(&clntraw_lock);
262	if (clp == NULL) {
263		rval = (bool_t) RPC_FAILED;
264		mutex_unlock(&clntraw_lock);
265		return (rval);
266	}
267	mutex_unlock(&clntraw_lock);
268	xdrs->x_op = XDR_FREE;
269	return ((*xdr_res)(xdrs, res_ptr));
270}
271
272/*ARGSUSED*/
273static void
274clnt_raw_abort(cl)
275	CLIENT *cl;
276{
277}
278
279/*ARGSUSED*/
280static bool_t
281clnt_raw_control(cl, ui, str)
282	CLIENT *cl;
283	u_int ui;
284	void *str;
285{
286	return (FALSE);
287}
288
289/*ARGSUSED*/
290static void
291clnt_raw_destroy(cl)
292	CLIENT *cl;
293{
294}
295
296static struct clnt_ops *
297clnt_raw_ops()
298{
299	static struct clnt_ops ops;
300
301	/* VARIABLES PROTECTED BY ops_lock: ops */
302
303	mutex_lock(&ops_lock);
304	if (ops.cl_call == NULL) {
305		ops.cl_call = clnt_raw_call;
306		ops.cl_abort = clnt_raw_abort;
307		ops.cl_geterr = clnt_raw_geterr;
308		ops.cl_freeres = clnt_raw_freeres;
309		ops.cl_destroy = clnt_raw_destroy;
310		ops.cl_control = clnt_raw_control;
311	}
312	mutex_unlock(&ops_lock);
313	return (&ops);
314}
315