1219820Sjeff/* $NetBSD: svc_simple.c,v 1.20 2000/07/06 03:10:35 christos Exp $ */ 2219820Sjeff 3219820Sjeff/*- 4219820Sjeff * Copyright (c) 2009, Sun Microsystems, Inc. 5219820Sjeff * All rights reserved. 6219820Sjeff * 7219820Sjeff * Redistribution and use in source and binary forms, with or without 8219820Sjeff * modification, are permitted provided that the following conditions are met: 9219820Sjeff * - Redistributions of source code must retain the above copyright notice, 10219820Sjeff * this list of conditions and the following disclaimer. 11219820Sjeff * - Redistributions in binary form must reproduce the above copyright notice, 12219820Sjeff * this list of conditions and the following disclaimer in the documentation 13219820Sjeff * and/or other materials provided with the distribution. 14219820Sjeff * - Neither the name of Sun Microsystems, Inc. nor the names of its 15219820Sjeff * contributors may be used to endorse or promote products derived 16219820Sjeff * from this software without specific prior written permission. 17219820Sjeff * 18219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19219820Sjeff * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20219820Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21219820Sjeff * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22219820Sjeff * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23219820Sjeff * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24219820Sjeff * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25219820Sjeff * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26219820Sjeff * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27219820Sjeff * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28219820Sjeff * POSSIBILITY OF SUCH DAMAGE. 29219820Sjeff */ 30219820Sjeff/* 31219820Sjeff * Copyright (c) 1986-1991 by Sun Microsystems Inc. 32219820Sjeff */ 33219820Sjeff 34219820Sjeff/* #pragma ident "@(#)svc_simple.c 1.18 94/04/24 SMI" */ 35219820Sjeff#include <sys/cdefs.h> 36219820Sjeff__FBSDID("$FreeBSD$"); 37219820Sjeff 38219820Sjeff/* 39219820Sjeff * svc_simple.c 40219820Sjeff * Simplified front end to rpc. 41219820Sjeff */ 42219820Sjeff 43219820Sjeff/* 44219820Sjeff * This interface creates a virtual listener for all the services 45219820Sjeff * started through rpc_reg(). It listens on the same endpoint for 46219820Sjeff * all the services and then executes the corresponding service 47219820Sjeff * for the given prognum and procnum. 48219820Sjeff */ 49219820Sjeff 50219820Sjeff#include "namespace.h" 51219820Sjeff#include "reentrant.h" 52219820Sjeff#include <sys/types.h> 53219820Sjeff#include <rpc/rpc.h> 54219820Sjeff#include <rpc/nettype.h> 55219820Sjeff#include <stdio.h> 56219820Sjeff#include <stdlib.h> 57219820Sjeff#include <string.h> 58219820Sjeff#include <err.h> 59219820Sjeff#include "un-namespace.h" 60219820Sjeff 61219820Sjeff#include "rpc_com.h" 62219820Sjeff#include "mt_misc.h" 63219820Sjeff 64219820Sjeffstatic void universal(struct svc_req *, SVCXPRT *); 65219820Sjeff 66219820Sjeffstatic struct proglst { 67219820Sjeff char *(*p_progname)(char *); 68219820Sjeff rpcprog_t p_prognum; 69219820Sjeff rpcvers_t p_versnum; 70219820Sjeff rpcproc_t p_procnum; 71219820Sjeff SVCXPRT *p_transp; 72219820Sjeff char *p_netid; 73219820Sjeff char *p_xdrbuf; 74219820Sjeff int p_recvsz; 75219820Sjeff xdrproc_t p_inproc, p_outproc; 76219820Sjeff struct proglst *p_nxt; 77219820Sjeff} *proglst; 78219820Sjeff 79219820Sjeffstatic const char rpc_reg_err[] = "%s: %s"; 80219820Sjeffstatic const char rpc_reg_msg[] = "rpc_reg: "; 81219820Sjeffstatic const char __reg_err1[] = "can't find appropriate transport"; 82219820Sjeffstatic const char __reg_err2[] = "can't get protocol info"; 83219820Sjeffstatic const char __reg_err3[] = "unsupported transport size"; 84219820Sjeffstatic const char __no_mem_str[] = "out of memory"; 85219820Sjeff 86219820Sjeff/* 87219820Sjeff * For simplified, easy to use kind of rpc interfaces. 88219820Sjeff * nettype indicates the type of transport on which the service will be 89219820Sjeff * listening. Used for conservation of the system resource. Only one 90219820Sjeff * handle is created for all the services (actually one of each netid) 91219820Sjeff * and same xdrbuf is used for same netid. The size of the arguments 92219820Sjeff * is also limited by the recvsize for that transport, even if it is 93219820Sjeff * a COTS transport. This may be wrong, but for cases like these, they 94219820Sjeff * should not use the simplified interfaces like this. 95219820Sjeff * 96219820Sjeff * prognum - program number 97219820Sjeff * versnum - version number 98219820Sjeff * procnum - procedure number 99219820Sjeff * progname - Server routine 100219820Sjeff * inproc, outproc - in/out XDR procedures 101219820Sjeff * nettype - nettype 102219820Sjeff */ 103219820Sjeffint 104219820Sjeffrpc_reg(rpcprog_t prognum, rpcvers_t versnum, rpcproc_t procnum, 105219820Sjeff char *(*progname)(char *), xdrproc_t inproc, xdrproc_t outproc, 106219820Sjeff char *nettype) 107219820Sjeff{ 108219820Sjeff struct netconfig *nconf; 109219820Sjeff int done = FALSE; 110219820Sjeff void *handle; 111219820Sjeff 112219820Sjeff 113219820Sjeff if (procnum == NULLPROC) { 114219820Sjeff warnx("%s can't reassign procedure number %u", rpc_reg_msg, 115219820Sjeff NULLPROC); 116219820Sjeff return (-1); 117219820Sjeff } 118219820Sjeff 119219820Sjeff if (nettype == NULL) 120219820Sjeff nettype = "netpath"; /* The default behavior */ 121219820Sjeff if ((handle = __rpc_setconf(nettype)) == NULL) { 122219820Sjeff warnx(rpc_reg_err, rpc_reg_msg, __reg_err1); 123219820Sjeff return (-1); 124219820Sjeff } 125219820Sjeff/* VARIABLES PROTECTED BY proglst_lock: proglst */ 126219820Sjeff mutex_lock(&proglst_lock); 127219820Sjeff while ((nconf = __rpc_getconf(handle)) != NULL) { 128219820Sjeff struct proglst *pl; 129219820Sjeff SVCXPRT *svcxprt; 130219820Sjeff int madenow; 131219820Sjeff u_int recvsz; 132219820Sjeff char *xdrbuf; 133219820Sjeff char *netid; 134219820Sjeff 135219820Sjeff madenow = FALSE; 136219820Sjeff svcxprt = NULL; 137219820Sjeff recvsz = 0; 138219820Sjeff xdrbuf = netid = NULL; 139219820Sjeff for (pl = proglst; pl; pl = pl->p_nxt) { 140219820Sjeff if (strcmp(pl->p_netid, nconf->nc_netid) == 0) { 141219820Sjeff svcxprt = pl->p_transp; 142219820Sjeff xdrbuf = pl->p_xdrbuf; 143219820Sjeff recvsz = pl->p_recvsz; 144219820Sjeff netid = pl->p_netid; 145219820Sjeff break; 146219820Sjeff } 147219820Sjeff } 148219820Sjeff 149219820Sjeff if (svcxprt == NULL) { 150219820Sjeff struct __rpc_sockinfo si; 151219820Sjeff 152219820Sjeff svcxprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0); 153219820Sjeff if (svcxprt == NULL) 154219820Sjeff continue; 155219820Sjeff if (!__rpc_fd2sockinfo(svcxprt->xp_fd, &si)) { 156219820Sjeff warnx(rpc_reg_err, rpc_reg_msg, __reg_err2); 157219820Sjeff SVC_DESTROY(svcxprt); 158219820Sjeff continue; 159219820Sjeff } 160219820Sjeff recvsz = __rpc_get_t_size(si.si_af, si.si_proto, 0); 161219820Sjeff if (recvsz == 0) { 162219820Sjeff warnx(rpc_reg_err, rpc_reg_msg, __reg_err3); 163219820Sjeff SVC_DESTROY(svcxprt); 164219820Sjeff continue; 165219820Sjeff } 166219820Sjeff if (((xdrbuf = malloc((unsigned)recvsz)) == NULL) || 167219820Sjeff ((netid = strdup(nconf->nc_netid)) == NULL)) { 168219820Sjeff warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str); 169219820Sjeff free(xdrbuf); 170219820Sjeff free(netid); 171219820Sjeff SVC_DESTROY(svcxprt); 172219820Sjeff break; 173219820Sjeff } 174219820Sjeff madenow = TRUE; 175219820Sjeff } 176219820Sjeff /* 177219820Sjeff * Check if this (program, version, netid) had already been 178219820Sjeff * registered. The check may save a few RPC calls to rpcbind 179219820Sjeff */ 180219820Sjeff for (pl = proglst; pl; pl = pl->p_nxt) 181219820Sjeff if ((pl->p_prognum == prognum) && 182219820Sjeff (pl->p_versnum == versnum) && 183219820Sjeff (strcmp(pl->p_netid, netid) == 0)) 184219820Sjeff break; 185219820Sjeff if (pl == NULL) { /* Not yet */ 186219820Sjeff (void) rpcb_unset(prognum, versnum, nconf); 187219820Sjeff } else { 188219820Sjeff /* so that svc_reg does not call rpcb_set() */ 189219820Sjeff nconf = NULL; 190219820Sjeff } 191219820Sjeff 192219820Sjeff if (!svc_reg(svcxprt, prognum, versnum, universal, nconf)) { 193219820Sjeff warnx("%s couldn't register prog %u vers %u for %s", 194219820Sjeff rpc_reg_msg, (unsigned)prognum, 195219820Sjeff (unsigned)versnum, netid); 196219820Sjeff if (madenow) { 197219820Sjeff SVC_DESTROY(svcxprt); 198219820Sjeff free(xdrbuf); 199219820Sjeff free(netid); 200219820Sjeff } 201219820Sjeff continue; 202219820Sjeff } 203219820Sjeff 204219820Sjeff pl = malloc(sizeof (struct proglst)); 205219820Sjeff if (pl == NULL) { 206219820Sjeff warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str); 207219820Sjeff if (madenow) { 208219820Sjeff SVC_DESTROY(svcxprt); 209219820Sjeff free(xdrbuf); 210219820Sjeff free(netid); 211219820Sjeff } 212219820Sjeff break; 213219820Sjeff } 214219820Sjeff pl->p_progname = progname; 215219820Sjeff pl->p_prognum = prognum; 216219820Sjeff pl->p_versnum = versnum; 217219820Sjeff pl->p_procnum = procnum; 218219820Sjeff pl->p_inproc = inproc; 219219820Sjeff pl->p_outproc = outproc; 220219820Sjeff pl->p_transp = svcxprt; 221219820Sjeff pl->p_xdrbuf = xdrbuf; 222219820Sjeff pl->p_recvsz = recvsz; 223219820Sjeff pl->p_netid = netid; 224219820Sjeff pl->p_nxt = proglst; 225219820Sjeff proglst = pl; 226219820Sjeff done = TRUE; 227219820Sjeff } 228219820Sjeff __rpc_endconf(handle); 229219820Sjeff mutex_unlock(&proglst_lock); 230219820Sjeff 231219820Sjeff if (done == FALSE) { 232219820Sjeff warnx("%s can't find suitable transport for %s", 233219820Sjeff rpc_reg_msg, nettype); 234219820Sjeff return (-1); 235219820Sjeff } 236219820Sjeff return (0); 237219820Sjeff} 238219820Sjeff 239219820Sjeff/* 240219820Sjeff * The universal handler for the services registered using registerrpc. 241219820Sjeff * It handles both the connectionless and the connection oriented cases. 242219820Sjeff */ 243219820Sjeff 244219820Sjeffstatic void 245219820Sjeffuniversal(struct svc_req *rqstp, SVCXPRT *transp) 246219820Sjeff{ 247219820Sjeff rpcprog_t prog; 248219820Sjeff rpcvers_t vers; 249219820Sjeff rpcproc_t proc; 250219820Sjeff char *outdata; 251219820Sjeff char *xdrbuf; 252219820Sjeff struct proglst *pl; 253219820Sjeff 254219820Sjeff /* 255219820Sjeff * enforce "procnum 0 is echo" convention 256219820Sjeff */ 257219820Sjeff if (rqstp->rq_proc == NULLPROC) { 258219820Sjeff if (svc_sendreply(transp, (xdrproc_t) xdr_void, NULL) == 259219820Sjeff FALSE) { 260219820Sjeff warnx("svc_sendreply failed"); 261219820Sjeff } 262219820Sjeff return; 263219820Sjeff } 264219820Sjeff prog = rqstp->rq_prog; 265219820Sjeff vers = rqstp->rq_vers; 266219820Sjeff proc = rqstp->rq_proc; 267219820Sjeff mutex_lock(&proglst_lock); 268219820Sjeff for (pl = proglst; pl; pl = pl->p_nxt) 269219820Sjeff if (pl->p_prognum == prog && pl->p_procnum == proc && 270 pl->p_versnum == vers && 271 (strcmp(pl->p_netid, transp->xp_netid) == 0)) { 272 /* decode arguments into a CLEAN buffer */ 273 xdrbuf = pl->p_xdrbuf; 274 /* Zero the arguments: reqd ! */ 275 (void) memset(xdrbuf, 0, (size_t)pl->p_recvsz); 276 /* 277 * Assuming that sizeof (xdrbuf) would be enough 278 * for the arguments; if not then the program 279 * may bomb. BEWARE! 280 */ 281 if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) { 282 svcerr_decode(transp); 283 mutex_unlock(&proglst_lock); 284 return; 285 } 286 outdata = (*(pl->p_progname))(xdrbuf); 287 if (outdata == NULL && 288 pl->p_outproc != (xdrproc_t) xdr_void){ 289 /* there was an error */ 290 mutex_unlock(&proglst_lock); 291 return; 292 } 293 if (!svc_sendreply(transp, pl->p_outproc, outdata)) { 294 warnx( 295 "rpc: rpc_reg trouble replying to prog %u vers %u", 296 (unsigned)prog, (unsigned)vers); 297 mutex_unlock(&proglst_lock); 298 return; 299 } 300 /* free the decoded arguments */ 301 (void)svc_freeargs(transp, pl->p_inproc, xdrbuf); 302 mutex_unlock(&proglst_lock); 303 return; 304 } 305 mutex_unlock(&proglst_lock); 306 /* This should never happen */ 307 warnx("rpc: rpc_reg: never registered prog %u vers %u", 308 (unsigned)prog, (unsigned)vers); 309 return; 310} 311