1 /*
2  * clnt_raw.c
3  *
4  * Copyright (c) 2010, Oracle America, Inc.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above
13  *       copyright notice, this list of conditions and the following
14  *       disclaimer in the documentation and/or other materials
15  *       provided with the distribution.
16  *     * Neither the name of the "Oracle America, 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
21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Memory based rpc for simple testing and timing.
34  * Interface to create an rpc client and server in the same process.
35  * This lets us simulate rpc and get round trip overhead, without
36  * any interference from the kernel.
37  */
38 
39 #include <rpc/rpc.h>
40 #include <rpc/svc.h>
41 #include <rpc/xdr.h>
42 #include <libintl.h>
43 #include <shlib-compat.h>
44 
45 #define MCALL_MSG_SIZE 24
46 
47 /*
48  * This is the "network" we will be moving stuff over.
49  */
50 struct clntraw_private_s
51   {
52     CLIENT client_object;
53     XDR xdr_stream;
54     char _raw_buf[UDPMSGSIZE];
55     union
56     {
57       char msg[MCALL_MSG_SIZE];
58       u_long rm_xid;
59     } mashl_callmsg;
60     u_int mcnt;
61   };
62 #define clntraw_private RPC_THREAD_VARIABLE(clntraw_private_s)
63 
64 static enum clnt_stat clntraw_call (CLIENT *, u_long, xdrproc_t, caddr_t,
65 				    xdrproc_t, caddr_t, struct timeval);
66 static void clntraw_abort (void);
67 static void clntraw_geterr (CLIENT *, struct rpc_err *);
68 static bool_t clntraw_freeres (CLIENT *, xdrproc_t, caddr_t);
69 static bool_t clntraw_control (CLIENT *, int, char *);
70 static void clntraw_destroy (CLIENT *);
71 
72 static const struct clnt_ops client_ops =
73 {
74   clntraw_call,
75   clntraw_abort,
76   clntraw_geterr,
77   clntraw_freeres,
78   clntraw_destroy,
79   clntraw_control
80 };
81 
82 /*
83  * Create a client handle for memory based rpc.
84  */
85 CLIENT *
clntraw_create(u_long prog,u_long vers)86 clntraw_create (u_long prog, u_long vers)
87 {
88   struct clntraw_private_s *clp = clntraw_private;
89   struct rpc_msg call_msg;
90   XDR *xdrs;
91   CLIENT *client;
92 
93   if (clp == 0)
94     {
95       clp = (struct clntraw_private_s *) calloc (1, sizeof (*clp));
96       if (clp == 0)
97 	return (0);
98       clntraw_private = clp;
99     }
100   xdrs = &clp->xdr_stream;
101   client = &clp->client_object;
102   /*
103    * pre-serialize the static part of the call msg and stash it away
104    */
105   call_msg.rm_direction = CALL;
106   call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
107   call_msg.rm_call.cb_prog = prog;
108   call_msg.rm_call.cb_vers = vers;
109   xdrmem_create (xdrs, clp->mashl_callmsg.msg, MCALL_MSG_SIZE, XDR_ENCODE);
110   if (!xdr_callhdr (xdrs, &call_msg))
111     {
112       perror (_ ("clnt_raw.c: fatal header serialization error"));
113     }
114   clp->mcnt = XDR_GETPOS (xdrs);
115   XDR_DESTROY (xdrs);
116 
117   /*
118    * Set xdrmem for client/server shared buffer
119    */
120   xdrmem_create (xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE);
121 
122   /*
123    * create client handle
124    */
125   client->cl_ops = (struct clnt_ops *) &client_ops;
126   client->cl_auth = authnone_create ();
127   return client;
128 }
libc_hidden_nolink_sunrpc(clntraw_create,GLIBC_2_0)129 libc_hidden_nolink_sunrpc (clntraw_create, GLIBC_2_0)
130 
131 static enum clnt_stat
132 clntraw_call (CLIENT *h, u_long proc, xdrproc_t xargs, caddr_t argsp,
133 	      xdrproc_t xresults, caddr_t resultsp, struct timeval timeout)
134 {
135   struct clntraw_private_s *clp = clntraw_private;
136   XDR *xdrs = &clp->xdr_stream;
137   struct rpc_msg msg;
138   enum clnt_stat status;
139   struct rpc_err error;
140 
141   if (clp == NULL)
142     return RPC_FAILED;
143 call_again:
144   /*
145    * send request
146    */
147   xdrs->x_op = XDR_ENCODE;
148   XDR_SETPOS (xdrs, 0);
149   /* Just checking the union definition to access rm_xid is correct.  */
150   if (offsetof (struct rpc_msg, rm_xid) != 0)
151     abort ();
152   clp->mashl_callmsg.rm_xid++;
153   if ((!XDR_PUTBYTES (xdrs, clp->mashl_callmsg.msg, clp->mcnt)) ||
154       (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
155       (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
156       (!(*xargs) (xdrs, argsp)))
157     {
158       return (RPC_CANTENCODEARGS);
159     }
160   (void) XDR_GETPOS (xdrs);	/* called just to cause overhead */
161 
162   /*
163    * We have to call server input routine here because this is
164    * all going on in one process. Yuk.
165    */
166   svc_getreq (1);
167 
168   /*
169    * get results
170    */
171   xdrs->x_op = XDR_DECODE;
172   XDR_SETPOS (xdrs, 0);
173   msg.acpted_rply.ar_verf = _null_auth;
174   msg.acpted_rply.ar_results.where = resultsp;
175   msg.acpted_rply.ar_results.proc = xresults;
176   if (!xdr_replymsg (xdrs, &msg))
177     return RPC_CANTDECODERES;
178   _seterr_reply (&msg, &error);
179   status = error.re_status;
180 
181   if (status == RPC_SUCCESS)
182     {
183       if (!AUTH_VALIDATE (h->cl_auth, &msg.acpted_rply.ar_verf))
184 	{
185 	  status = RPC_AUTHERROR;
186 	}
187     }				/* end successful completion */
188   else
189     {
190       if (AUTH_REFRESH (h->cl_auth))
191 	goto call_again;
192     }				/* end of unsuccessful completion */
193 
194   if (status == RPC_SUCCESS)
195     {
196       if (!AUTH_VALIDATE (h->cl_auth, &msg.acpted_rply.ar_verf))
197 	{
198 	  status = RPC_AUTHERROR;
199 	}
200       if (msg.acpted_rply.ar_verf.oa_base != NULL)
201 	{
202 	  xdrs->x_op = XDR_FREE;
203 	  (void) xdr_opaque_auth (xdrs, &(msg.acpted_rply.ar_verf));
204 	}
205     }
206 
207   return status;
208 }
209 
210 static void
clntraw_geterr(CLIENT * cl,struct rpc_err * err)211 clntraw_geterr (CLIENT *cl, struct rpc_err *err)
212 {
213 }
214 
215 
216 static bool_t
clntraw_freeres(CLIENT * cl,xdrproc_t xdr_res,caddr_t res_ptr)217 clntraw_freeres (CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr)
218 {
219   struct clntraw_private_s *clp = clntraw_private;
220   XDR *xdrs = &clp->xdr_stream;
221   bool_t rval;
222 
223   if (clp == NULL)
224     {
225       rval = (bool_t) RPC_FAILED;
226       return rval;
227     }
228   xdrs->x_op = XDR_FREE;
229   return (*xdr_res) (xdrs, res_ptr);
230 }
231 
232 static void
clntraw_abort(void)233 clntraw_abort (void)
234 {
235 }
236 
237 static bool_t
clntraw_control(CLIENT * cl,int i,char * c)238 clntraw_control (CLIENT *cl, int i, char *c)
239 {
240   return FALSE;
241 }
242 
243 static void
clntraw_destroy(CLIENT * cl)244 clntraw_destroy (CLIENT *cl)
245 {
246 }
247