xref: /freebsd/lib/libc/rpc/clnt_raw.c (revision 2e3507c25e42292b45a5482e116d278f5515d04d)
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  */
61 static 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 
72 static enum clnt_stat clnt_raw_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
73 	xdrproc_t, void *, struct timeval);
74 static void clnt_raw_geterr(CLIENT *, struct rpc_err *);
75 static bool_t clnt_raw_freeres(CLIENT *, xdrproc_t, void *);
76 static void clnt_raw_abort(CLIENT *);
77 static bool_t clnt_raw_control(CLIENT *, u_int, void *);
78 static void clnt_raw_destroy(CLIENT *);
79 static struct clnt_ops *clnt_raw_ops(void);
80 
81 /*
82  * Create a client handle for memory based rpc.
83  */
84 CLIENT *
85 clnt_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 */
137 static enum clnt_stat
138 clnt_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 
156 call_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*/
229 static void
230 clnt_raw_geterr(CLIENT *cl, struct rpc_err *err)
231 {
232 }
233 
234 
235 /* ARGSUSED */
236 static bool_t
237 clnt_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*/
255 static void
256 clnt_raw_abort(CLIENT *cl)
257 {
258 }
259 
260 /*ARGSUSED*/
261 static bool_t
262 clnt_raw_control(CLIENT *cl, u_int ui, void *str)
263 {
264 	return (FALSE);
265 }
266 
267 /*ARGSUSED*/
268 static void
269 clnt_raw_destroy(CLIENT *cl)
270 {
271 }
272 
273 static struct clnt_ops *
274 clnt_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