1 /* $NetBSD: clnt_raw.c,v 1.20 2000/12/10 04:12:03 christos Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 * Copyright (c) 2009, Sun Microsystems, Inc. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions are met: 11 * - Redistributions of source code must retain the above copyright notice, 12 * this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * - Neither the name of Sun Microsystems, 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 "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * clnt_raw.c 35 * 36 * Copyright (C) 1984, Sun Microsystems, Inc. 37 * 38 * Memory based rpc for simple testing and timing. 39 * Interface to create an rpc client and server in the same process. 40 * This lets us similate rpc and get round trip overhead, without 41 * any interference from the kernel. 42 */ 43 44 #include "namespace.h" 45 #include "reentrant.h" 46 #include <assert.h> 47 #include <err.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 51 #include <rpc/rpc.h> 52 #include <rpc/raw.h> 53 #include "un-namespace.h" 54 #include "mt_misc.h" 55 56 #define MCALL_MSG_SIZE 24 57 58 /* 59 * This is the "network" we will be moving stuff over. 60 */ 61 static struct clntraw_private { 62 CLIENT client_object; 63 XDR xdr_stream; 64 char *_raw_buf; 65 union { 66 struct rpc_msg mashl_rpcmsg; 67 char mashl_callmsg[MCALL_MSG_SIZE]; 68 } u; 69 u_int mcnt; 70 } *clntraw_private; 71 72 static enum clnt_stat clnt_raw_call(CLIENT *, rpcproc_t, xdrproc_t, void *, 73 xdrproc_t, void *, struct timeval); 74 static void clnt_raw_geterr(CLIENT *, struct rpc_err *); 75 static bool_t clnt_raw_freeres(CLIENT *, xdrproc_t, void *); 76 static void clnt_raw_abort(CLIENT *); 77 static bool_t clnt_raw_control(CLIENT *, u_int, void *); 78 static void clnt_raw_destroy(CLIENT *); 79 static struct clnt_ops *clnt_raw_ops(void); 80 81 /* 82 * Create a client handle for memory based rpc. 83 */ 84 CLIENT * 85 clnt_raw_create(rpcprog_t prog, rpcvers_t vers) 86 { 87 struct clntraw_private *clp; 88 struct rpc_msg call_msg; 89 XDR *xdrs; 90 CLIENT *client; 91 92 mutex_lock(&clntraw_lock); 93 if ((clp = clntraw_private) == NULL) { 94 clp = (struct clntraw_private *)calloc(1, sizeof (*clp)); 95 if (clp == NULL) { 96 mutex_unlock(&clntraw_lock); 97 return NULL; 98 } 99 if (__rpc_rawcombuf == NULL) 100 __rpc_rawcombuf = 101 (char *)calloc(UDPMSGSIZE, sizeof (char)); 102 clp->_raw_buf = __rpc_rawcombuf; 103 clntraw_private = clp; 104 } 105 xdrs = &clp->xdr_stream; 106 client = &clp->client_object; 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 (void)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 (void)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