174462Salfred/* $NetBSD: svc_simple.c,v 1.20 2000/07/06 03:10:35 christos Exp $ */ 274462Salfred 3261046Smav/*- 4261046Smav * Copyright (c) 2009, Sun Microsystems, Inc. 5261046Smav * All rights reserved. 68870Srgrimes * 7261046Smav * Redistribution and use in source and binary forms, with or without 8261046Smav * modification, are permitted provided that the following conditions are met: 9261046Smav * - Redistributions of source code must retain the above copyright notice, 10261046Smav * this list of conditions and the following disclaimer. 11261046Smav * - Redistributions in binary form must reproduce the above copyright notice, 12261046Smav * this list of conditions and the following disclaimer in the documentation 13261046Smav * and/or other materials provided with the distribution. 14261046Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its 15261046Smav * contributors may be used to endorse or promote products derived 16261046Smav * from this software without specific prior written permission. 17261046Smav * 18261046Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19261046Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20261046Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21261046Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22261046Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23261046Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24261046Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25261046Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26261046Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27261046Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28261046Smav * POSSIBILITY OF SUCH DAMAGE. 291901Swollman */ 3074462Salfred/* 3174462Salfred * Copyright (c) 1986-1991 by Sun Microsystems Inc. 3274462Salfred */ 331901Swollman 3474462Salfred/* #pragma ident "@(#)svc_simple.c 1.18 94/04/24 SMI" */ 3592990Sobrien#include <sys/cdefs.h> 3692990Sobrien__FBSDID("$FreeBSD$"); 371901Swollman 388870Srgrimes/* 391901Swollman * svc_simple.c 401901Swollman * Simplified front end to rpc. 411901Swollman */ 421901Swollman 4374462Salfred/* 4474462Salfred * This interface creates a virtual listener for all the services 4574462Salfred * started thru rpc_reg(). It listens on the same endpoint for 4674462Salfred * all the services and then executes the corresponding service 4774462Salfred * for the given prognum and procnum. 4874462Salfred */ 4974462Salfred 5075094Siedowse#include "namespace.h" 5174462Salfred#include "reentrant.h" 5274462Salfred#include <sys/types.h> 5374462Salfred#include <rpc/rpc.h> 5474462Salfred#include <rpc/nettype.h> 551901Swollman#include <stdio.h> 5611666Sphk#include <stdlib.h> 5711666Sphk#include <string.h> 5874462Salfred#include <err.h> 5974462Salfred#include "un-namespace.h" 601901Swollman 6174462Salfred#include "rpc_com.h" 62156090Sdeischen#include "mt_misc.h" 6374462Salfred 6492905Sobrienstatic void universal(struct svc_req *, SVCXPRT *); 6574462Salfred 661901Swollmanstatic struct proglst { 6792905Sobrien char *(*p_progname)(char *); 6874462Salfred rpcprog_t p_prognum; 6974462Salfred rpcvers_t p_versnum; 7074462Salfred rpcproc_t p_procnum; 7174462Salfred SVCXPRT *p_transp; 7274462Salfred char *p_netid; 7374462Salfred char *p_xdrbuf; 7474462Salfred int p_recvsz; 751901Swollman xdrproc_t p_inproc, p_outproc; 761901Swollman struct proglst *p_nxt; 771901Swollman} *proglst; 781901Swollman 7974462Salfredstatic const char rpc_reg_err[] = "%s: %s"; 8074462Salfredstatic const char rpc_reg_msg[] = "rpc_reg: "; 8174462Salfredstatic const char __reg_err1[] = "can't find appropriate transport"; 8274462Salfredstatic const char __reg_err2[] = "can't get protocol info"; 8374462Salfredstatic const char __reg_err3[] = "unsupported transport size"; 8474462Salfredstatic const char __no_mem_str[] = "out of memory"; 8574462Salfred 8674462Salfred/* 8774462Salfred * For simplified, easy to use kind of rpc interfaces. 8874462Salfred * nettype indicates the type of transport on which the service will be 8974462Salfred * listening. Used for conservation of the system resource. Only one 9074462Salfred * handle is created for all the services (actually one of each netid) 9174462Salfred * and same xdrbuf is used for same netid. The size of the arguments 9274462Salfred * is also limited by the recvsize for that transport, even if it is 9374462Salfred * a COTS transport. This may be wrong, but for cases like these, they 9474462Salfred * should not use the simplified interfaces like this. 9574462Salfred */ 9674462Salfred 9721090Speterint 9874462Salfredrpc_reg(prognum, versnum, procnum, progname, inproc, outproc, nettype) 9974462Salfred rpcprog_t prognum; /* program number */ 10074462Salfred rpcvers_t versnum; /* version number */ 10174462Salfred rpcproc_t procnum; /* procedure number */ 10292905Sobrien char *(*progname)(char *); /* Server routine */ 10374462Salfred xdrproc_t inproc, outproc; /* in/out XDR procedures */ 10474462Salfred char *nettype; /* nettype */ 1051901Swollman{ 10674462Salfred struct netconfig *nconf; 10774462Salfred int done = FALSE; 10874462Salfred void *handle; 1098870Srgrimes 11074462Salfred 1111901Swollman if (procnum == NULLPROC) { 11274462Salfred warnx("%s can't reassign procedure number %u", rpc_reg_msg, 11374462Salfred NULLPROC); 1141901Swollman return (-1); 1151901Swollman } 11674462Salfred 11774462Salfred if (nettype == NULL) 11874462Salfred nettype = "netpath"; /* The default behavior */ 11974462Salfred if ((handle = __rpc_setconf(nettype)) == NULL) { 12074462Salfred warnx(rpc_reg_err, rpc_reg_msg, __reg_err1); 12174462Salfred return (-1); 12274462Salfred } 12374462Salfred/* VARIABLES PROTECTED BY proglst_lock: proglst */ 12474462Salfred mutex_lock(&proglst_lock); 12574462Salfred while ((nconf = __rpc_getconf(handle)) != NULL) { 12674462Salfred struct proglst *pl; 12774462Salfred SVCXPRT *svcxprt; 12874462Salfred int madenow; 12974462Salfred u_int recvsz; 13074462Salfred char *xdrbuf; 13174462Salfred char *netid; 13274462Salfred 13374462Salfred madenow = FALSE; 13474462Salfred svcxprt = NULL; 13590271Salfred recvsz = 0; 13690271Salfred xdrbuf = netid = NULL; 13790271Salfred for (pl = proglst; pl; pl = pl->p_nxt) { 13874462Salfred if (strcmp(pl->p_netid, nconf->nc_netid) == 0) { 13974462Salfred svcxprt = pl->p_transp; 14074462Salfred xdrbuf = pl->p_xdrbuf; 14174462Salfred recvsz = pl->p_recvsz; 14274462Salfred netid = pl->p_netid; 14374462Salfred break; 14474462Salfred } 14590271Salfred } 14674462Salfred 14774462Salfred if (svcxprt == NULL) { 14874462Salfred struct __rpc_sockinfo si; 14974462Salfred 15074462Salfred svcxprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0); 15174462Salfred if (svcxprt == NULL) 15274462Salfred continue; 15374462Salfred if (!__rpc_fd2sockinfo(svcxprt->xp_fd, &si)) { 15474462Salfred warnx(rpc_reg_err, rpc_reg_msg, __reg_err2); 15574462Salfred SVC_DESTROY(svcxprt); 15674462Salfred continue; 15774462Salfred } 15874462Salfred recvsz = __rpc_get_t_size(si.si_af, si.si_proto, 0); 15974462Salfred if (recvsz == 0) { 16074462Salfred warnx(rpc_reg_err, rpc_reg_msg, __reg_err3); 16174462Salfred SVC_DESTROY(svcxprt); 16274462Salfred continue; 16374462Salfred } 16474462Salfred if (((xdrbuf = malloc((unsigned)recvsz)) == NULL) || 16574462Salfred ((netid = strdup(nconf->nc_netid)) == NULL)) { 16674462Salfred warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str); 167162195Smbr if (xdrbuf != NULL) 168162195Smbr free(xdrbuf); 169162195Smbr if (netid != NULL) 170162195Smbr free(netid); 17174462Salfred SVC_DESTROY(svcxprt); 17274462Salfred break; 17374462Salfred } 17474462Salfred madenow = TRUE; 1751901Swollman } 17674462Salfred /* 17774462Salfred * Check if this (program, version, netid) had already been 17874462Salfred * registered. The check may save a few RPC calls to rpcbind 17974462Salfred */ 18074462Salfred for (pl = proglst; pl; pl = pl->p_nxt) 18174462Salfred if ((pl->p_prognum == prognum) && 18274462Salfred (pl->p_versnum == versnum) && 18374462Salfred (strcmp(pl->p_netid, netid) == 0)) 18474462Salfred break; 18574462Salfred if (pl == NULL) { /* Not yet */ 18674462Salfred (void) rpcb_unset(prognum, versnum, nconf); 18774462Salfred } else { 18874462Salfred /* so that svc_reg does not call rpcb_set() */ 18974462Salfred nconf = NULL; 19074462Salfred } 19174462Salfred 19274462Salfred if (!svc_reg(svcxprt, prognum, versnum, universal, nconf)) { 19374462Salfred warnx("%s couldn't register prog %u vers %u for %s", 19474462Salfred rpc_reg_msg, (unsigned)prognum, 19574462Salfred (unsigned)versnum, netid); 19674462Salfred if (madenow) { 19774462Salfred SVC_DESTROY(svcxprt); 19874462Salfred free(xdrbuf); 19974462Salfred free(netid); 20074462Salfred } 20174462Salfred continue; 20274462Salfred } 20374462Salfred 20474462Salfred pl = malloc(sizeof (struct proglst)); 20574462Salfred if (pl == NULL) { 20674462Salfred warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str); 20774462Salfred if (madenow) { 20874462Salfred SVC_DESTROY(svcxprt); 20974462Salfred free(xdrbuf); 21074462Salfred free(netid); 21174462Salfred } 21274462Salfred break; 21374462Salfred } 21474462Salfred pl->p_progname = progname; 21574462Salfred pl->p_prognum = prognum; 21674462Salfred pl->p_versnum = versnum; 21774462Salfred pl->p_procnum = procnum; 21874462Salfred pl->p_inproc = inproc; 21974462Salfred pl->p_outproc = outproc; 22074462Salfred pl->p_transp = svcxprt; 22174462Salfred pl->p_xdrbuf = xdrbuf; 22274462Salfred pl->p_recvsz = recvsz; 22374462Salfred pl->p_netid = netid; 22474462Salfred pl->p_nxt = proglst; 22574462Salfred proglst = pl; 22674462Salfred done = TRUE; 2271901Swollman } 22874462Salfred __rpc_endconf(handle); 22974462Salfred mutex_unlock(&proglst_lock); 23074462Salfred 23174462Salfred if (done == FALSE) { 23274462Salfred warnx("%s cant find suitable transport for %s", 23374462Salfred rpc_reg_msg, nettype); 2341901Swollman return (-1); 2351901Swollman } 2361901Swollman return (0); 2371901Swollman} 2381901Swollman 23974462Salfred/* 24074462Salfred * The universal handler for the services registered using registerrpc. 24174462Salfred * It handles both the connectionless and the connection oriented cases. 24274462Salfred */ 24374462Salfred 2441901Swollmanstatic void 2451901Swollmanuniversal(rqstp, transp) 2461901Swollman struct svc_req *rqstp; 2471901Swollman SVCXPRT *transp; 2481901Swollman{ 24974462Salfred rpcprog_t prog; 25074462Salfred rpcvers_t vers; 25174462Salfred rpcproc_t proc; 2521901Swollman char *outdata; 25374462Salfred char *xdrbuf; 2541901Swollman struct proglst *pl; 2551901Swollman 2568870Srgrimes /* 2571901Swollman * enforce "procnum 0 is echo" convention 2581901Swollman */ 2591901Swollman if (rqstp->rq_proc == NULLPROC) { 26074462Salfred if (svc_sendreply(transp, (xdrproc_t) xdr_void, NULL) == 26174462Salfred FALSE) { 26274462Salfred warnx("svc_sendreply failed"); 2631901Swollman } 2641901Swollman return; 2651901Swollman } 2661901Swollman prog = rqstp->rq_prog; 26774462Salfred vers = rqstp->rq_vers; 2681901Swollman proc = rqstp->rq_proc; 26974462Salfred mutex_lock(&proglst_lock); 27074462Salfred for (pl = proglst; pl; pl = pl->p_nxt) 27174462Salfred if (pl->p_prognum == prog && pl->p_procnum == proc && 27274462Salfred pl->p_versnum == vers && 27374462Salfred (strcmp(pl->p_netid, transp->xp_netid) == 0)) { 2741901Swollman /* decode arguments into a CLEAN buffer */ 27574462Salfred xdrbuf = pl->p_xdrbuf; 27674462Salfred /* Zero the arguments: reqd ! */ 27774462Salfred (void) memset(xdrbuf, 0, sizeof (pl->p_recvsz)); 27874462Salfred /* 27974462Salfred * Assuming that sizeof (xdrbuf) would be enough 28074462Salfred * for the arguments; if not then the program 28174462Salfred * may bomb. BEWARE! 28274462Salfred */ 2831901Swollman if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) { 2841901Swollman svcerr_decode(transp); 28574462Salfred mutex_unlock(&proglst_lock); 2861901Swollman return; 2871901Swollman } 2881901Swollman outdata = (*(pl->p_progname))(xdrbuf); 28974462Salfred if (outdata == NULL && 29074462Salfred pl->p_outproc != (xdrproc_t) xdr_void){ 2911901Swollman /* there was an error */ 29274462Salfred mutex_unlock(&proglst_lock); 2931901Swollman return; 29474462Salfred } 2951901Swollman if (!svc_sendreply(transp, pl->p_outproc, outdata)) { 29674462Salfred warnx( 29774462Salfred "rpc: rpc_reg trouble replying to prog %u vers %u", 29874462Salfred (unsigned)prog, (unsigned)vers); 29974462Salfred mutex_unlock(&proglst_lock); 30074462Salfred return; 3011901Swollman } 3021901Swollman /* free the decoded arguments */ 3031901Swollman (void)svc_freeargs(transp, pl->p_inproc, xdrbuf); 30474462Salfred mutex_unlock(&proglst_lock); 3051901Swollman return; 3061901Swollman } 30774462Salfred mutex_unlock(&proglst_lock); 30874462Salfred /* This should never happen */ 30974462Salfred warnx("rpc: rpc_reg: never registered prog %u vers %u", 31074462Salfred (unsigned)prog, (unsigned)vers); 31174462Salfred return; 3121901Swollman} 313