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