xref: /titanic_51/usr/src/lib/libnsl/rpc/svc_simple.c (revision 9ff75ade7518b5023d90c864a4c081dba319589e)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
59acbbeafSnn35248  * Common Development and Distribution License (the "License").
69acbbeafSnn35248  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2161961e0fSrobinson 
227c478bd9Sstevel@tonic-gate /*
23*9ff75adeSSurya Prakki  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
267c478bd9Sstevel@tonic-gate /* All Rights Reserved */
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley
297c478bd9Sstevel@tonic-gate  * 4.3 BSD under license from the Regents of the University of
307c478bd9Sstevel@tonic-gate  * California.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate  * svc_simple.c
357c478bd9Sstevel@tonic-gate  * Simplified front end to rpc.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate  * This interface creates a virtual listener for all the services
407c478bd9Sstevel@tonic-gate  * started thru rpc_reg(). It listens on the same endpoint for
417c478bd9Sstevel@tonic-gate  * all the services and then executes the corresponding service
427c478bd9Sstevel@tonic-gate  * for the given prognum and procnum.
437c478bd9Sstevel@tonic-gate  */
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #include "mt.h"
467c478bd9Sstevel@tonic-gate #include "rpc_mt.h"
477c478bd9Sstevel@tonic-gate #include <errno.h>
487c478bd9Sstevel@tonic-gate #include <stdio.h>
497c478bd9Sstevel@tonic-gate #include <stdlib.h>
507c478bd9Sstevel@tonic-gate #include <string.h>
517c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
527c478bd9Sstevel@tonic-gate #include <sys/types.h>
537c478bd9Sstevel@tonic-gate #include <syslog.h>
547c478bd9Sstevel@tonic-gate #include <rpc/nettype.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate static struct proglst {
577c478bd9Sstevel@tonic-gate 	char *(*p_progname)();
587c478bd9Sstevel@tonic-gate 	rpcprog_t p_prognum;
597c478bd9Sstevel@tonic-gate 	rpcvers_t p_versnum;
607c478bd9Sstevel@tonic-gate 	rpcproc_t p_procnum;
617c478bd9Sstevel@tonic-gate 	SVCXPRT *p_transp;
627c478bd9Sstevel@tonic-gate 	char *p_netid;
637c478bd9Sstevel@tonic-gate 	char *p_xdrbuf;
647c478bd9Sstevel@tonic-gate 	int p_recvsz;
657c478bd9Sstevel@tonic-gate 	xdrproc_t p_inproc, p_outproc;
667c478bd9Sstevel@tonic-gate 	struct proglst *p_nxt;
677c478bd9Sstevel@tonic-gate } *proglst;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate static void universal();
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate static const char rpc_reg_err[] = "%s: %s";
727c478bd9Sstevel@tonic-gate static const char rpc_reg_msg[] = "rpc_reg: ";
737c478bd9Sstevel@tonic-gate static const char __reg_err1[] = "can't find appropriate transport";
747c478bd9Sstevel@tonic-gate static const char __reg_err3[] = "unsupported transport size";
757c478bd9Sstevel@tonic-gate static const char __no_mem_str[] = "out of memory";
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate  * For simplified, easy to use kind of rpc interfaces.
787c478bd9Sstevel@tonic-gate  * nettype indicates the type of transport on which the service will be
797c478bd9Sstevel@tonic-gate  * listening. Used for conservation of the system resource. Only one
807c478bd9Sstevel@tonic-gate  * handle is created for all the services (actually one of each netid)
817c478bd9Sstevel@tonic-gate  * and same xdrbuf is used for same netid. The size of the arguments
827c478bd9Sstevel@tonic-gate  * is also limited by the recvsize for that transport, even if it is
837c478bd9Sstevel@tonic-gate  * a COTS transport. This may be wrong, but for cases like these, they
847c478bd9Sstevel@tonic-gate  * should not use the simplified interfaces like this.
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate int
8861961e0fSrobinson rpc_reg(const rpcprog_t prognum, const rpcvers_t versnum,
8961961e0fSrobinson 	const rpcproc_t procnum, char *(*progname)(), const xdrproc_t inproc,
9061961e0fSrobinson 	const xdrproc_t outproc, const char *nettype)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	struct netconfig *nconf;
937c478bd9Sstevel@tonic-gate 	int done = FALSE;
947c478bd9Sstevel@tonic-gate 	void *handle;
957c478bd9Sstevel@tonic-gate 	extern mutex_t proglst_lock;
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	if (procnum == NULLPROC) {
987c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, (const char *) "%s: %s %d",
997c478bd9Sstevel@tonic-gate 			rpc_reg_msg,
1007c478bd9Sstevel@tonic-gate 			(const char *) "can't reassign procedure number %d",
1017c478bd9Sstevel@tonic-gate 			NULLPROC);
1027c478bd9Sstevel@tonic-gate 		return (-1);
1037c478bd9Sstevel@tonic-gate 	}
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	if (nettype == NULL)
1067c478bd9Sstevel@tonic-gate 		nettype = "netpath";		/* The default behavior */
1077c478bd9Sstevel@tonic-gate 	if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
1087c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg, __reg_err1);
1097c478bd9Sstevel@tonic-gate 		return (-1);
1107c478bd9Sstevel@tonic-gate 	}
1117c478bd9Sstevel@tonic-gate /* VARIABLES PROTECTED BY proglst_lock: proglst */
11261961e0fSrobinson 	(void) mutex_lock(&proglst_lock);
1137c478bd9Sstevel@tonic-gate 	while (nconf = __rpc_getconf(handle)) {
1147c478bd9Sstevel@tonic-gate 		struct proglst *pl;
1157c478bd9Sstevel@tonic-gate 		SVCXPRT *svcxprt;
1167c478bd9Sstevel@tonic-gate 		int madenow;
1177c478bd9Sstevel@tonic-gate 		uint_t recvsz;
1187c478bd9Sstevel@tonic-gate 		char *xdrbuf;
1197c478bd9Sstevel@tonic-gate 		char *netid;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 		madenow = FALSE;
12261961e0fSrobinson 		svcxprt = NULL;
1237c478bd9Sstevel@tonic-gate 		for (pl = proglst; pl; pl = pl->p_nxt)
1247c478bd9Sstevel@tonic-gate 			if (strcmp(pl->p_netid, nconf->nc_netid) == 0) {
1257c478bd9Sstevel@tonic-gate 				svcxprt = pl->p_transp;
1267c478bd9Sstevel@tonic-gate 				xdrbuf = pl->p_xdrbuf;
1277c478bd9Sstevel@tonic-gate 				recvsz = pl->p_recvsz;
1287c478bd9Sstevel@tonic-gate 				netid = pl->p_netid;
1297c478bd9Sstevel@tonic-gate 				break;
1307c478bd9Sstevel@tonic-gate 			}
1317c478bd9Sstevel@tonic-gate 
13261961e0fSrobinson 		if (svcxprt == NULL) {
1337c478bd9Sstevel@tonic-gate 			struct t_info tinfo;
1347c478bd9Sstevel@tonic-gate 
13561961e0fSrobinson 			svcxprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0);
13661961e0fSrobinson 			if (svcxprt == NULL)
1377c478bd9Sstevel@tonic-gate 				continue;
1387c478bd9Sstevel@tonic-gate 			if (t_getinfo(svcxprt->xp_fd, &tinfo) == -1) {
1397c478bd9Sstevel@tonic-gate 				char errorstr[100];
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 				__tli_sys_strerror(errorstr, sizeof (errorstr),
1427c478bd9Sstevel@tonic-gate 						t_errno, errno);
1437c478bd9Sstevel@tonic-gate 				(void) syslog(LOG_ERR, "%s : %s : %s",
1447c478bd9Sstevel@tonic-gate 					rpc_reg_msg, "t_getinfo failed",
1457c478bd9Sstevel@tonic-gate 					errorstr);
1467c478bd9Sstevel@tonic-gate 				SVC_DESTROY(svcxprt);
1477c478bd9Sstevel@tonic-gate 				continue;
1487c478bd9Sstevel@tonic-gate 			}
1497c478bd9Sstevel@tonic-gate 			if ((recvsz = __rpc_get_t_size(0, tinfo.tsdu)) == 0) {
1507c478bd9Sstevel@tonic-gate 				(void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg,
1517c478bd9Sstevel@tonic-gate 					__reg_err3);
1527c478bd9Sstevel@tonic-gate 				SVC_DESTROY(svcxprt);
1537c478bd9Sstevel@tonic-gate 				continue;
1547c478bd9Sstevel@tonic-gate 			}
1557c478bd9Sstevel@tonic-gate 			if (((xdrbuf = malloc((unsigned)recvsz)) == NULL) ||
1567c478bd9Sstevel@tonic-gate 				((netid = strdup(nconf->nc_netid)) == NULL)) {
1577c478bd9Sstevel@tonic-gate 				(void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg,
1587c478bd9Sstevel@tonic-gate 					__no_mem_str);
1597c478bd9Sstevel@tonic-gate 				SVC_DESTROY(svcxprt);
1607c478bd9Sstevel@tonic-gate 				break;
1617c478bd9Sstevel@tonic-gate 			}
1627c478bd9Sstevel@tonic-gate 			madenow = TRUE;
1637c478bd9Sstevel@tonic-gate 		}
1647c478bd9Sstevel@tonic-gate 		/*
1657c478bd9Sstevel@tonic-gate 		 * Check if this (program, version, netid) had already been
1667c478bd9Sstevel@tonic-gate 		 * registered.  The check may save a few RPC calls to rpcbind
1677c478bd9Sstevel@tonic-gate 		 */
1687c478bd9Sstevel@tonic-gate 		for (pl = proglst; pl; pl = pl->p_nxt)
1697c478bd9Sstevel@tonic-gate 			if ((pl->p_prognum == prognum) &&
1707c478bd9Sstevel@tonic-gate 				(pl->p_versnum == versnum) &&
1717c478bd9Sstevel@tonic-gate 				(strcmp(pl->p_netid, netid) == 0))
1727c478bd9Sstevel@tonic-gate 				break;
1737c478bd9Sstevel@tonic-gate 		if (pl == NULL) { /* Not yet */
1747c478bd9Sstevel@tonic-gate 			(void) rpcb_unset(prognum, versnum, nconf);
1757c478bd9Sstevel@tonic-gate 		} else {
1767c478bd9Sstevel@tonic-gate 			/* so that svc_reg does not call rpcb_set() */
1777c478bd9Sstevel@tonic-gate 			nconf = NULL;
1787c478bd9Sstevel@tonic-gate 		}
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 		if (!svc_reg(svcxprt, prognum, versnum, universal, nconf)) {
1817c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
1827c478bd9Sstevel@tonic-gate 				"%s couldn't register prog %d vers %d for %s",
1837c478bd9Sstevel@tonic-gate 				rpc_reg_msg, prognum, versnum, netid);
1847c478bd9Sstevel@tonic-gate 			if (madenow) {
1857c478bd9Sstevel@tonic-gate 				SVC_DESTROY(svcxprt);
1867c478bd9Sstevel@tonic-gate 				free(xdrbuf);
1877c478bd9Sstevel@tonic-gate 				free(netid);
1887c478bd9Sstevel@tonic-gate 			}
1897c478bd9Sstevel@tonic-gate 			continue;
1907c478bd9Sstevel@tonic-gate 		}
1917c478bd9Sstevel@tonic-gate 
19261961e0fSrobinson 		pl = malloc(sizeof (struct proglst));
19361961e0fSrobinson 		if (pl == NULL) {
1947c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg,
1957c478bd9Sstevel@tonic-gate 					__no_mem_str);
1967c478bd9Sstevel@tonic-gate 			if (madenow) {
1977c478bd9Sstevel@tonic-gate 				SVC_DESTROY(svcxprt);
1987c478bd9Sstevel@tonic-gate 				free(xdrbuf);
1997c478bd9Sstevel@tonic-gate 				free(netid);
2007c478bd9Sstevel@tonic-gate 			}
2017c478bd9Sstevel@tonic-gate 			break;
2027c478bd9Sstevel@tonic-gate 		}
2037c478bd9Sstevel@tonic-gate 		pl->p_progname = progname;
2047c478bd9Sstevel@tonic-gate 		pl->p_prognum = prognum;
2057c478bd9Sstevel@tonic-gate 		pl->p_versnum = versnum;
2067c478bd9Sstevel@tonic-gate 		pl->p_procnum = procnum;
2077c478bd9Sstevel@tonic-gate 		pl->p_inproc = inproc;
2087c478bd9Sstevel@tonic-gate 		pl->p_outproc = outproc;
2097c478bd9Sstevel@tonic-gate 		pl->p_transp = svcxprt;
2107c478bd9Sstevel@tonic-gate 		pl->p_xdrbuf = xdrbuf;
2117c478bd9Sstevel@tonic-gate 		pl->p_recvsz = recvsz;
2127c478bd9Sstevel@tonic-gate 		pl->p_netid = netid;
2137c478bd9Sstevel@tonic-gate 		pl->p_nxt = proglst;
2147c478bd9Sstevel@tonic-gate 		proglst = pl;
2157c478bd9Sstevel@tonic-gate 		done = TRUE;
2167c478bd9Sstevel@tonic-gate 	}
2177c478bd9Sstevel@tonic-gate 	__rpc_endconf(handle);
21861961e0fSrobinson 	(void) mutex_unlock(&proglst_lock);
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	if (done == FALSE) {
2217c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
2227c478bd9Sstevel@tonic-gate 			(const char *) "%s cant find suitable transport for %s",
2237c478bd9Sstevel@tonic-gate 			rpc_reg_msg, nettype);
2247c478bd9Sstevel@tonic-gate 		return (-1);
2257c478bd9Sstevel@tonic-gate 	}
2267c478bd9Sstevel@tonic-gate 	return (0);
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate /*
2307c478bd9Sstevel@tonic-gate  * The universal handler for the services registered using registerrpc.
2317c478bd9Sstevel@tonic-gate  * It handles both the connectionless and the connection oriented cases.
2327c478bd9Sstevel@tonic-gate  */
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate static void
23561961e0fSrobinson universal(struct svc_req *rqstp, SVCXPRT *transp)
2367c478bd9Sstevel@tonic-gate {
2377c478bd9Sstevel@tonic-gate 	rpcprog_t prog;
2387c478bd9Sstevel@tonic-gate 	rpcvers_t vers;
2397c478bd9Sstevel@tonic-gate 	rpcproc_t proc;
2407c478bd9Sstevel@tonic-gate 	char *outdata;
2417c478bd9Sstevel@tonic-gate 	char *xdrbuf;
2427c478bd9Sstevel@tonic-gate 	struct proglst *pl;
2437c478bd9Sstevel@tonic-gate 	extern mutex_t proglst_lock;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	/*
2467c478bd9Sstevel@tonic-gate 	 * enforce "procnum 0 is echo" convention
2477c478bd9Sstevel@tonic-gate 	 */
2487c478bd9Sstevel@tonic-gate 	if (rqstp->rq_proc == NULLPROC) {
24961961e0fSrobinson 		if (svc_sendreply(transp, (xdrproc_t)xdr_void, NULL) == FALSE) {
2507c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
2517c478bd9Sstevel@tonic-gate 				(const char *) "svc_sendreply failed");
2527c478bd9Sstevel@tonic-gate 		}
2537c478bd9Sstevel@tonic-gate 		return;
2547c478bd9Sstevel@tonic-gate 	}
2557c478bd9Sstevel@tonic-gate 	prog = rqstp->rq_prog;
2567c478bd9Sstevel@tonic-gate 	vers = rqstp->rq_vers;
2577c478bd9Sstevel@tonic-gate 	proc = rqstp->rq_proc;
25861961e0fSrobinson 	(void) mutex_lock(&proglst_lock);
25961961e0fSrobinson 	for (pl = proglst; pl; pl = pl->p_nxt) {
2607c478bd9Sstevel@tonic-gate 		if (pl->p_prognum == prog && pl->p_procnum == proc &&
2617c478bd9Sstevel@tonic-gate 			pl->p_versnum == vers &&
2627c478bd9Sstevel@tonic-gate 			(strcmp(pl->p_netid, transp->xp_netid) == 0)) {
2637c478bd9Sstevel@tonic-gate 			/* decode arguments into a CLEAN buffer */
2647c478bd9Sstevel@tonic-gate 			xdrbuf = pl->p_xdrbuf;
2657c478bd9Sstevel@tonic-gate 			/* Zero the arguments: reqd ! */
2667c478bd9Sstevel@tonic-gate 			(void) memset(xdrbuf, 0, pl->p_recvsz);
2677c478bd9Sstevel@tonic-gate 			/*
2687c478bd9Sstevel@tonic-gate 			 * Assuming that sizeof (xdrbuf) would be enough
2697c478bd9Sstevel@tonic-gate 			 * for the arguments; if not then the program
2707c478bd9Sstevel@tonic-gate 			 * may bomb. BEWARE!
2717c478bd9Sstevel@tonic-gate 			 */
2727c478bd9Sstevel@tonic-gate 			if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) {
2737c478bd9Sstevel@tonic-gate 				svcerr_decode(transp);
27461961e0fSrobinson 				(void) mutex_unlock(&proglst_lock);
2757c478bd9Sstevel@tonic-gate 				return;
2767c478bd9Sstevel@tonic-gate 			}
2777c478bd9Sstevel@tonic-gate 			outdata = (*(pl->p_progname))(xdrbuf);
2787c478bd9Sstevel@tonic-gate 			if (outdata == NULL &&
2797c478bd9Sstevel@tonic-gate 				pl->p_outproc != (xdrproc_t)xdr_void) {
2807c478bd9Sstevel@tonic-gate 				/* there was an error */
28161961e0fSrobinson 				(void) mutex_unlock(&proglst_lock);
2827c478bd9Sstevel@tonic-gate 				return;
2837c478bd9Sstevel@tonic-gate 			}
2847c478bd9Sstevel@tonic-gate 			if (!svc_sendreply(transp, pl->p_outproc, outdata)) {
2857c478bd9Sstevel@tonic-gate 				(void) syslog(LOG_ERR, (const char *)
2867c478bd9Sstevel@tonic-gate 			"rpc: rpc_reg trouble replying to prog %d vers %d",
2877c478bd9Sstevel@tonic-gate 				prog, vers);
28861961e0fSrobinson 				(void) mutex_unlock(&proglst_lock);
2897c478bd9Sstevel@tonic-gate 				return;
2907c478bd9Sstevel@tonic-gate 			}
2917c478bd9Sstevel@tonic-gate 			/* free the decoded arguments */
2927c478bd9Sstevel@tonic-gate 			(void) svc_freeargs(transp, pl->p_inproc, xdrbuf);
29361961e0fSrobinson 			(void) mutex_unlock(&proglst_lock);
2947c478bd9Sstevel@tonic-gate 			return;
2957c478bd9Sstevel@tonic-gate 		}
29661961e0fSrobinson 	}
29761961e0fSrobinson 	(void) mutex_unlock(&proglst_lock);
2987c478bd9Sstevel@tonic-gate 	/* This should never happen */
2997c478bd9Sstevel@tonic-gate 	(void) syslog(LOG_ERR, (const char *)
3007c478bd9Sstevel@tonic-gate 		"rpc: rpc_reg: never registered prog %d vers %d",
3017c478bd9Sstevel@tonic-gate 		prog, vers);
3027c478bd9Sstevel@tonic-gate }
303