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