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