1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 * 22 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 26 /* All Rights Reserved */ 27 /* 28 * Portions of this source code were derived from Berkeley 29 * 4.3 BSD under license from the Regents of the University of 30 * California. 31 */ 32 33 #pragma ident "%Z%%M% %I% %E% SMI" 34 35 /* 36 * clnt_raw.c 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 #include "mt.h" 44 #include "rpc_mt.h" 45 #include <rpc/rpc.h> 46 #include <rpc/trace.h> 47 #include <rpc/raw.h> 48 #include <syslog.h> 49 50 extern mutex_t clntraw_lock; 51 #define MCALL_MSG_SIZE 24 52 #ifndef UDPMSGSIZE 53 #define UDPMSGSIZE 8800 54 #endif 55 56 /* 57 * This is the "network" we will be moving stuff over. 58 */ 59 static struct clnt_raw_private { 60 CLIENT client_object; 61 XDR xdr_stream; 62 char *raw_buf; /* should be shared with server handle */ 63 char mashl_callmsg[MCALL_MSG_SIZE]; 64 uint_t mcnt; 65 } *clnt_raw_private; 66 67 static struct clnt_ops *clnt_raw_ops(); 68 69 extern char *calloc(); 70 extern void free(); 71 extern void svc_getreq_common(int); 72 extern bool_t xdr_opaque_auth(); 73 74 /* 75 * Create a client handle for memory based rpc. 76 */ 77 CLIENT * 78 clnt_raw_create(rpcprog_t prog, rpcvers_t vers) 79 { 80 struct clnt_raw_private *clp; 81 struct rpc_msg call_msg; 82 XDR *xdrs; 83 CLIENT *client; 84 85 /* VARIABLES PROTECTED BY clntraw_lock: clp */ 86 87 trace3(TR_clnt_raw_create, 0, prog, vers); 88 mutex_lock(&clntraw_lock); 89 clp = clnt_raw_private; 90 if (clp == NULL) { 91 /* LINTED pointer alignment */ 92 clp = (struct clnt_raw_private *)calloc(1, sizeof (*clp)); 93 if (clp == NULL) { 94 mutex_unlock(&clntraw_lock); 95 trace3(TR_clnt_raw_create, 1, prog, vers); 96 return ((CLIENT *)NULL); 97 } 98 if (_rawcombuf == NULL) { 99 _rawcombuf = (char *)calloc(UDPMSGSIZE, sizeof (char)); 100 if (_rawcombuf == NULL) { 101 syslog(LOG_ERR, "clnt_raw_create: " 102 "out of memory."); 103 if (clp) 104 free(clp); 105 mutex_unlock(&clntraw_lock); 106 trace3(TR_clnt_raw_create, 1, prog, vers); 107 return ((CLIENT *)NULL); 108 } 109 } 110 clp->raw_buf = _rawcombuf; /* Share it with the server */ 111 clnt_raw_private = clp; 112 } 113 xdrs = &clp->xdr_stream; 114 client = &clp->client_object; 115 116 /* 117 * pre-serialize the static part of the call msg and stash it away 118 */ 119 call_msg.rm_direction = CALL; 120 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 121 call_msg.rm_call.cb_prog = prog; 122 call_msg.rm_call.cb_vers = vers; 123 xdrmem_create(xdrs, clp->mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE); 124 if (! xdr_callhdr(xdrs, &call_msg)) 125 (void) syslog(LOG_ERR, 126 (const char *) "clnt_raw_create : \ 127 Fatal header serialization error."); 128 129 clp->mcnt = XDR_GETPOS(xdrs); 130 XDR_DESTROY(xdrs); 131 132 /* 133 * Set xdrmem for client/server shared buffer 134 */ 135 xdrmem_create(xdrs, clp->raw_buf, UDPMSGSIZE, XDR_FREE); 136 137 /* 138 * create client handle 139 */ 140 client->cl_ops = clnt_raw_ops(); 141 client->cl_auth = authnone_create(); 142 mutex_unlock(&clntraw_lock); 143 trace3(TR_clnt_raw_create, 1, prog, vers); 144 return (client); 145 } 146 147 /*ARGSUSED*/ 148 static enum clnt_stat 149 clnt_raw_call(CLIENT *h, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp, 150 xdrproc_t xresults, caddr_t resultsp, struct timeval timeout) 151 { 152 struct clnt_raw_private *clp; 153 XDR *xdrs; 154 struct rpc_msg msg; 155 enum clnt_stat status; 156 struct rpc_err error; 157 158 trace3(TR_clnt_raw_call, 0, h, proc); 159 mutex_lock(&clntraw_lock); 160 clp = clnt_raw_private; 161 xdrs = &clp->xdr_stream; 162 if (clp == NULL) { 163 mutex_unlock(&clntraw_lock); 164 trace3(TR_clnt_raw_call, 1, h, proc); 165 return (RPC_FAILED); 166 } 167 mutex_unlock(&clntraw_lock); 168 169 call_again: 170 /* 171 * send request 172 */ 173 xdrs->x_op = XDR_ENCODE; 174 XDR_SETPOS(xdrs, 0); 175 /* LINTED pointer alignment */ 176 ((struct rpc_msg *)clp->mashl_callmsg)->rm_xid++; 177 if ((! XDR_PUTBYTES(xdrs, clp->mashl_callmsg, clp->mcnt)) || 178 (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 179 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 180 (! (*xargs)(xdrs, argsp))) { 181 trace3(TR_clnt_raw_call, 1, h, proc); 182 return (RPC_CANTENCODEARGS); 183 } 184 (void) XDR_GETPOS(xdrs); /* called just to cause overhead */ 185 186 /* 187 * We have to call server input routine here because this is 188 * all going on in one process. 189 * By convention using FD_SETSIZE as the psuedo file descriptor. 190 */ 191 svc_getreq_common(FD_SETSIZE); 192 193 /* 194 * get results 195 */ 196 xdrs->x_op = XDR_DECODE; 197 XDR_SETPOS(xdrs, 0); 198 msg.acpted_rply.ar_verf = _null_auth; 199 msg.acpted_rply.ar_results.where = resultsp; 200 msg.acpted_rply.ar_results.proc = xresults; 201 if (! xdr_replymsg(xdrs, &msg)) { 202 trace3(TR_clnt_raw_call, 1, h, proc); 203 return (RPC_CANTDECODERES); 204 } 205 if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) && 206 (msg.acpted_rply.ar_stat == SUCCESS)) 207 status = RPC_SUCCESS; 208 else { 209 __seterr_reply(&msg, &error); 210 status = error.re_status; 211 } 212 213 if (status == RPC_SUCCESS) { 214 if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { 215 status = RPC_AUTHERROR; 216 } 217 /* end successful completion */ 218 } else { 219 if (AUTH_REFRESH(h->cl_auth, &msg)) 220 goto call_again; 221 /* end of unsuccessful completion */ 222 } 223 224 if (status == RPC_SUCCESS) { 225 if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { 226 status = RPC_AUTHERROR; 227 } 228 if (msg.acpted_rply.ar_verf.oa_base != NULL) { 229 xdrs->x_op = XDR_FREE; 230 (void) xdr_opaque_auth(xdrs, 231 &(msg.acpted_rply.ar_verf)); 232 } 233 } 234 trace3(TR_clnt_raw_call, 1, h, proc); 235 return (status); 236 } 237 238 /*ARGSUSED*/ 239 static enum clnt_stat 240 clnt_raw_send(CLIENT *h, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp) 241 { 242 struct clnt_raw_private *clp; 243 XDR *xdrs; 244 245 trace3(TR_clnt_raw_send, 0, h, proc); 246 247 mutex_lock(&clntraw_lock); 248 clp = clnt_raw_private; 249 xdrs = &clp->xdr_stream; 250 if (clp == NULL) { 251 mutex_unlock(&clntraw_lock); 252 trace3(TR_clnt_raw_send, 1, h, proc); 253 return (RPC_FAILED); 254 } 255 mutex_unlock(&clntraw_lock); 256 257 /* 258 * send request 259 */ 260 xdrs->x_op = XDR_ENCODE; 261 XDR_SETPOS(xdrs, 0); 262 /* LINTED pointer alignment */ 263 ((struct rpc_msg *)clp->mashl_callmsg)->rm_xid++; 264 if ((! XDR_PUTBYTES(xdrs, clp->mashl_callmsg, clp->mcnt)) || 265 (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 266 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 267 (! (*xargs)(xdrs, argsp))) { 268 trace3(TR_clnt_raw_send, 1, h, proc); 269 return (RPC_CANTENCODEARGS); 270 } 271 (void) XDR_GETPOS(xdrs); /* called just to cause overhead */ 272 273 /* 274 * We have to call server input routine here because this is 275 * all going on in one process. 276 * By convention using FD_SETSIZE as the psuedo file descriptor. 277 */ 278 svc_getreq_common(FD_SETSIZE); 279 280 return (RPC_SUCCESS); 281 } 282 283 /*ARGSUSED*/ 284 static void 285 clnt_raw_geterr(CLIENT *cl, struct rpc_err *errp) 286 { 287 trace1(TR_clnt_raw_geterr, 0); 288 trace1(TR_clnt_raw_geterr, 1); 289 } 290 291 /*ARGSUSED*/ 292 static bool_t 293 clnt_raw_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) 294 { 295 struct clnt_raw_private *clp; 296 XDR *xdrs; 297 static bool_t dummy; 298 299 trace2(TR_clnt_raw_freeres, 0, cl); 300 mutex_lock(&clntraw_lock); 301 clp = clnt_raw_private; 302 xdrs = &clp->xdr_stream; 303 if (clp == NULL) { 304 mutex_unlock(&clntraw_lock); 305 trace2(TR_clnt_raw_freeres, 1, cl); 306 return (FALSE); 307 } 308 mutex_unlock(&clntraw_lock); 309 xdrs->x_op = XDR_FREE; 310 dummy = (*xdr_res)(xdrs, res_ptr); 311 trace2(TR_clnt_raw_freeres, 1, cl); 312 return (dummy); 313 } 314 315 /*ARGSUSED*/ 316 static void 317 clnt_raw_abort(CLIENT *cl, struct rpc_err *errp) 318 { 319 trace1(TR_clnt_raw_abort, 0); 320 trace1(TR_clnt_raw_abort, 1); 321 } 322 323 /*ARGSUSED*/ 324 static bool_t 325 clnt_raw_control(CLIENT *cl, int request, char *info) 326 { 327 trace1(TR_clnt_raw_control, 0); 328 trace1(TR_clnt_raw_control, 1); 329 return (FALSE); 330 } 331 332 /*ARGSUSED*/ 333 static void 334 clnt_raw_destroy(CLIENT *cl) 335 { 336 trace1(TR_clnt_raw_destroy, 0); 337 trace1(TR_clnt_raw_destroy, 1); 338 } 339 340 static struct clnt_ops * 341 clnt_raw_ops(void) 342 { 343 static struct clnt_ops ops; 344 extern mutex_t ops_lock; 345 346 /* VARIABLES PROTECTED BY ops_lock: ops */ 347 348 trace1(TR_clnt_raw_ops, 0); 349 mutex_lock(&ops_lock); 350 if (ops.cl_call == NULL) { 351 ops.cl_call = clnt_raw_call; 352 ops.cl_send = clnt_raw_send; 353 ops.cl_abort = clnt_raw_abort; 354 ops.cl_geterr = clnt_raw_geterr; 355 ops.cl_freeres = clnt_raw_freeres; 356 ops.cl_destroy = clnt_raw_destroy; 357 ops.cl_control = clnt_raw_control; 358 } 359 mutex_unlock(&ops_lock); 360 trace1(TR_clnt_raw_ops, 1); 361 return (&ops); 362 } 363