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 309487 2016-12-03 17:27:28Z ngie $");
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(rpcprog_t prog, rpcvers_t vers)
91{
92	struct clntraw_private *clp;
93	struct rpc_msg call_msg;
94	XDR *xdrs;
95	CLIENT	*client;
96
97	mutex_lock(&clntraw_lock);
98	if ((clp = clntraw_private) == NULL) {
99		clp = (struct clntraw_private *)calloc(1, sizeof (*clp));
100		if (clp == NULL) {
101			mutex_unlock(&clntraw_lock);
102			return NULL;
103		}
104		if (__rpc_rawcombuf == NULL)
105			__rpc_rawcombuf =
106			    (char *)calloc(UDPMSGSIZE, sizeof (char));
107		clp->_raw_buf = __rpc_rawcombuf;
108		clntraw_private = clp;
109	}
110	xdrs = &clp->xdr_stream;
111	client = &clp->client_object;
112
113	/*
114	 * pre-serialize the static part of the call msg and stash it away
115	 */
116	call_msg.rm_direction = CALL;
117	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
118	/* XXX: prog and vers have been long historically :-( */
119	call_msg.rm_call.cb_prog = (u_int32_t)prog;
120	call_msg.rm_call.cb_vers = (u_int32_t)vers;
121	xdrmem_create(xdrs, clp->u.mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE);
122	if (! xdr_callhdr(xdrs, &call_msg))
123		warnx("clntraw_create - Fatal header serialization error.");
124	clp->mcnt = XDR_GETPOS(xdrs);
125	XDR_DESTROY(xdrs);
126
127	/*
128	 * Set xdrmem for client/server shared buffer
129	 */
130	xdrmem_create(xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE);
131
132	/*
133	 * create client handle
134	 */
135	client->cl_ops = clnt_raw_ops();
136	client->cl_auth = authnone_create();
137	mutex_unlock(&clntraw_lock);
138	return (client);
139}
140
141/* ARGSUSED */
142static enum clnt_stat
143clnt_raw_call(CLIENT *h, rpcproc_t proc, xdrproc_t xargs, void *argsp,
144    xdrproc_t xresults, void *resultsp, struct timeval timeout)
145{
146	struct clntraw_private *clp = clntraw_private;
147	XDR *xdrs = &clp->xdr_stream;
148	struct rpc_msg msg;
149	enum clnt_stat status;
150	struct rpc_err error;
151
152	assert(h != NULL);
153
154	mutex_lock(&clntraw_lock);
155	if (clp == NULL) {
156		mutex_unlock(&clntraw_lock);
157		return (RPC_FAILED);
158	}
159	mutex_unlock(&clntraw_lock);
160
161call_again:
162	/*
163	 * send request
164	 */
165	xdrs->x_op = XDR_ENCODE;
166	XDR_SETPOS(xdrs, 0);
167	clp->u.mashl_rpcmsg.rm_xid ++ ;
168	if ((! XDR_PUTBYTES(xdrs, clp->u.mashl_callmsg, clp->mcnt)) ||
169	    (! XDR_PUTINT32(xdrs, &proc)) ||
170	    (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
171	    (! (*xargs)(xdrs, argsp))) {
172		return (RPC_CANTENCODEARGS);
173	}
174	(void)XDR_GETPOS(xdrs);  /* called just to cause overhead */
175
176	/*
177	 * We have to call server input routine here because this is
178	 * all going on in one process. Yuk.
179	 */
180	svc_getreq_common(FD_SETSIZE);
181
182	/*
183	 * get results
184	 */
185	xdrs->x_op = XDR_DECODE;
186	XDR_SETPOS(xdrs, 0);
187	msg.acpted_rply.ar_verf = _null_auth;
188	msg.acpted_rply.ar_results.where = resultsp;
189	msg.acpted_rply.ar_results.proc = xresults;
190	if (! xdr_replymsg(xdrs, &msg)) {
191		/*
192		 * It's possible for xdr_replymsg() to fail partway
193		 * through its attempt to decode the result from the
194		 * server. If this happens, it will leave the reply
195		 * structure partially populated with dynamically
196		 * allocated memory. (This can happen if someone uses
197		 * clntudp_bufcreate() to create a CLIENT handle and
198		 * specifies a receive buffer size that is too small.)
199		 * This memory must be free()ed to avoid a leak.
200		 */
201		int op = xdrs->x_op;
202		xdrs->x_op = XDR_FREE;
203		xdr_replymsg(xdrs, &msg);
204		xdrs->x_op = op;
205		return (RPC_CANTDECODERES);
206	}
207	_seterr_reply(&msg, &error);
208	status = error.re_status;
209
210	if (status == RPC_SUCCESS) {
211		if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) {
212			status = RPC_AUTHERROR;
213		}
214	}  /* end successful completion */
215	else {
216		if (AUTH_REFRESH(h->cl_auth, &msg))
217			goto call_again;
218	}  /* end of unsuccessful completion */
219
220	if (status == RPC_SUCCESS) {
221		if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) {
222			status = RPC_AUTHERROR;
223		}
224		if (msg.acpted_rply.ar_verf.oa_base != NULL) {
225			xdrs->x_op = XDR_FREE;
226			(void)xdr_opaque_auth(xdrs, &(msg.acpted_rply.ar_verf));
227		}
228	}
229
230	return (status);
231}
232
233/*ARGSUSED*/
234static void
235clnt_raw_geterr(CLIENT *cl, struct rpc_err *err)
236{
237}
238
239
240/* ARGSUSED */
241static bool_t
242clnt_raw_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
243{
244	struct clntraw_private *clp = clntraw_private;
245	XDR *xdrs = &clp->xdr_stream;
246	bool_t rval;
247
248	mutex_lock(&clntraw_lock);
249	if (clp == NULL) {
250		rval = (bool_t) RPC_FAILED;
251		mutex_unlock(&clntraw_lock);
252		return (rval);
253	}
254	mutex_unlock(&clntraw_lock);
255	xdrs->x_op = XDR_FREE;
256	return ((*xdr_res)(xdrs, res_ptr));
257}
258
259/*ARGSUSED*/
260static void
261clnt_raw_abort(CLIENT *cl)
262{
263}
264
265/*ARGSUSED*/
266static bool_t
267clnt_raw_control(CLIENT *cl, u_int ui, void *str)
268{
269	return (FALSE);
270}
271
272/*ARGSUSED*/
273static void
274clnt_raw_destroy(CLIENT *cl)
275{
276}
277
278static struct clnt_ops *
279clnt_raw_ops(void)
280{
281	static struct clnt_ops ops;
282
283	/* VARIABLES PROTECTED BY ops_lock: ops */
284
285	mutex_lock(&ops_lock);
286	if (ops.cl_call == NULL) {
287		ops.cl_call = clnt_raw_call;
288		ops.cl_abort = clnt_raw_abort;
289		ops.cl_geterr = clnt_raw_geterr;
290		ops.cl_freeres = clnt_raw_freeres;
291		ops.cl_destroy = clnt_raw_destroy;
292		ops.cl_control = clnt_raw_control;
293	}
294	mutex_unlock(&ops_lock);
295	return (&ops);
296}
297