xref: /dragonfly/lib/libc/rpc/clnt_raw.c (revision f746689a)
1 /*
2  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3  * unrestricted use provided that this legend is included on all tape
4  * media and as a part of the software program in whole or part.  Users
5  * may copy or modify Sun RPC without charge, but are not authorized
6  * to license or distribute it to anyone else except as part of a product or
7  * program developed by the user.
8  *
9  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12  *
13  * Sun RPC is provided with no support and without any obligation on the
14  * part of Sun Microsystems, Inc. to assist in its use, correction,
15  * modification or enhancement.
16  *
17  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19  * OR ANY PART THEREOF.
20  *
21  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22  * or profits or other special, indirect and consequential damages, even if
23  * Sun has been advised of the possibility of such damages.
24  *
25  * Sun Microsystems, Inc.
26  * 2550 Garcia Avenue
27  * Mountain View, California  94043
28  *
29  * @(#)clnt_raw.c 1.22 87/08/11 Copyr 1984 Sun Micro
30  * @(#)clnt_raw.c	2.2 88/08/01 4.0 RPCSRC
31  * $NetBSD: clnt_raw.c,v 1.20 2000/12/10 04:12:03 christos Exp $
32  * $FreeBSD: src/lib/libc/rpc/clnt_raw.c,v 1.20 2006/02/27 22:10:58 deischen Exp $
33  * $DragonFly: src/lib/libc/rpc/clnt_raw.c,v 1.4 2005/11/13 12:27:04 swildner Exp $
34  */
35 
36 /*
37  * clnt_raw.c
38  *
39  * Copyright (C) 1984, Sun Microsystems, Inc.
40  *
41  * Memory based rpc for simple testing and timing.
42  * Interface to create an rpc client and server in the same process.
43  * This lets us similate rpc and get round trip overhead, without
44  * any interference from the kernel.
45  */
46 
47 #include "namespace.h"
48 #include "reentrant.h"
49 #include <assert.h>
50 #include <err.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 
54 #include <rpc/rpc.h>
55 #include <rpc/raw.h>
56 #include "un-namespace.h"
57 #include "mt_misc.h"
58 
59 #define MCALL_MSG_SIZE 24
60 
61 /*
62  * This is the "network" we will be moving stuff over.
63  */
64 static struct clntraw_private {
65 	CLIENT	client_object;
66 	XDR	xdr_stream;
67 	char	*_raw_buf;
68 	union {
69 	    struct rpc_msg	mashl_rpcmsg;
70 	    char 		mashl_callmsg[MCALL_MSG_SIZE];
71 	} u;
72 	u_int	mcnt;
73 } *clntraw_private;
74 
75 static void		 clnt_raw_abort(CLIENT *);
76 static enum clnt_stat	 clnt_raw_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
77 				       xdrproc_t, void *, struct timeval);
78 static bool_t		 clnt_raw_control(CLIENT *, u_int, void *);
79 static void		 clnt_raw_destroy(CLIENT *);
80 static bool_t		 clnt_raw_freeres(CLIENT *, xdrproc_t, void *);
81 static void		 clnt_raw_geterr(CLIENT *, struct rpc_err *);
82 static struct clnt_ops	*clnt_raw_ops(void);
83 
84 /*
85  * Create a client handle for memory based rpc.
86  */
87 CLIENT *
88 clnt_raw_create(rpcprog_t prog, rpcvers_t vers)
89 {
90 	struct clntraw_private *clp = clntraw_private;
91 	struct rpc_msg call_msg;
92 	XDR *xdrs = &clp->xdr_stream;
93 	CLIENT	*client = &clp->client_object;
94 
95 	mutex_lock(&clntraw_lock);
96 	if (clp == NULL) {
97 		clp = (struct clntraw_private *)calloc(1, sizeof (*clp));
98 		if (clp == NULL) {
99 			mutex_unlock(&clntraw_lock);
100 			return NULL;
101 		}
102 		if (__rpc_rawcombuf == NULL)
103 			__rpc_rawcombuf =
104 			    (char *)calloc(UDPMSGSIZE, sizeof (char));
105 		clp->_raw_buf = __rpc_rawcombuf;
106 		clntraw_private = clp;
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 	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 			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