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