xref: /titanic_51/usr/src/lib/libnsl/rpc/svc_simple.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28 /*
29  * Portions of this source code were derived from Berkeley
30  * 4.3 BSD under license from the Regents of the University of
31  * California.
32  */
33 
34 #pragma ident	"%Z%%M%	%I%	%E% SMI"
35 
36 /*
37  * svc_simple.c
38  * Simplified front end to rpc.
39  */
40 
41 /*
42  * This interface creates a virtual listener for all the services
43  * started thru rpc_reg(). It listens on the same endpoint for
44  * all the services and then executes the corresponding service
45  * for the given prognum and procnum.
46  */
47 
48 #include "mt.h"
49 #include "rpc_mt.h"
50 #include <errno.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <rpc/rpc.h>
55 #include <sys/types.h>
56 #include <rpc/trace.h>
57 #include <syslog.h>
58 #include <rpc/nettype.h>
59 
60 static struct proglst {
61 	char *(*p_progname)();
62 	rpcprog_t p_prognum;
63 	rpcvers_t p_versnum;
64 	rpcproc_t p_procnum;
65 	SVCXPRT *p_transp;
66 	char *p_netid;
67 	char *p_xdrbuf;
68 	int p_recvsz;
69 	xdrproc_t p_inproc, p_outproc;
70 	struct proglst *p_nxt;
71 } *proglst;
72 
73 static void universal();
74 
75 static const char rpc_reg_err[] = "%s: %s";
76 static const char rpc_reg_msg[] = "rpc_reg: ";
77 static const char __reg_err1[] = "can't find appropriate transport";
78 static const char __reg_err3[] = "unsupported transport size";
79 static const char __no_mem_str[] = "out of memory";
80 /*
81  * For simplified, easy to use kind of rpc interfaces.
82  * nettype indicates the type of transport on which the service will be
83  * listening. Used for conservation of the system resource. Only one
84  * handle is created for all the services (actually one of each netid)
85  * and same xdrbuf is used for same netid. The size of the arguments
86  * is also limited by the recvsize for that transport, even if it is
87  * a COTS transport. This may be wrong, but for cases like these, they
88  * should not use the simplified interfaces like this.
89  */
90 
91 int
92 rpc_reg(prognum, versnum, procnum, progname, inproc, outproc, nettype)
93 	rpcprog_t prognum;		/* program number */
94 	rpcvers_t versnum;		/* version number */
95 	rpcproc_t procnum;		/* procedure number */
96 	char *(*progname)();		/* Server routine */
97 	xdrproc_t inproc, outproc;	/* in/out XDR procedures */
98 	const char *nettype;		/* nettype */
99 {
100 	struct netconfig *nconf;
101 	int done = FALSE;
102 	void *handle;
103 	extern mutex_t proglst_lock;
104 
105 
106 
107 	trace4(TR_rpc_reg, 0, prognum, versnum, procnum);
108 	if (procnum == NULLPROC) {
109 		(void) syslog(LOG_ERR, (const char *) "%s: %s %d",
110 			rpc_reg_msg,
111 			(const char *) "can't reassign procedure number %d",
112 			NULLPROC);
113 		trace4(TR_rpc_reg, 1, prognum, versnum, procnum);
114 		return (-1);
115 	}
116 
117 	if (nettype == NULL)
118 		nettype = "netpath";		/* The default behavior */
119 	if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
120 		(void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg, __reg_err1);
121 		return (-1);
122 	}
123 /* VARIABLES PROTECTED BY proglst_lock: proglst */
124 	mutex_lock(&proglst_lock);
125 	while (nconf = __rpc_getconf(handle)) {
126 		struct proglst *pl;
127 		SVCXPRT *svcxprt;
128 		int madenow;
129 		uint_t recvsz;
130 		char *xdrbuf;
131 		char *netid;
132 
133 		madenow = FALSE;
134 		svcxprt = (SVCXPRT *)NULL;
135 		for (pl = proglst; pl; pl = pl->p_nxt)
136 			if (strcmp(pl->p_netid, nconf->nc_netid) == 0) {
137 				svcxprt = pl->p_transp;
138 				xdrbuf = pl->p_xdrbuf;
139 				recvsz = pl->p_recvsz;
140 				netid = pl->p_netid;
141 				break;
142 			}
143 
144 		if (svcxprt == (SVCXPRT *)NULL) {
145 			struct t_info tinfo;
146 
147 			svcxprt = svc_tli_create(RPC_ANYFD, nconf,
148 					(struct t_bind *)NULL, 0, 0);
149 			if (svcxprt == (SVCXPRT *)NULL)
150 				continue;
151 			if (t_getinfo(svcxprt->xp_fd, &tinfo) == -1) {
152 				char errorstr[100];
153 
154 				__tli_sys_strerror(errorstr, sizeof (errorstr),
155 						t_errno, errno);
156 				(void) syslog(LOG_ERR, "%s : %s : %s",
157 					rpc_reg_msg, "t_getinfo failed",
158 					errorstr);
159 				SVC_DESTROY(svcxprt);
160 				continue;
161 			}
162 			if ((recvsz = __rpc_get_t_size(0, tinfo.tsdu)) == 0) {
163 				(void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg,
164 					__reg_err3);
165 				SVC_DESTROY(svcxprt);
166 				continue;
167 			}
168 			if (((xdrbuf = malloc((unsigned)recvsz)) == NULL) ||
169 				((netid = strdup(nconf->nc_netid)) == NULL)) {
170 				(void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg,
171 					__no_mem_str);
172 				SVC_DESTROY(svcxprt);
173 				break;
174 			}
175 			madenow = TRUE;
176 		}
177 		/*
178 		 * Check if this (program, version, netid) had already been
179 		 * registered.  The check may save a few RPC calls to rpcbind
180 		 */
181 		for (pl = proglst; pl; pl = pl->p_nxt)
182 			if ((pl->p_prognum == prognum) &&
183 				(pl->p_versnum == versnum) &&
184 				(strcmp(pl->p_netid, netid) == 0))
185 				break;
186 		if (pl == NULL) { /* Not yet */
187 			(void) rpcb_unset(prognum, versnum, nconf);
188 		} else {
189 			/* so that svc_reg does not call rpcb_set() */
190 			nconf = NULL;
191 		}
192 
193 		if (!svc_reg(svcxprt, prognum, versnum, universal, nconf)) {
194 			(void) syslog(LOG_ERR,
195 				"%s couldn't register prog %d vers %d for %s",
196 				rpc_reg_msg, prognum, versnum, netid);
197 			if (madenow) {
198 				SVC_DESTROY(svcxprt);
199 				free(xdrbuf);
200 				free(netid);
201 			}
202 			continue;
203 		}
204 
205 		pl = (struct proglst *)malloc(sizeof (struct proglst));
206 		if (pl == (struct proglst *)NULL) {
207 			(void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg,
208 					__no_mem_str);
209 			if (madenow) {
210 				SVC_DESTROY(svcxprt);
211 				free(xdrbuf);
212 				free(netid);
213 			}
214 			break;
215 		}
216 		pl->p_progname = progname;
217 		pl->p_prognum = prognum;
218 		pl->p_versnum = versnum;
219 		pl->p_procnum = procnum;
220 		pl->p_inproc = inproc;
221 		pl->p_outproc = outproc;
222 		pl->p_transp = svcxprt;
223 		pl->p_xdrbuf = xdrbuf;
224 		pl->p_recvsz = recvsz;
225 		pl->p_netid = netid;
226 		pl->p_nxt = proglst;
227 		proglst = pl;
228 		done = TRUE;
229 	}
230 	__rpc_endconf(handle);
231 	mutex_unlock(&proglst_lock);
232 
233 	if (done == FALSE) {
234 		(void) syslog(LOG_ERR,
235 			(const char *) "%s cant find suitable transport for %s",
236 			rpc_reg_msg, nettype);
237 		trace4(TR_rpc_reg, 1, prognum, versnum, procnum);
238 		return (-1);
239 	}
240 	trace4(TR_rpc_reg, 1, prognum, versnum, procnum);
241 	return (0);
242 }
243 
244 /*
245  * The universal handler for the services registered using registerrpc.
246  * It handles both the connectionless and the connection oriented cases.
247  */
248 
249 static const char __univ_err[] = " prog %d vers %d";
250 static void
251 universal(rqstp, transp)
252 	struct svc_req *rqstp;
253 	SVCXPRT *transp;
254 {
255 	rpcprog_t prog;
256 	rpcvers_t vers;
257 	rpcproc_t proc;
258 	char *outdata;
259 	char *xdrbuf;
260 	struct proglst *pl;
261 	extern mutex_t proglst_lock;
262 
263 	/*
264 	 * enforce "procnum 0 is echo" convention
265 	 */
266 	trace1(TR_universal, 0);
267 	if (rqstp->rq_proc == NULLPROC) {
268 		if (svc_sendreply(transp, (xdrproc_t)xdr_void,
269 			(char *)NULL) == FALSE) {
270 			(void) syslog(LOG_ERR,
271 				(const char *) "svc_sendreply failed");
272 		}
273 		trace1(TR_universal, 1);
274 		return;
275 	}
276 	prog = rqstp->rq_prog;
277 	vers = rqstp->rq_vers;
278 	proc = rqstp->rq_proc;
279 	mutex_lock(&proglst_lock);
280 	for (pl = proglst; pl; pl = pl->p_nxt)
281 		if (pl->p_prognum == prog && pl->p_procnum == proc &&
282 			pl->p_versnum == vers &&
283 			(strcmp(pl->p_netid, transp->xp_netid) == 0)) {
284 			/* decode arguments into a CLEAN buffer */
285 			xdrbuf = pl->p_xdrbuf;
286 			/* Zero the arguments: reqd ! */
287 			(void) memset(xdrbuf, 0, pl->p_recvsz);
288 			/*
289 			 * Assuming that sizeof (xdrbuf) would be enough
290 			 * for the arguments; if not then the program
291 			 * may bomb. BEWARE!
292 			 */
293 			if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) {
294 				svcerr_decode(transp);
295 				mutex_unlock(&proglst_lock);
296 				trace1(TR_universal, 1);
297 				return;
298 			}
299 			outdata = (*(pl->p_progname))(xdrbuf);
300 			if (outdata == NULL &&
301 				pl->p_outproc != (xdrproc_t)xdr_void) {
302 				/* there was an error */
303 				mutex_unlock(&proglst_lock);
304 				trace1(TR_universal, 1);
305 				return;
306 			}
307 			if (!svc_sendreply(transp, pl->p_outproc, outdata)) {
308 				(void) syslog(LOG_ERR, (const char *)
309 			"rpc: rpc_reg trouble replying to prog %d vers %d",
310 				prog, vers);
311 				mutex_unlock(&proglst_lock);
312 				trace1(TR_universal, 1);
313 				return;
314 			}
315 			/* free the decoded arguments */
316 			(void) svc_freeargs(transp, pl->p_inproc, xdrbuf);
317 			mutex_unlock(&proglst_lock);
318 			trace1(TR_universal, 1);
319 			return;
320 		}
321 	mutex_unlock(&proglst_lock);
322 	/* This should never happen */
323 	(void) syslog(LOG_ERR, (const char *)
324 		"rpc: rpc_reg: never registered prog %d vers %d",
325 		prog, vers);
326 	trace1(TR_universal, 1);
327 }
328