1 /* $NetBSD: clnt_raw.c,v 1.30 2012/03/20 17:14:50 matt Exp $ */ 2 3 /* 4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5 * unrestricted use provided that this legend is included on all tape 6 * media and as a part of the software program in whole or part. Users 7 * may copy or modify Sun RPC without charge, but are not authorized 8 * to license or distribute it to anyone else except as part of a product or 9 * program developed by the user. 10 * 11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 14 * 15 * Sun RPC is provided with no support and without any obligation on the 16 * part of Sun Microsystems, Inc. to assist in its use, correction, 17 * modification or enhancement. 18 * 19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 21 * OR ANY PART THEREOF. 22 * 23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24 * or profits or other special, indirect and consequential damages, even if 25 * Sun has been advised of the possibility of such damages. 26 * 27 * Sun Microsystems, Inc. 28 * 2550 Garcia Avenue 29 * Mountain View, California 94043 30 */ 31 32 #include <sys/cdefs.h> 33 #if defined(LIBC_SCCS) && !defined(lint) 34 #if 0 35 static char *sccsid = "@(#)clnt_raw.c 1.22 87/08/11 Copyr 1984 Sun Micro"; 36 static char *sccsid = "@(#)clnt_raw.c 2.2 88/08/01 4.0 RPCSRC"; 37 #else 38 __RCSID("$NetBSD: clnt_raw.c,v 1.30 2012/03/20 17:14:50 matt Exp $"); 39 #endif 40 #endif 41 42 /* 43 * clnt_raw.c 44 * 45 * Copyright (C) 1984, Sun Microsystems, Inc. 46 * 47 * Memory based rpc for simple testing and timing. 48 * Interface to create an rpc client and server in the same process. 49 * This lets us similate rpc and get round trip overhead, without 50 * any interference from the kernel. 51 */ 52 53 #include "namespace.h" 54 #include "reentrant.h" 55 #include <assert.h> 56 #include <err.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 60 #include <rpc/rpc.h> 61 #include <rpc/raw.h> 62 63 #ifdef __weak_alias 64 __weak_alias(clntraw_create,_clntraw_create) 65 __weak_alias(clnt_raw_create,_clnt_raw_create) 66 #endif 67 68 #ifdef _REENTRANT 69 extern mutex_t clntraw_lock; 70 #endif 71 72 #define MCALL_MSG_SIZE 24 73 74 /* 75 * This is the "network" we will be moving stuff over. 76 */ 77 static struct clntraw_private { 78 CLIENT client_object; 79 XDR xdr_stream; 80 char *_raw_buf; 81 union { 82 struct rpc_msg mashl_rpcmsg; 83 char mashl_callmsg[MCALL_MSG_SIZE]; 84 } u; 85 u_int mcnt; 86 } *clntraw_private; 87 88 static enum clnt_stat clnt_raw_call(CLIENT *, rpcproc_t, xdrproc_t, 89 const char *, xdrproc_t, caddr_t, struct timeval); 90 static void clnt_raw_geterr(CLIENT *, struct rpc_err *); 91 static bool_t clnt_raw_freeres(CLIENT *, xdrproc_t, caddr_t); 92 static void clnt_raw_abort(CLIENT *); 93 static bool_t clnt_raw_control(CLIENT *, u_int, char *); 94 static void clnt_raw_destroy(CLIENT *); 95 static struct clnt_ops *clnt_raw_ops(void); 96 97 /* 98 * Create a client handle for memory based rpc. 99 */ 100 CLIENT * 101 clnt_raw_create(rpcprog_t prog, rpcvers_t vers) 102 { 103 struct clntraw_private *clp = clntraw_private; 104 struct rpc_msg call_msg; 105 XDR *xdrs = &clp->xdr_stream; 106 CLIENT *client = &clp->client_object; 107 108 mutex_lock(&clntraw_lock); 109 if (clp == NULL) { 110 clp = calloc((size_t)1, sizeof (*clp)); 111 if (clp == NULL) 112 goto out; 113 if (__rpc_rawcombuf == NULL) 114 __rpc_rawcombuf = 115 malloc(UDPMSGSIZE); 116 if (__rpc_rawcombuf == NULL) 117 goto out; 118 clp->_raw_buf = __rpc_rawcombuf; 119 clntraw_private = clp; 120 } 121 /* 122 * pre-serialize the static part of the call msg and stash it away 123 */ 124 call_msg.rm_direction = CALL; 125 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 126 /* XXX: prog and vers have been long historically :-( */ 127 call_msg.rm_call.cb_prog = (u_int32_t)prog; 128 call_msg.rm_call.cb_vers = (u_int32_t)vers; 129 xdrmem_create(xdrs, clp->u.mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE); 130 if (! xdr_callhdr(xdrs, &call_msg)) 131 warnx("clntraw_create - Fatal header serialization error."); 132 clp->mcnt = XDR_GETPOS(xdrs); 133 XDR_DESTROY(xdrs); 134 135 /* 136 * Set xdrmem for client/server shared buffer 137 */ 138 xdrmem_create(xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE); 139 140 /* 141 * create client handle 142 */ 143 client->cl_ops = clnt_raw_ops(); 144 client->cl_auth = authnone_create(); 145 mutex_unlock(&clntraw_lock); 146 return (client); 147 out: 148 if (clp) 149 free(clp); 150 mutex_unlock(&clntraw_lock); 151 return NULL; 152 153 } 154 155 /* ARGSUSED */ 156 static enum clnt_stat 157 clnt_raw_call(CLIENT *h, rpcproc_t proc, xdrproc_t xargs, const char *argsp, 158 xdrproc_t xresults, caddr_t resultsp, struct timeval timeout) 159 { 160 struct clntraw_private *clp = clntraw_private; 161 XDR *xdrs = &clp->xdr_stream; 162 struct rpc_msg msg; 163 enum clnt_stat status; 164 struct rpc_err error; 165 166 _DIAGASSERT(h != NULL); 167 168 mutex_lock(&clntraw_lock); 169 if (clp == NULL) { 170 mutex_unlock(&clntraw_lock); 171 return (RPC_FAILED); 172 } 173 mutex_unlock(&clntraw_lock); 174 175 call_again: 176 /* 177 * send request 178 */ 179 xdrs->x_op = XDR_ENCODE; 180 XDR_SETPOS(xdrs, 0); 181 clp->u.mashl_rpcmsg.rm_xid ++ ; 182 if ((! XDR_PUTBYTES(xdrs, clp->u.mashl_callmsg, clp->mcnt)) || 183 (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 184 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 185 (! (*xargs)(xdrs, __UNCONST(argsp)))) { 186 return (RPC_CANTENCODEARGS); 187 } 188 (void)XDR_GETPOS(xdrs); /* called just to cause overhead */ 189 190 /* 191 * We have to call server input routine here because this is 192 * all going on in one process. Yuk. 193 */ 194 svc_getreq_common(FD_SETSIZE); 195 196 /* 197 * get results 198 */ 199 xdrs->x_op = XDR_DECODE; 200 XDR_SETPOS(xdrs, 0); 201 msg.acpted_rply.ar_verf = _null_auth; 202 msg.acpted_rply.ar_results.where = resultsp; 203 msg.acpted_rply.ar_results.proc = xresults; 204 if (! xdr_replymsg(xdrs, &msg)) { 205 /* 206 * It's possible for xdr_replymsg() to fail partway 207 * through its attempt to decode the result from the 208 * server. If this happens, it will leave the reply 209 * structure partially populated with dynamically 210 * allocated memory. (This can happen if someone uses 211 * clntudp_bufcreate() to create a CLIENT handle and 212 * specifies a receive buffer size that is too small.) 213 * This memory must be free()ed to avoid a leak. 214 */ 215 int op = xdrs->x_op; 216 xdrs->x_op = XDR_FREE; 217 xdr_replymsg(xdrs, &msg); 218 xdrs->x_op = op; 219 return (RPC_CANTDECODERES); 220 } 221 _seterr_reply(&msg, &error); 222 status = error.re_status; 223 224 if (status == RPC_SUCCESS) { 225 if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { 226 status = RPC_AUTHERROR; 227 } 228 } /* end successful completion */ 229 else { 230 if (AUTH_REFRESH(h->cl_auth)) 231 goto call_again; 232 } /* end of unsuccessful completion */ 233 234 if (status == RPC_SUCCESS) { 235 if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { 236 status = RPC_AUTHERROR; 237 } 238 if (msg.acpted_rply.ar_verf.oa_base != NULL) { 239 xdrs->x_op = XDR_FREE; 240 (void)xdr_opaque_auth(xdrs, &(msg.acpted_rply.ar_verf)); 241 } 242 } 243 244 return (status); 245 } 246 247 /*ARGSUSED*/ 248 static void 249 clnt_raw_geterr(CLIENT *cl, struct rpc_err *error) 250 { 251 } 252 253 254 /* ARGSUSED */ 255 static bool_t 256 clnt_raw_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) 257 { 258 struct clntraw_private *clp = clntraw_private; 259 XDR *xdrs = &clp->xdr_stream; 260 bool_t rval; 261 262 mutex_lock(&clntraw_lock); 263 if (clp == NULL) { 264 rval = (bool_t) RPC_FAILED; 265 mutex_unlock(&clntraw_lock); 266 return (rval); 267 } 268 mutex_unlock(&clntraw_lock); 269 xdrs->x_op = XDR_FREE; 270 return ((*xdr_res)(xdrs, res_ptr)); 271 } 272 273 /*ARGSUSED*/ 274 static void 275 clnt_raw_abort(CLIENT *cl) 276 { 277 } 278 279 /*ARGSUSED*/ 280 static bool_t 281 clnt_raw_control(CLIENT *cl, u_int ui, char *str) 282 { 283 return (FALSE); 284 } 285 286 /*ARGSUSED*/ 287 static void 288 clnt_raw_destroy(CLIENT *cl) 289 { 290 } 291 292 static struct clnt_ops * 293 clnt_raw_ops(void) 294 { 295 static struct clnt_ops ops; 296 #ifdef _REENTRANT 297 extern mutex_t ops_lock; 298 #endif 299 300 /* VARIABLES PROTECTED BY ops_lock: ops */ 301 302 mutex_lock(&ops_lock); 303 if (ops.cl_call == NULL) { 304 ops.cl_call = clnt_raw_call; 305 ops.cl_abort = clnt_raw_abort; 306 ops.cl_geterr = clnt_raw_geterr; 307 ops.cl_freeres = clnt_raw_freeres; 308 ops.cl_destroy = clnt_raw_destroy; 309 ops.cl_control = clnt_raw_control; 310 } 311 mutex_unlock(&ops_lock); 312 return (&ops); 313 } 314