xref: /minix3/lib/libc/rpc/svc_simple.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: svc_simple.c,v 1.33 2013/03/11 20:19:29 tron Exp $	*/
22fe8fb19SBen Gras 
32fe8fb19SBen Gras /*
4*84d9c625SLionel Sambuc  * Copyright (c) 2010, Oracle America, Inc.
52fe8fb19SBen Gras  *
6*84d9c625SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
7*84d9c625SLionel Sambuc  * modification, are permitted provided that the following conditions are
8*84d9c625SLionel Sambuc  * met:
92fe8fb19SBen Gras  *
10*84d9c625SLionel Sambuc  *     * Redistributions of source code must retain the above copyright
11*84d9c625SLionel Sambuc  *       notice, this list of conditions and the following disclaimer.
12*84d9c625SLionel Sambuc  *     * Redistributions in binary form must reproduce the above
13*84d9c625SLionel Sambuc  *       copyright notice, this list of conditions and the following
14*84d9c625SLionel Sambuc  *       disclaimer in the documentation and/or other materials
15*84d9c625SLionel Sambuc  *       provided with the distribution.
16*84d9c625SLionel Sambuc  *     * Neither the name of the "Oracle America, Inc." nor the names of its
17*84d9c625SLionel Sambuc  *       contributors may be used to endorse or promote products derived
18*84d9c625SLionel Sambuc  *       from this software without specific prior written permission.
192fe8fb19SBen Gras  *
20*84d9c625SLionel Sambuc  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*84d9c625SLionel Sambuc  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*84d9c625SLionel Sambuc  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*84d9c625SLionel Sambuc  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24*84d9c625SLionel Sambuc  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25*84d9c625SLionel Sambuc  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26*84d9c625SLionel Sambuc  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27*84d9c625SLionel Sambuc  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28*84d9c625SLionel Sambuc  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29*84d9c625SLionel Sambuc  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30*84d9c625SLionel Sambuc  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31*84d9c625SLionel Sambuc  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
322fe8fb19SBen Gras  */
332fe8fb19SBen Gras /*
342fe8fb19SBen Gras  * Copyright (c) 1986-1991 by Sun Microsystems Inc.
352fe8fb19SBen Gras  */
362fe8fb19SBen Gras 
372fe8fb19SBen Gras /* #pragma ident	"@(#)svc_simple.c	1.18	94/04/24 SMI" */
382fe8fb19SBen Gras 
392fe8fb19SBen Gras /*
402fe8fb19SBen Gras  * svc_simple.c
412fe8fb19SBen Gras  * Simplified front end to rpc.
422fe8fb19SBen Gras  */
432fe8fb19SBen Gras 
442fe8fb19SBen Gras /*
452fe8fb19SBen Gras  * This interface creates a virtual listener for all the services
462fe8fb19SBen Gras  * started thru rpc_reg(). It listens on the same endpoint for
472fe8fb19SBen Gras  * all the services and then executes the corresponding service
482fe8fb19SBen Gras  * for the given prognum and procnum.
492fe8fb19SBen Gras  */
502fe8fb19SBen Gras 
512fe8fb19SBen Gras #include <sys/cdefs.h>
522fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
53*84d9c625SLionel Sambuc __RCSID("$NetBSD: svc_simple.c,v 1.33 2013/03/11 20:19:29 tron Exp $");
542fe8fb19SBen Gras #endif
552fe8fb19SBen Gras 
562fe8fb19SBen Gras #include "namespace.h"
572fe8fb19SBen Gras #include "reentrant.h"
582fe8fb19SBen Gras #include <sys/types.h>
592fe8fb19SBen Gras #include <rpc/rpc.h>
602fe8fb19SBen Gras #include <rpc/nettype.h>
612fe8fb19SBen Gras #include <assert.h>
622fe8fb19SBen Gras #include <err.h>
632fe8fb19SBen Gras #include <stdio.h>
642fe8fb19SBen Gras #include <stdlib.h>
652fe8fb19SBen Gras #include <string.h>
662fe8fb19SBen Gras 
672fe8fb19SBen Gras #include "rpc_internal.h"
682fe8fb19SBen Gras 
692fe8fb19SBen Gras #ifdef __weak_alias
702fe8fb19SBen Gras __weak_alias(rpc_reg,_rpc_reg)
712fe8fb19SBen Gras #endif
722fe8fb19SBen Gras 
73f14fb602SLionel Sambuc static void universal(struct svc_req *, SVCXPRT *);
742fe8fb19SBen Gras 
752fe8fb19SBen Gras static struct proglst {
76f14fb602SLionel Sambuc 	char *(*p_progname)(char *);
772fe8fb19SBen Gras 	rpcprog_t p_prognum;
782fe8fb19SBen Gras 	rpcvers_t p_versnum;
792fe8fb19SBen Gras 	rpcproc_t p_procnum;
802fe8fb19SBen Gras 	SVCXPRT *p_transp;
812fe8fb19SBen Gras 	char *p_netid;
822fe8fb19SBen Gras 	char *p_xdrbuf;
832fe8fb19SBen Gras 	int p_recvsz;
842fe8fb19SBen Gras 	xdrproc_t p_inproc, p_outproc;
852fe8fb19SBen Gras 	struct proglst *p_nxt;
862fe8fb19SBen Gras } *proglst;
872fe8fb19SBen Gras 
882fe8fb19SBen Gras static const char __reg_err1[] = "can't find appropriate transport";
892fe8fb19SBen Gras static const char __reg_err2[] = "can't get protocol info";
902fe8fb19SBen Gras static const char __reg_err3[] = "unsupported transport size";
912fe8fb19SBen Gras static const char __no_mem_str[] = "out of memory";
922fe8fb19SBen Gras 
932fe8fb19SBen Gras /*
942fe8fb19SBen Gras  * For simplified, easy to use kind of rpc interfaces.
952fe8fb19SBen Gras  * nettype indicates the type of transport on which the service will be
962fe8fb19SBen Gras  * listening. Used for conservation of the system resource. Only one
972fe8fb19SBen Gras  * handle is created for all the services (actually one of each netid)
982fe8fb19SBen Gras  * and same xdrbuf is used for same netid. The size of the arguments
992fe8fb19SBen Gras  * is also limited by the recvsize for that transport, even if it is
1002fe8fb19SBen Gras  * a COTS transport. This may be wrong, but for cases like these, they
1012fe8fb19SBen Gras  * should not use the simplified interfaces like this.
1022fe8fb19SBen Gras  */
1032fe8fb19SBen Gras 
1042fe8fb19SBen Gras int
rpc_reg(rpcprog_t prognum,rpcvers_t versnum,rpcproc_t procnum,char * (* progname)(char *),xdrproc_t inproc,xdrproc_t outproc,char * nettype)105f14fb602SLionel Sambuc rpc_reg(
106f14fb602SLionel Sambuc 	rpcprog_t prognum,		/* program number */
107f14fb602SLionel Sambuc 	rpcvers_t versnum,		/* version number */
108f14fb602SLionel Sambuc 	rpcproc_t procnum,		/* procedure number */
109f14fb602SLionel Sambuc 	char *(*progname)(char *),	/* Server routine */
110f14fb602SLionel Sambuc 	xdrproc_t inproc,		/* in XDR procedure */
111f14fb602SLionel Sambuc 	xdrproc_t outproc,		/* out XDR procedure */
112f14fb602SLionel Sambuc 	char *nettype)			/* nettype */
1132fe8fb19SBen Gras {
1142fe8fb19SBen Gras 	struct netconfig *nconf;
1152fe8fb19SBen Gras 	int done = FALSE;
1162fe8fb19SBen Gras 	void *handle;
1172fe8fb19SBen Gras #ifdef _REENTRANT
1182fe8fb19SBen Gras 	extern mutex_t proglst_lock;
1192fe8fb19SBen Gras #endif
1202fe8fb19SBen Gras 
1212fe8fb19SBen Gras 	if (procnum == NULLPROC) {
122*84d9c625SLionel Sambuc 		warnx("%s: can't reassign procedure number %u", __func__,
1232fe8fb19SBen Gras 		    NULLPROC);
1242fe8fb19SBen Gras 		return (-1);
1252fe8fb19SBen Gras 	}
1262fe8fb19SBen Gras 
1272fe8fb19SBen Gras 	if (nettype == NULL)
1282fe8fb19SBen Gras 		nettype = __UNCONST("netpath");	/* The default behavior */
1292fe8fb19SBen Gras 	if ((handle = __rpc_setconf(nettype)) == NULL) {
130*84d9c625SLionel Sambuc 		warnx("%s: %s", __func__, __reg_err1);
1312fe8fb19SBen Gras 		return (-1);
1322fe8fb19SBen Gras 	}
1332fe8fb19SBen Gras /* VARIABLES PROTECTED BY proglst_lock: proglst */
1342fe8fb19SBen Gras 	mutex_lock(&proglst_lock);
1352fe8fb19SBen Gras 	while ((nconf = __rpc_getconf(handle)) != NULL) {
1362fe8fb19SBen Gras 		struct proglst *pl;
1372fe8fb19SBen Gras 		SVCXPRT *svcxprt;
1382fe8fb19SBen Gras 		int madenow;
1392fe8fb19SBen Gras 		u_int recvsz;
1402fe8fb19SBen Gras 		char *xdrbuf;
1412fe8fb19SBen Gras 		char *netid;
1422fe8fb19SBen Gras 
1432fe8fb19SBen Gras 		madenow = FALSE;
1442fe8fb19SBen Gras 		svcxprt = NULL;
1452fe8fb19SBen Gras 		recvsz = 0;
1462fe8fb19SBen Gras 		xdrbuf = NULL;
1472fe8fb19SBen Gras 		netid = NULL;
1482fe8fb19SBen Gras 		for (pl = proglst; pl; pl = pl->p_nxt)
1492fe8fb19SBen Gras 			if (strcmp(pl->p_netid, nconf->nc_netid) == 0) {
1502fe8fb19SBen Gras 				svcxprt = pl->p_transp;
1512fe8fb19SBen Gras 				xdrbuf = pl->p_xdrbuf;
1522fe8fb19SBen Gras 				recvsz = pl->p_recvsz;
1532fe8fb19SBen Gras 				netid = pl->p_netid;
1542fe8fb19SBen Gras 				break;
1552fe8fb19SBen Gras 			}
1562fe8fb19SBen Gras 
1572fe8fb19SBen Gras 		if (svcxprt == NULL) {
1582fe8fb19SBen Gras 			struct __rpc_sockinfo si;
1592fe8fb19SBen Gras 
1602fe8fb19SBen Gras 			svcxprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0);
1612fe8fb19SBen Gras 			if (svcxprt == NULL)
1622fe8fb19SBen Gras 				continue;
1632fe8fb19SBen Gras 			if (!__rpc_fd2sockinfo(svcxprt->xp_fd, &si)) {
164*84d9c625SLionel Sambuc 				warnx("%s: %s", __func__, __reg_err2);
1652fe8fb19SBen Gras 				SVC_DESTROY(svcxprt);
1662fe8fb19SBen Gras 				continue;
1672fe8fb19SBen Gras 			}
1682fe8fb19SBen Gras 			recvsz = __rpc_get_t_size(si.si_af, si.si_proto, 0);
1692fe8fb19SBen Gras 			if (recvsz == 0) {
170*84d9c625SLionel Sambuc 				warnx("%s: %s", __func__, __reg_err3);
1712fe8fb19SBen Gras 				SVC_DESTROY(svcxprt);
1722fe8fb19SBen Gras 				continue;
1732fe8fb19SBen Gras 			}
174*84d9c625SLionel Sambuc 			if (((xdrbuf = mem_alloc((size_t)recvsz)) == NULL) ||
1752fe8fb19SBen Gras 				((netid = strdup(nconf->nc_netid)) == NULL)) {
176*84d9c625SLionel Sambuc 				warnx("%s: %s", __func__, __no_mem_str);
1772fe8fb19SBen Gras 				if (xdrbuf != NULL)
1782fe8fb19SBen Gras 					free(xdrbuf);
1792fe8fb19SBen Gras 				if (netid != NULL)
1802fe8fb19SBen Gras 					free(netid);
1812fe8fb19SBen Gras 				SVC_DESTROY(svcxprt);
1822fe8fb19SBen Gras 				break;
1832fe8fb19SBen Gras 			}
1842fe8fb19SBen Gras 			madenow = TRUE;
1852fe8fb19SBen Gras 		}
1862fe8fb19SBen Gras 		/*
1872fe8fb19SBen Gras 		 * Check if this (program, version, netid) had already been
1882fe8fb19SBen Gras 		 * registered.  The check may save a few RPC calls to rpcbind
1892fe8fb19SBen Gras 		 */
1902fe8fb19SBen Gras 		for (pl = proglst; pl; pl = pl->p_nxt)
1912fe8fb19SBen Gras 			if ((pl->p_prognum == prognum) &&
1922fe8fb19SBen Gras 				(pl->p_versnum == versnum) &&
1932fe8fb19SBen Gras 				(strcmp(pl->p_netid, netid) == 0))
1942fe8fb19SBen Gras 				break;
1952fe8fb19SBen Gras 		if (pl == NULL) { /* Not yet */
1962fe8fb19SBen Gras 			(void) rpcb_unset(prognum, versnum, nconf);
1972fe8fb19SBen Gras 		} else {
1982fe8fb19SBen Gras 			/* so that svc_reg does not call rpcb_set() */
1992fe8fb19SBen Gras 			nconf = NULL;
2002fe8fb19SBen Gras 		}
2012fe8fb19SBen Gras 
2022fe8fb19SBen Gras 		if (!svc_reg(svcxprt, prognum, versnum, universal, nconf)) {
203*84d9c625SLionel Sambuc 			warnx("%s: couldn't register prog %u vers %u for %s",
204*84d9c625SLionel Sambuc 			    __func__, (unsigned)prognum,
2052fe8fb19SBen Gras 			    (unsigned)versnum, netid);
2062fe8fb19SBen Gras 			if (madenow) {
2072fe8fb19SBen Gras 				SVC_DESTROY(svcxprt);
2082fe8fb19SBen Gras 				free(xdrbuf);
2092fe8fb19SBen Gras 				free(netid);
2102fe8fb19SBen Gras 			}
2112fe8fb19SBen Gras 			continue;
2122fe8fb19SBen Gras 		}
2132fe8fb19SBen Gras 
2142fe8fb19SBen Gras 		pl = malloc(sizeof(*pl));
2152fe8fb19SBen Gras 		if (pl == NULL) {
216*84d9c625SLionel Sambuc 			warn("%s: %s", __func__, __no_mem_str);
2172fe8fb19SBen Gras 			if (madenow) {
2182fe8fb19SBen Gras 				SVC_DESTROY(svcxprt);
2192fe8fb19SBen Gras 				free(xdrbuf);
2202fe8fb19SBen Gras 				free(netid);
2212fe8fb19SBen Gras 			}
2222fe8fb19SBen Gras 			break;
2232fe8fb19SBen Gras 		}
2242fe8fb19SBen Gras 		pl->p_progname = progname;
2252fe8fb19SBen Gras 		pl->p_prognum = prognum;
2262fe8fb19SBen Gras 		pl->p_versnum = versnum;
2272fe8fb19SBen Gras 		pl->p_procnum = procnum;
2282fe8fb19SBen Gras 		pl->p_inproc = inproc;
2292fe8fb19SBen Gras 		pl->p_outproc = outproc;
2302fe8fb19SBen Gras 		pl->p_transp = svcxprt;
2312fe8fb19SBen Gras 		pl->p_xdrbuf = xdrbuf;
2322fe8fb19SBen Gras 		pl->p_recvsz = recvsz;
2332fe8fb19SBen Gras 		pl->p_netid = netid;
2342fe8fb19SBen Gras 		pl->p_nxt = proglst;
2352fe8fb19SBen Gras 		proglst = pl;
2362fe8fb19SBen Gras 		done = TRUE;
2372fe8fb19SBen Gras 	}
2382fe8fb19SBen Gras 	__rpc_endconf(handle);
2392fe8fb19SBen Gras 	mutex_unlock(&proglst_lock);
2402fe8fb19SBen Gras 
2412fe8fb19SBen Gras 	if (done == FALSE) {
242*84d9c625SLionel Sambuc 		warnx("%s: can't find suitable transport for %s",
243*84d9c625SLionel Sambuc 		    __func__, nettype);
2442fe8fb19SBen Gras 		return (-1);
2452fe8fb19SBen Gras 	}
2462fe8fb19SBen Gras 	return (0);
2472fe8fb19SBen Gras }
2482fe8fb19SBen Gras 
2492fe8fb19SBen Gras /*
2502fe8fb19SBen Gras  * The universal handler for the services registered using registerrpc.
2512fe8fb19SBen Gras  * It handles both the connectionless and the connection oriented cases.
2522fe8fb19SBen Gras  */
2532fe8fb19SBen Gras 
2542fe8fb19SBen Gras static void
universal(struct svc_req * rqstp,SVCXPRT * transp)255f14fb602SLionel Sambuc universal(struct svc_req *rqstp, SVCXPRT *transp)
2562fe8fb19SBen Gras {
2572fe8fb19SBen Gras 	rpcprog_t prog;
2582fe8fb19SBen Gras 	rpcvers_t vers;
2592fe8fb19SBen Gras 	rpcproc_t proc;
2602fe8fb19SBen Gras 	char *outdata;
2612fe8fb19SBen Gras 	char *xdrbuf;
2622fe8fb19SBen Gras 	struct proglst *pl;
2632fe8fb19SBen Gras #ifdef _REENTRANT
2642fe8fb19SBen Gras 	extern mutex_t proglst_lock;
2652fe8fb19SBen Gras #endif
2662fe8fb19SBen Gras 
2672fe8fb19SBen Gras 	_DIAGASSERT(rqstp != NULL);
2682fe8fb19SBen Gras 	_DIAGASSERT(transp != NULL);
2692fe8fb19SBen Gras 
2702fe8fb19SBen Gras 	/*
2712fe8fb19SBen Gras 	 * enforce "procnum 0 is echo" convention
2722fe8fb19SBen Gras 	 */
2732fe8fb19SBen Gras 	if (rqstp->rq_proc == NULLPROC) {
2742fe8fb19SBen Gras 		if (svc_sendreply(transp, (xdrproc_t) xdr_void, NULL) ==
2752fe8fb19SBen Gras 		    FALSE) {
276*84d9c625SLionel Sambuc 			warnx("%s: svc_sendreply failed", __func__);
2772fe8fb19SBen Gras 		}
2782fe8fb19SBen Gras 		return;
2792fe8fb19SBen Gras 	}
2802fe8fb19SBen Gras 	prog = rqstp->rq_prog;
2812fe8fb19SBen Gras 	vers = rqstp->rq_vers;
2822fe8fb19SBen Gras 	proc = rqstp->rq_proc;
2832fe8fb19SBen Gras 	mutex_lock(&proglst_lock);
2842fe8fb19SBen Gras 	for (pl = proglst; pl; pl = pl->p_nxt)
2852fe8fb19SBen Gras 		if (pl->p_prognum == prog && pl->p_procnum == proc &&
2862fe8fb19SBen Gras 			pl->p_versnum == vers &&
2872fe8fb19SBen Gras 			(strcmp(pl->p_netid, transp->xp_netid) == 0)) {
2882fe8fb19SBen Gras 			/* decode arguments into a CLEAN buffer */
2892fe8fb19SBen Gras 			xdrbuf = pl->p_xdrbuf;
2902fe8fb19SBen Gras 			/* Zero the arguments: reqd ! */
2912fe8fb19SBen Gras 			(void) memset(xdrbuf, 0, (size_t)pl->p_recvsz);
2922fe8fb19SBen Gras 			/*
2932fe8fb19SBen Gras 			 * Assuming that sizeof (xdrbuf) would be enough
2942fe8fb19SBen Gras 			 * for the arguments; if not then the program
2952fe8fb19SBen Gras 			 * may bomb. BEWARE!
2962fe8fb19SBen Gras 			 */
2972fe8fb19SBen Gras 			if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) {
2982fe8fb19SBen Gras 				svcerr_decode(transp);
2992fe8fb19SBen Gras 				mutex_unlock(&proglst_lock);
3002fe8fb19SBen Gras 				return;
3012fe8fb19SBen Gras 			}
3022fe8fb19SBen Gras 			outdata = (*(pl->p_progname))(xdrbuf);
3032fe8fb19SBen Gras 			if (outdata == NULL &&
3042fe8fb19SBen Gras 				pl->p_outproc != (xdrproc_t) xdr_void){
3052fe8fb19SBen Gras 				/* there was an error */
3062fe8fb19SBen Gras 				mutex_unlock(&proglst_lock);
3072fe8fb19SBen Gras 				return;
3082fe8fb19SBen Gras 			}
3092fe8fb19SBen Gras 			if (!svc_sendreply(transp, pl->p_outproc, outdata)) {
310*84d9c625SLionel Sambuc 				warnx("%s: trouble replying to prog %u vers %u",
311*84d9c625SLionel Sambuc 				    __func__, (unsigned)prog, (unsigned)vers);
3122fe8fb19SBen Gras 				mutex_unlock(&proglst_lock);
3132fe8fb19SBen Gras 				return;
3142fe8fb19SBen Gras 			}
3152fe8fb19SBen Gras 			/* free the decoded arguments */
3162fe8fb19SBen Gras 			(void) svc_freeargs(transp, pl->p_inproc, xdrbuf);
3172fe8fb19SBen Gras 			mutex_unlock(&proglst_lock);
3182fe8fb19SBen Gras 			return;
3192fe8fb19SBen Gras 		}
3202fe8fb19SBen Gras 	mutex_unlock(&proglst_lock);
3212fe8fb19SBen Gras 	/* This should never happen */
322*84d9c625SLionel Sambuc 	warnx("%s: never registered prog %u vers %u", __func__,
3232fe8fb19SBen Gras 	    (unsigned)prog, (unsigned)vers);
3242fe8fb19SBen Gras 	return;
3252fe8fb19SBen Gras }
326