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