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 23 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 /* 30 * Portions of this source code were derived from Berkeley 31 * 4.3 BSD under license from the Regents of the University of 32 * California. 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 /* 38 * clnt_raw.c 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 #include "mt.h" 46 #include "rpc_mt.h" 47 #include <stdlib.h> 48 #include <rpc/rpc.h> 49 #include <rpc/raw.h> 50 #include <syslog.h> 51 52 extern mutex_t clntraw_lock; 53 #define MCALL_MSG_SIZE 24 54 #ifndef UDPMSGSIZE 55 #define UDPMSGSIZE 8800 56 #endif 57 58 /* 59 * This is the "network" we will be moving stuff over. 60 */ 61 static struct clnt_raw_private { 62 CLIENT client_object; 63 XDR xdr_stream; 64 char *raw_buf; /* should be shared with server handle */ 65 char mashl_callmsg[MCALL_MSG_SIZE]; 66 uint_t mcnt; 67 } *clnt_raw_private; 68 69 static struct clnt_ops *clnt_raw_ops(); 70 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(const rpcprog_t prog, const 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 (void) mutex_lock(&clntraw_lock); 88 clp = clnt_raw_private; 89 if (clp == NULL) { 90 clp = calloc(1, sizeof (*clp)); 91 if (clp == NULL) { 92 (void) mutex_unlock(&clntraw_lock); 93 return (NULL); 94 } 95 if (_rawcombuf == NULL) { 96 _rawcombuf = calloc(UDPMSGSIZE, sizeof (char)); 97 if (_rawcombuf == NULL) { 98 syslog(LOG_ERR, "clnt_raw_create: " 99 "out of memory."); 100 if (clp) 101 free(clp); 102 (void) mutex_unlock(&clntraw_lock); 103 return (NULL); 104 } 105 } 106 clp->raw_buf = _rawcombuf; /* Share it with the server */ 107 clnt_raw_private = clp; 108 } 109 xdrs = &clp->xdr_stream; 110 client = &clp->client_object; 111 112 /* 113 * pre-serialize the static part of the call msg and stash it away 114 */ 115 call_msg.rm_direction = CALL; 116 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 117 call_msg.rm_call.cb_prog = prog; 118 call_msg.rm_call.cb_vers = vers; 119 xdrmem_create(xdrs, clp->mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE); 120 if (!xdr_callhdr(xdrs, &call_msg)) 121 (void) syslog(LOG_ERR, 122 (const char *) "clnt_raw_create : \ 123 Fatal header serialization error."); 124 125 clp->mcnt = XDR_GETPOS(xdrs); 126 XDR_DESTROY(xdrs); 127 128 /* 129 * Set xdrmem for client/server shared buffer 130 */ 131 xdrmem_create(xdrs, clp->raw_buf, UDPMSGSIZE, XDR_FREE); 132 133 /* 134 * create client handle 135 */ 136 client->cl_ops = clnt_raw_ops(); 137 client->cl_auth = authnone_create(); 138 (void) mutex_unlock(&clntraw_lock); 139 return (client); 140 } 141 142 /*ARGSUSED*/ 143 static enum clnt_stat 144 clnt_raw_call(CLIENT *h, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp, 145 xdrproc_t xresults, caddr_t resultsp, struct timeval timeout) 146 { 147 struct clnt_raw_private *clp; 148 XDR *xdrs; 149 struct rpc_msg msg; 150 enum clnt_stat status; 151 struct rpc_err error; 152 153 (void) mutex_lock(&clntraw_lock); 154 clp = clnt_raw_private; 155 xdrs = &clp->xdr_stream; 156 if (clp == NULL) { 157 (void) mutex_unlock(&clntraw_lock); 158 return (RPC_FAILED); 159 } 160 (void) mutex_unlock(&clntraw_lock); 161 162 call_again: 163 /* 164 * send request 165 */ 166 xdrs->x_op = XDR_ENCODE; 167 XDR_SETPOS(xdrs, 0); 168 /* LINTED pointer alignment */ 169 ((struct rpc_msg *)clp->mashl_callmsg)->rm_xid++; 170 if ((!XDR_PUTBYTES(xdrs, clp->mashl_callmsg, clp->mcnt)) || 171 (!XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 172 (!AUTH_MARSHALL(h->cl_auth, xdrs)) || 173 (!(*xargs)(xdrs, argsp))) 174 return (RPC_CANTENCODEARGS); 175 (void) XDR_GETPOS(xdrs); /* called just to cause overhead */ 176 177 /* 178 * We have to call server input routine here because this is 179 * all going on in one process. 180 * By convention using FD_SETSIZE as the psuedo file descriptor. 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 return (RPC_CANTDECODERES); 194 if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) && 195 (msg.acpted_rply.ar_stat == SUCCESS)) 196 status = RPC_SUCCESS; 197 else { 198 __seterr_reply(&msg, &error); 199 status = error.re_status; 200 } 201 202 if (status == RPC_SUCCESS) { 203 if (!AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { 204 status = RPC_AUTHERROR; 205 } 206 /* end successful completion */ 207 } else { 208 if (AUTH_REFRESH(h->cl_auth, &msg)) 209 goto call_again; 210 /* end of unsuccessful completion */ 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 if (msg.acpted_rply.ar_verf.oa_base != NULL) { 218 xdrs->x_op = XDR_FREE; 219 (void) xdr_opaque_auth(xdrs, 220 &(msg.acpted_rply.ar_verf)); 221 } 222 } 223 return (status); 224 } 225 226 /*ARGSUSED*/ 227 static enum clnt_stat 228 clnt_raw_send(CLIENT *h, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp) 229 { 230 struct clnt_raw_private *clp; 231 XDR *xdrs; 232 233 (void) mutex_lock(&clntraw_lock); 234 clp = clnt_raw_private; 235 xdrs = &clp->xdr_stream; 236 if (clp == NULL) { 237 (void) mutex_unlock(&clntraw_lock); 238 return (RPC_FAILED); 239 } 240 (void) mutex_unlock(&clntraw_lock); 241 242 /* 243 * send request 244 */ 245 xdrs->x_op = XDR_ENCODE; 246 XDR_SETPOS(xdrs, 0); 247 /* LINTED pointer alignment */ 248 ((struct rpc_msg *)clp->mashl_callmsg)->rm_xid++; 249 if ((!XDR_PUTBYTES(xdrs, clp->mashl_callmsg, clp->mcnt)) || 250 (!XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 251 (!AUTH_MARSHALL(h->cl_auth, xdrs)) || 252 (!(*xargs)(xdrs, argsp))) 253 return (RPC_CANTENCODEARGS); 254 (void) XDR_GETPOS(xdrs); /* called just to cause overhead */ 255 256 /* 257 * We have to call server input routine here because this is 258 * all going on in one process. 259 * By convention using FD_SETSIZE as the psuedo file descriptor. 260 */ 261 svc_getreq_common(FD_SETSIZE); 262 263 return (RPC_SUCCESS); 264 } 265 266 /*ARGSUSED*/ 267 static void 268 clnt_raw_geterr(CLIENT *cl, struct rpc_err *errp) 269 { 270 } 271 272 /*ARGSUSED*/ 273 static bool_t 274 clnt_raw_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) 275 { 276 struct clnt_raw_private *clp; 277 XDR *xdrs; 278 279 (void) mutex_lock(&clntraw_lock); 280 clp = clnt_raw_private; 281 xdrs = &clp->xdr_stream; 282 if (clp == NULL) { 283 (void) mutex_unlock(&clntraw_lock); 284 return (FALSE); 285 } 286 (void) mutex_unlock(&clntraw_lock); 287 xdrs->x_op = XDR_FREE; 288 return ((*xdr_res)(xdrs, res_ptr)); 289 } 290 291 /*ARGSUSED*/ 292 static void 293 clnt_raw_abort(CLIENT *cl, struct rpc_err *errp) 294 { 295 } 296 297 /*ARGSUSED*/ 298 static bool_t 299 clnt_raw_control(CLIENT *cl, int request, char *info) 300 { 301 return (FALSE); 302 } 303 304 /*ARGSUSED*/ 305 static void 306 clnt_raw_destroy(CLIENT *cl) 307 { 308 } 309 310 static struct clnt_ops * 311 clnt_raw_ops(void) 312 { 313 static struct clnt_ops ops; 314 extern mutex_t ops_lock; 315 316 /* VARIABLES PROTECTED BY ops_lock: ops */ 317 318 (void) mutex_lock(&ops_lock); 319 if (ops.cl_call == NULL) { 320 ops.cl_call = clnt_raw_call; 321 ops.cl_send = clnt_raw_send; 322 ops.cl_abort = clnt_raw_abort; 323 ops.cl_geterr = clnt_raw_geterr; 324 ops.cl_freeres = clnt_raw_freeres; 325 ops.cl_destroy = clnt_raw_destroy; 326 ops.cl_control = clnt_raw_control; 327 } 328 (void) mutex_unlock(&ops_lock); 329 return (&ops); 330 } 331