1 /* 2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 3 * unrestricted use provided that this legend is included on all tape 4 * media and as a part of the software program in whole or part. Users 5 * may copy or modify Sun RPC without charge, but are not authorized 6 * to license or distribute it to anyone else except as part of a product or 7 * program developed by the user. 8 * 9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 12 * 13 * Sun RPC is provided with no support and without any obligation on the 14 * part of Sun Microsystems, Inc. to assist in its use, correction, 15 * modification or enhancement. 16 * 17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 19 * OR ANY PART THEREOF. 20 * 21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 22 * or profits or other special, indirect and consequential damages, even if 23 * Sun has been advised of the possibility of such damages. 24 * 25 * Sun Microsystems, Inc. 26 * 2550 Garcia Avenue 27 * Mountain View, California 94043 28 * 29 * @(#)clnt_raw.c 1.22 87/08/11 Copyr 1984 Sun Micro 30 * @(#)clnt_raw.c 2.2 88/08/01 4.0 RPCSRC 31 * $NetBSD: clnt_raw.c,v 1.20 2000/12/10 04:12:03 christos Exp $ 32 * $FreeBSD: src/lib/libc/rpc/clnt_raw.c,v 1.20 2006/02/27 22:10:58 deischen Exp $ 33 */ 34 35 /* 36 * clnt_raw.c 37 * 38 * Copyright (C) 1984, Sun Microsystems, Inc. 39 * 40 * Memory based rpc for simple testing and timing. 41 * Interface to create an rpc client and server in the same process. 42 * This lets us similate rpc and get round trip overhead, without 43 * any interference from the kernel. 44 */ 45 46 #include "namespace.h" 47 #include "reentrant.h" 48 #include <assert.h> 49 #include <err.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 53 #include <rpc/rpc.h> 54 #include <rpc/raw.h> 55 #include "un-namespace.h" 56 #include "mt_misc.h" 57 58 #define MCALL_MSG_SIZE 24 59 60 /* 61 * This is the "network" we will be moving stuff over. 62 */ 63 static struct clntraw_private { 64 CLIENT client_object; 65 XDR xdr_stream; 66 char *_raw_buf; 67 union { 68 struct rpc_msg mashl_rpcmsg; 69 char mashl_callmsg[MCALL_MSG_SIZE]; 70 } u; 71 u_int mcnt; 72 } *clntraw_private; 73 74 static void clnt_raw_abort(CLIENT *); 75 static enum clnt_stat clnt_raw_call(CLIENT *, rpcproc_t, xdrproc_t, void *, 76 xdrproc_t, void *, struct timeval); 77 static bool_t clnt_raw_control(CLIENT *, u_int, void *); 78 static void clnt_raw_destroy(CLIENT *); 79 static bool_t clnt_raw_freeres(CLIENT *, xdrproc_t, void *); 80 static void clnt_raw_geterr(CLIENT *, struct rpc_err *); 81 static struct clnt_ops *clnt_raw_ops(void); 82 83 /* 84 * Create a client handle for memory based rpc. 85 */ 86 CLIENT * 87 clnt_raw_create(rpcprog_t prog, rpcvers_t vers) 88 { 89 struct clntraw_private *clp = clntraw_private; 90 struct rpc_msg call_msg; 91 XDR *xdrs = &clp->xdr_stream; 92 CLIENT *client = &clp->client_object; 93 94 mutex_lock(&clntraw_lock); 95 if (clp == NULL) { 96 clp = (struct clntraw_private *)calloc(1, sizeof (*clp)); 97 if (clp == NULL) { 98 mutex_unlock(&clntraw_lock); 99 return NULL; 100 } 101 if (__rpc_rawcombuf == NULL) 102 __rpc_rawcombuf = 103 (char *)calloc(UDPMSGSIZE, sizeof (char)); 104 clp->_raw_buf = __rpc_rawcombuf; 105 clntraw_private = clp; 106 } 107 /* 108 * pre-serialize the static part of the call msg and stash it away 109 */ 110 call_msg.rm_direction = CALL; 111 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 112 /* XXX: prog and vers have been long historically :-( */ 113 call_msg.rm_call.cb_prog = (u_int32_t)prog; 114 call_msg.rm_call.cb_vers = (u_int32_t)vers; 115 xdrmem_create(xdrs, clp->u.mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE); 116 if (! xdr_callhdr(xdrs, &call_msg)) 117 warnx("clntraw_create - Fatal header serialization error."); 118 clp->mcnt = XDR_GETPOS(xdrs); 119 XDR_DESTROY(xdrs); 120 121 /* 122 * Set xdrmem for client/server shared buffer 123 */ 124 xdrmem_create(xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE); 125 126 /* 127 * create client handle 128 */ 129 client->cl_ops = clnt_raw_ops(); 130 client->cl_auth = authnone_create(); 131 mutex_unlock(&clntraw_lock); 132 return (client); 133 } 134 135 /* ARGSUSED */ 136 static enum clnt_stat 137 clnt_raw_call(CLIENT *h, rpcproc_t proc, xdrproc_t xargs, void *argsp, 138 xdrproc_t xresults, void *resultsp, 139 struct timeval timeout __unused) 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 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 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 __unused, struct rpc_err *err __unused) 231 { 232 } 233 234 235 /* ARGSUSED */ 236 static bool_t 237 clnt_raw_freeres(CLIENT *cl __unused, 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 __unused) 257 { 258 } 259 260 /*ARGSUSED*/ 261 static bool_t 262 clnt_raw_control(CLIENT *cl __unused, u_int ui __unused, void *str __unused) 263 { 264 return (FALSE); 265 } 266 267 /*ARGSUSED*/ 268 static void 269 clnt_raw_destroy(CLIENT *cl __unused) 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