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