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