1/* $NetBSD: clnt_raw.c,v 1.29 2008/04/25 17:44:44 christos Exp $ */ 2 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 34#include <sys/cdefs.h> 35#if defined(LIBC_SCCS) && !defined(lint) 36#if 0 37static char *sccsid = "@(#)clnt_raw.c 1.22 87/08/11 Copyr 1984 Sun Micro"; 38static char *sccsid = "@(#)clnt_raw.c 2.2 88/08/01 4.0 RPCSRC"; 39#else 40__RCSID("$NetBSD: clnt_raw.c,v 1.29 2008/04/25 17:44:44 christos Exp $"); 41#endif 42#endif 43 44/* 45 * clnt_raw.c 46 * 47 * Copyright (C) 1984, Sun Microsystems, Inc. 48 * 49 * Memory based rpc for simple testing and timing. 50 * Interface to create an rpc client and server in the same process. 51 * This lets us similate rpc and get round trip overhead, without 52 * any interference from the kernel. 53 */ 54 55#include "namespace.h" 56#include "reentrant.h" 57#include <assert.h> 58#include <err.h> 59#include <stdio.h> 60#include <stdlib.h> 61 62#include <rpc/rpc.h> 63#include <rpc/raw.h> 64 65#ifdef __weak_alias 66__weak_alias(clntraw_create,_clntraw_create) 67__weak_alias(clnt_raw_create,_clnt_raw_create) 68#endif 69 70#ifdef _REENTRANT 71extern mutex_t clntraw_lock; 72#endif 73 74#define MCALL_MSG_SIZE 24 75 76/* 77 * This is the "network" we will be moving stuff over. 78 */ 79static struct clntraw_private { 80 CLIENT client_object; 81 XDR xdr_stream; 82 char *_raw_buf; 83 union { 84 struct rpc_msg mashl_rpcmsg; 85 char mashl_callmsg[MCALL_MSG_SIZE]; 86 } u; 87 u_int mcnt; 88} *clntraw_private; 89 90static enum clnt_stat clnt_raw_call __P((CLIENT *, rpcproc_t, xdrproc_t, 91 const char *, xdrproc_t, caddr_t, struct timeval)); 92static void clnt_raw_geterr __P((CLIENT *, struct rpc_err *)); 93static bool_t clnt_raw_freeres __P((CLIENT *, xdrproc_t, caddr_t)); 94static void clnt_raw_abort __P((CLIENT *)); 95static bool_t clnt_raw_control __P((CLIENT *, u_int, char *)); 96static void clnt_raw_destroy __P((CLIENT *)); 97static struct clnt_ops *clnt_raw_ops __P((void)); 98 99/* 100 * Create a client handle for memory based rpc. 101 */ 102CLIENT * 103clnt_raw_create(prog, vers) 104 rpcprog_t prog; 105 rpcvers_t vers; 106{ 107 struct clntraw_private *clp = clntraw_private; 108 struct rpc_msg call_msg; 109 XDR *xdrs = &clp->xdr_stream; 110 CLIENT *client = &clp->client_object; 111 112 mutex_lock(&clntraw_lock); 113 if (clp == NULL) { 114 clp = calloc((size_t)1, sizeof (*clp)); 115 if (clp == NULL) 116 goto out; 117 if (__rpc_rawcombuf == NULL) 118 __rpc_rawcombuf = 119 malloc(UDPMSGSIZE); 120 if (__rpc_rawcombuf == NULL) 121 goto out; 122 clp->_raw_buf = __rpc_rawcombuf; 123 clntraw_private = clp; 124 } 125 /* 126 * pre-serialize the static part of the call msg and stash it away 127 */ 128 call_msg.rm_direction = CALL; 129 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 130 /* XXX: prog and vers have been long historically :-( */ 131 call_msg.rm_call.cb_prog = (u_int32_t)prog; 132 call_msg.rm_call.cb_vers = (u_int32_t)vers; 133 xdrmem_create(xdrs, clp->u.mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE); 134 if (! xdr_callhdr(xdrs, &call_msg)) 135 warnx("clntraw_create - Fatal header serialization error."); 136 clp->mcnt = XDR_GETPOS(xdrs); 137 XDR_DESTROY(xdrs); 138 139 /* 140 * Set xdrmem for client/server shared buffer 141 */ 142 xdrmem_create(xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE); 143 144 /* 145 * create client handle 146 */ 147 client->cl_ops = clnt_raw_ops(); 148 client->cl_auth = authnone_create(); 149 mutex_unlock(&clntraw_lock); 150 return (client); 151out: 152 if (clp) 153 free(clp); 154 mutex_unlock(&clntraw_lock); 155 return NULL; 156 157} 158 159/* ARGSUSED */ 160static enum clnt_stat 161clnt_raw_call(h, proc, xargs, argsp, xresults, resultsp, timeout) 162 CLIENT *h; 163 rpcproc_t proc; 164 xdrproc_t xargs; 165 const char *argsp; 166 xdrproc_t xresults; 167 caddr_t resultsp; 168 struct timeval timeout; 169{ 170 struct clntraw_private *clp = clntraw_private; 171 XDR *xdrs = &clp->xdr_stream; 172 struct rpc_msg msg; 173 enum clnt_stat status; 174 struct rpc_err error; 175 176 _DIAGASSERT(h != NULL); 177 178 mutex_lock(&clntraw_lock); 179 if (clp == NULL) { 180 mutex_unlock(&clntraw_lock); 181 return (RPC_FAILED); 182 } 183 mutex_unlock(&clntraw_lock); 184 185call_again: 186 /* 187 * send request 188 */ 189 xdrs->x_op = XDR_ENCODE; 190 XDR_SETPOS(xdrs, 0); 191 clp->u.mashl_rpcmsg.rm_xid ++ ; 192 if ((! XDR_PUTBYTES(xdrs, clp->u.mashl_callmsg, clp->mcnt)) || 193 (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 194 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 195 (! (*xargs)(xdrs, __UNCONST(argsp)))) { 196 return (RPC_CANTENCODEARGS); 197 } 198 (void)XDR_GETPOS(xdrs); /* called just to cause overhead */ 199 200 /* 201 * We have to call server input routine here because this is 202 * all going on in one process. Yuk. 203 */ 204 svc_getreq_common(FD_SETSIZE); 205 206 /* 207 * get results 208 */ 209 xdrs->x_op = XDR_DECODE; 210 XDR_SETPOS(xdrs, 0); 211 msg.acpted_rply.ar_verf = _null_auth; 212 msg.acpted_rply.ar_results.where = resultsp; 213 msg.acpted_rply.ar_results.proc = xresults; 214 if (! xdr_replymsg(xdrs, &msg)) { 215 /* 216 * It's possible for xdr_replymsg() to fail partway 217 * through its attempt to decode the result from the 218 * server. If this happens, it will leave the reply 219 * structure partially populated with dynamically 220 * allocated memory. (This can happen if someone uses 221 * clntudp_bufcreate() to create a CLIENT handle and 222 * specifies a receive buffer size that is too small.) 223 * This memory must be free()ed to avoid a leak. 224 */ 225 int op = xdrs->x_op; 226 xdrs->x_op = XDR_FREE; 227 xdr_replymsg(xdrs, &msg); 228 xdrs->x_op = op; 229 return (RPC_CANTDECODERES); 230 } 231 _seterr_reply(&msg, &error); 232 status = error.re_status; 233 234 if (status == RPC_SUCCESS) { 235 if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { 236 status = RPC_AUTHERROR; 237 } 238 } /* end successful completion */ 239 else { 240 if (AUTH_REFRESH(h->cl_auth)) 241 goto call_again; 242 } /* end of unsuccessful completion */ 243 244 if (status == RPC_SUCCESS) { 245 if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { 246 status = RPC_AUTHERROR; 247 } 248 if (msg.acpted_rply.ar_verf.oa_base != NULL) { 249 xdrs->x_op = XDR_FREE; 250 (void)xdr_opaque_auth(xdrs, &(msg.acpted_rply.ar_verf)); 251 } 252 } 253 254 return (status); 255} 256 257/*ARGSUSED*/ 258static void 259clnt_raw_geterr(cl, error) 260 CLIENT *cl; 261 struct rpc_err *error; 262{ 263} 264 265 266/* ARGSUSED */ 267static bool_t 268clnt_raw_freeres(cl, xdr_res, res_ptr) 269 CLIENT *cl; 270 xdrproc_t xdr_res; 271 caddr_t res_ptr; 272{ 273 struct clntraw_private *clp = clntraw_private; 274 XDR *xdrs = &clp->xdr_stream; 275 bool_t rval; 276 277 mutex_lock(&clntraw_lock); 278 if (clp == NULL) { 279 rval = (bool_t) RPC_FAILED; 280 mutex_unlock(&clntraw_lock); 281 return (rval); 282 } 283 mutex_unlock(&clntraw_lock); 284 xdrs->x_op = XDR_FREE; 285 return ((*xdr_res)(xdrs, res_ptr)); 286} 287 288/*ARGSUSED*/ 289static void 290clnt_raw_abort(cl) 291 CLIENT *cl; 292{ 293} 294 295/*ARGSUSED*/ 296static bool_t 297clnt_raw_control(cl, ui, str) 298 CLIENT *cl; 299 u_int ui; 300 char *str; 301{ 302 return (FALSE); 303} 304 305/*ARGSUSED*/ 306static void 307clnt_raw_destroy(cl) 308 CLIENT *cl; 309{ 310} 311 312static struct clnt_ops * 313clnt_raw_ops() 314{ 315 static struct clnt_ops ops; 316#ifdef _REENTRANT 317 extern mutex_t ops_lock; 318#endif 319 320 /* VARIABLES PROTECTED BY ops_lock: ops */ 321 322 mutex_lock(&ops_lock); 323 if (ops.cl_call == NULL) { 324 ops.cl_call = clnt_raw_call; 325 ops.cl_abort = clnt_raw_abort; 326 ops.cl_geterr = clnt_raw_geterr; 327 ops.cl_freeres = clnt_raw_freeres; 328 ops.cl_destroy = clnt_raw_destroy; 329 ops.cl_control = clnt_raw_control; 330 } 331 mutex_unlock(&ops_lock); 332 return (&ops); 333} 334