xref: /dflybsd-src/lib/libc/rpc/svc_generic.c (revision ce0e08e21d42c06c0014fae6b9d27144aa5109b0)
1*ce0e08e2SPeter Avalos /*
2*ce0e08e2SPeter Avalos  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3*ce0e08e2SPeter Avalos  * unrestricted use provided that this legend is included on all tape
4*ce0e08e2SPeter Avalos  * media and as a part of the software program in whole or part.  Users
5*ce0e08e2SPeter Avalos  * may copy or modify Sun RPC without charge, but are not authorized
6*ce0e08e2SPeter Avalos  * to license or distribute it to anyone else except as part of a product or
7*ce0e08e2SPeter Avalos  * program developed by the user.
8*ce0e08e2SPeter Avalos  *
9*ce0e08e2SPeter Avalos  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10*ce0e08e2SPeter Avalos  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11*ce0e08e2SPeter Avalos  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12*ce0e08e2SPeter Avalos  *
13*ce0e08e2SPeter Avalos  * Sun RPC is provided with no support and without any obligation on the
14*ce0e08e2SPeter Avalos  * part of Sun Microsystems, Inc. to assist in its use, correction,
15*ce0e08e2SPeter Avalos  * modification or enhancement.
16*ce0e08e2SPeter Avalos  *
17*ce0e08e2SPeter Avalos  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18*ce0e08e2SPeter Avalos  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19*ce0e08e2SPeter Avalos  * OR ANY PART THEREOF.
20*ce0e08e2SPeter Avalos  *
21*ce0e08e2SPeter Avalos  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22*ce0e08e2SPeter Avalos  * or profits or other special, indirect and consequential damages, even if
23*ce0e08e2SPeter Avalos  * Sun has been advised of the possibility of such damages.
24*ce0e08e2SPeter Avalos  *
25*ce0e08e2SPeter Avalos  * Sun Microsystems, Inc.
26*ce0e08e2SPeter Avalos  * 2550 Garcia Avenue
27*ce0e08e2SPeter Avalos  * Mountain View, California  94043
28*ce0e08e2SPeter Avalos  *
29*ce0e08e2SPeter Avalos  * @(#)svc_generic.c	1.19	94/04/24 SMI; 1.21 89/02/28 Copyr 1988 Sun Micro
30*ce0e08e2SPeter Avalos  * $NetBSD: svc_generic.c,v 1.3 2000/07/06 03:10:35 christos Exp $
31*ce0e08e2SPeter Avalos  * $FreeBSD: src/lib/libc/rpc/svc_generic.c,v 1.7 2006/02/27 22:10:59 deischen Exp $
32*ce0e08e2SPeter Avalos  * $DragonFly$
33*ce0e08e2SPeter Avalos  */
34*ce0e08e2SPeter Avalos 
35*ce0e08e2SPeter Avalos /*
36*ce0e08e2SPeter Avalos  * Copyright (c) 1986-1991 by Sun Microsystems Inc.
37*ce0e08e2SPeter Avalos  */
38*ce0e08e2SPeter Avalos 
39*ce0e08e2SPeter Avalos /*
40*ce0e08e2SPeter Avalos  * svc_generic.c, Server side for RPC.
41*ce0e08e2SPeter Avalos  */
42*ce0e08e2SPeter Avalos 
43*ce0e08e2SPeter Avalos #include "namespace.h"
44*ce0e08e2SPeter Avalos #include "reentrant.h"
45*ce0e08e2SPeter Avalos #include <sys/types.h>
46*ce0e08e2SPeter Avalos #include <sys/socket.h>
47*ce0e08e2SPeter Avalos #include <netinet/in.h>
48*ce0e08e2SPeter Avalos #include <rpc/rpc.h>
49*ce0e08e2SPeter Avalos #include <rpc/nettype.h>
50*ce0e08e2SPeter Avalos #include <stdio.h>
51*ce0e08e2SPeter Avalos #include <errno.h>
52*ce0e08e2SPeter Avalos #include <stdlib.h>
53*ce0e08e2SPeter Avalos #include <string.h>
54*ce0e08e2SPeter Avalos #include <unistd.h>
55*ce0e08e2SPeter Avalos #include <err.h>
56*ce0e08e2SPeter Avalos #include "un-namespace.h"
57*ce0e08e2SPeter Avalos 
58*ce0e08e2SPeter Avalos #include "rpc_com.h"
59*ce0e08e2SPeter Avalos #include "mt_misc.h"
60*ce0e08e2SPeter Avalos 
61*ce0e08e2SPeter Avalos extern int __svc_vc_setflag(SVCXPRT *, int);
62*ce0e08e2SPeter Avalos 
63*ce0e08e2SPeter Avalos /*
64*ce0e08e2SPeter Avalos  * The highest level interface for server creation.
65*ce0e08e2SPeter Avalos  * It tries for all the nettokens in that particular class of token
66*ce0e08e2SPeter Avalos  * and returns the number of handles it can create and/or find.
67*ce0e08e2SPeter Avalos  *
68*ce0e08e2SPeter Avalos  * It creates a link list of all the handles it could create.
69*ce0e08e2SPeter Avalos  * If svc_create() is called multiple times, it uses the handle
70*ce0e08e2SPeter Avalos  * created earlier instead of creating a new handle every time.
71*ce0e08e2SPeter Avalos  */
72*ce0e08e2SPeter Avalos int
73*ce0e08e2SPeter Avalos svc_create(void (*dispatch)(struct svc_req *, SVCXPRT *),
74*ce0e08e2SPeter Avalos 	   rpcprog_t prognum,		/* Program number */
75*ce0e08e2SPeter Avalos 	   rpcvers_t versnum,		/* Version number */
76*ce0e08e2SPeter Avalos 	   const char *nettype)		/* Networktype token */
77*ce0e08e2SPeter Avalos {
78*ce0e08e2SPeter Avalos 	struct xlist {
79*ce0e08e2SPeter Avalos 		SVCXPRT *xprt;		/* Server handle */
80*ce0e08e2SPeter Avalos 		struct xlist *next;	/* Next item */
81*ce0e08e2SPeter Avalos 	} *l;
82*ce0e08e2SPeter Avalos 	static struct xlist *xprtlist;	/* A link list of all the handles */
83*ce0e08e2SPeter Avalos 	int num = 0;
84*ce0e08e2SPeter Avalos 	SVCXPRT *xprt;
85*ce0e08e2SPeter Avalos 	struct netconfig *nconf;
86*ce0e08e2SPeter Avalos 	void *handle;
87*ce0e08e2SPeter Avalos 
88*ce0e08e2SPeter Avalos /* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */
89*ce0e08e2SPeter Avalos 
90*ce0e08e2SPeter Avalos 	if ((handle = __rpc_setconf(nettype)) == NULL) {
91*ce0e08e2SPeter Avalos 		warnx("svc_create: unknown protocol");
92*ce0e08e2SPeter Avalos 		return (0);
93*ce0e08e2SPeter Avalos 	}
94*ce0e08e2SPeter Avalos 	while ((nconf = __rpc_getconf(handle)) != NULL) {
95*ce0e08e2SPeter Avalos 		mutex_lock(&xprtlist_lock);
96*ce0e08e2SPeter Avalos 		for (l = xprtlist; l; l = l->next) {
97*ce0e08e2SPeter Avalos 			if (strcmp(l->xprt->xp_netid, nconf->nc_netid) == 0) {
98*ce0e08e2SPeter Avalos 				/* Found an old one, use it */
99*ce0e08e2SPeter Avalos 				rpcb_unset(prognum, versnum, nconf);
100*ce0e08e2SPeter Avalos 				if (svc_reg(l->xprt, prognum, versnum,
101*ce0e08e2SPeter Avalos 					dispatch, nconf) == FALSE)
102*ce0e08e2SPeter Avalos 					warnx(
103*ce0e08e2SPeter Avalos 		"svc_create: could not register prog %u vers %u on %s",
104*ce0e08e2SPeter Avalos 					(unsigned)prognum, (unsigned)versnum,
105*ce0e08e2SPeter Avalos 					 nconf->nc_netid);
106*ce0e08e2SPeter Avalos 				else
107*ce0e08e2SPeter Avalos 					num++;
108*ce0e08e2SPeter Avalos 				break;
109*ce0e08e2SPeter Avalos 			}
110*ce0e08e2SPeter Avalos 		}
111*ce0e08e2SPeter Avalos 		if (l == NULL) {
112*ce0e08e2SPeter Avalos 			/* It was not found. Now create a new one */
113*ce0e08e2SPeter Avalos 			xprt = svc_tp_create(dispatch, prognum, versnum, nconf);
114*ce0e08e2SPeter Avalos 			if (xprt) {
115*ce0e08e2SPeter Avalos 				l = (struct xlist *)malloc(sizeof (*l));
116*ce0e08e2SPeter Avalos 				if (l == NULL) {
117*ce0e08e2SPeter Avalos 					warnx("svc_create: no memory");
118*ce0e08e2SPeter Avalos 					mutex_unlock(&xprtlist_lock);
119*ce0e08e2SPeter Avalos 					return (0);
120*ce0e08e2SPeter Avalos 				}
121*ce0e08e2SPeter Avalos 				l->xprt = xprt;
122*ce0e08e2SPeter Avalos 				l->next = xprtlist;
123*ce0e08e2SPeter Avalos 				xprtlist = l;
124*ce0e08e2SPeter Avalos 				num++;
125*ce0e08e2SPeter Avalos 			}
126*ce0e08e2SPeter Avalos 		}
127*ce0e08e2SPeter Avalos 		mutex_unlock(&xprtlist_lock);
128*ce0e08e2SPeter Avalos 	}
129*ce0e08e2SPeter Avalos 	__rpc_endconf(handle);
130*ce0e08e2SPeter Avalos 	/*
131*ce0e08e2SPeter Avalos 	 * In case of num == 0; the error messages are generated by the
132*ce0e08e2SPeter Avalos 	 * underlying layers; and hence not needed here.
133*ce0e08e2SPeter Avalos 	 */
134*ce0e08e2SPeter Avalos 	return (num);
135*ce0e08e2SPeter Avalos }
136*ce0e08e2SPeter Avalos 
137*ce0e08e2SPeter Avalos /*
138*ce0e08e2SPeter Avalos  * The high level interface to svc_tli_create().
139*ce0e08e2SPeter Avalos  * It tries to create a server for "nconf" and registers the service
140*ce0e08e2SPeter Avalos  * with the rpcbind. It calls svc_tli_create();
141*ce0e08e2SPeter Avalos  */
142*ce0e08e2SPeter Avalos SVCXPRT *
143*ce0e08e2SPeter Avalos svc_tp_create(void (*dispatch)(struct svc_req *, SVCXPRT *),
144*ce0e08e2SPeter Avalos 	      rpcprog_t prognum,		/* Program number */
145*ce0e08e2SPeter Avalos 	      rpcvers_t versnum,		/* Version number */
146*ce0e08e2SPeter Avalos 	      const struct netconfig *nconf)	/* Netconfig structure for the network */
147*ce0e08e2SPeter Avalos {
148*ce0e08e2SPeter Avalos 	SVCXPRT *xprt;
149*ce0e08e2SPeter Avalos 
150*ce0e08e2SPeter Avalos 	if (nconf == NULL) {
151*ce0e08e2SPeter Avalos 		warnx(
152*ce0e08e2SPeter Avalos 	"svc_tp_create: invalid netconfig structure for prog %u vers %u",
153*ce0e08e2SPeter Avalos 				(unsigned)prognum, (unsigned)versnum);
154*ce0e08e2SPeter Avalos 		return (NULL);
155*ce0e08e2SPeter Avalos 	}
156*ce0e08e2SPeter Avalos 	xprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0);
157*ce0e08e2SPeter Avalos 	if (xprt == NULL) {
158*ce0e08e2SPeter Avalos 		return (NULL);
159*ce0e08e2SPeter Avalos 	}
160*ce0e08e2SPeter Avalos 	/*LINTED const castaway*/
161*ce0e08e2SPeter Avalos 	rpcb_unset(prognum, versnum, (struct netconfig *) nconf);
162*ce0e08e2SPeter Avalos 	if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
163*ce0e08e2SPeter Avalos 		warnx(
164*ce0e08e2SPeter Avalos 		"svc_tp_create: Could not register prog %u vers %u on %s",
165*ce0e08e2SPeter Avalos 				(unsigned)prognum, (unsigned)versnum,
166*ce0e08e2SPeter Avalos 				nconf->nc_netid);
167*ce0e08e2SPeter Avalos 		SVC_DESTROY(xprt);
168*ce0e08e2SPeter Avalos 		return (NULL);
169*ce0e08e2SPeter Avalos 	}
170*ce0e08e2SPeter Avalos 	return (xprt);
171*ce0e08e2SPeter Avalos }
172*ce0e08e2SPeter Avalos 
173*ce0e08e2SPeter Avalos /*
174*ce0e08e2SPeter Avalos  * If fd is RPC_ANYFD, then it opens a fd for the given transport
175*ce0e08e2SPeter Avalos  * provider (nconf cannot be NULL then). If the t_state is T_UNBND and
176*ce0e08e2SPeter Avalos  * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For
177*ce0e08e2SPeter Avalos  * NULL bindadr and Connection oriented transports, the value of qlen
178*ce0e08e2SPeter Avalos  * is set to 8.
179*ce0e08e2SPeter Avalos  *
180*ce0e08e2SPeter Avalos  * If sendsz or recvsz are zero, their default values are chosen.
181*ce0e08e2SPeter Avalos  */
182*ce0e08e2SPeter Avalos SVCXPRT *
183*ce0e08e2SPeter Avalos svc_tli_create(
184*ce0e08e2SPeter Avalos 	int fd,				/* Connection end point */
185*ce0e08e2SPeter Avalos 	const struct netconfig *nconf,	/* Netconfig struct for nettoken */
186*ce0e08e2SPeter Avalos 	const struct t_bind *bindaddr,	/* Local bind address */
187*ce0e08e2SPeter Avalos 	u_int sendsz,			/* Max sendsize */
188*ce0e08e2SPeter Avalos 	u_int recvsz)			/* Max recvsize */
189*ce0e08e2SPeter Avalos {
190*ce0e08e2SPeter Avalos 	SVCXPRT *xprt = NULL;		/* service handle */
191*ce0e08e2SPeter Avalos 	bool_t madefd = FALSE;		/* whether fd opened here  */
192*ce0e08e2SPeter Avalos 	struct __rpc_sockinfo si;
193*ce0e08e2SPeter Avalos 	struct sockaddr_storage ss;
194*ce0e08e2SPeter Avalos 	socklen_t slen;
195*ce0e08e2SPeter Avalos 
196*ce0e08e2SPeter Avalos 	if (fd == RPC_ANYFD) {
197*ce0e08e2SPeter Avalos 		if (nconf == NULL) {
198*ce0e08e2SPeter Avalos 			warnx("svc_tli_create: invalid netconfig");
199*ce0e08e2SPeter Avalos 			return (NULL);
200*ce0e08e2SPeter Avalos 		}
201*ce0e08e2SPeter Avalos 		fd = __rpc_nconf2fd(nconf);
202*ce0e08e2SPeter Avalos 		if (fd == -1) {
203*ce0e08e2SPeter Avalos 			warnx(
204*ce0e08e2SPeter Avalos 			    "svc_tli_create: could not open connection for %s",
205*ce0e08e2SPeter Avalos 					nconf->nc_netid);
206*ce0e08e2SPeter Avalos 			return (NULL);
207*ce0e08e2SPeter Avalos 		}
208*ce0e08e2SPeter Avalos 		__rpc_nconf2sockinfo(nconf, &si);
209*ce0e08e2SPeter Avalos 		madefd = TRUE;
210*ce0e08e2SPeter Avalos 	} else {
211*ce0e08e2SPeter Avalos 		/*
212*ce0e08e2SPeter Avalos 		 * It is an open descriptor. Get the transport info.
213*ce0e08e2SPeter Avalos 		 */
214*ce0e08e2SPeter Avalos 		if (!__rpc_fd2sockinfo(fd, &si)) {
215*ce0e08e2SPeter Avalos 			warnx(
216*ce0e08e2SPeter Avalos 		"svc_tli_create: could not get transport information");
217*ce0e08e2SPeter Avalos 			return (NULL);
218*ce0e08e2SPeter Avalos 		}
219*ce0e08e2SPeter Avalos 	}
220*ce0e08e2SPeter Avalos 
221*ce0e08e2SPeter Avalos 	/*
222*ce0e08e2SPeter Avalos 	 * If the fd is unbound, try to bind it.
223*ce0e08e2SPeter Avalos 	 */
224*ce0e08e2SPeter Avalos 	if (madefd || !__rpc_sockisbound(fd)) {
225*ce0e08e2SPeter Avalos 		if (bindaddr == NULL) {
226*ce0e08e2SPeter Avalos 			if (bindresvport(fd, NULL) < 0) {
227*ce0e08e2SPeter Avalos 				memset(&ss, 0, sizeof ss);
228*ce0e08e2SPeter Avalos 				ss.ss_family = si.si_af;
229*ce0e08e2SPeter Avalos 				ss.ss_len = si.si_alen;
230*ce0e08e2SPeter Avalos 				if (_bind(fd, (struct sockaddr *)(void *)&ss,
231*ce0e08e2SPeter Avalos 				    (socklen_t)si.si_alen) < 0) {
232*ce0e08e2SPeter Avalos 					warnx(
233*ce0e08e2SPeter Avalos 			"svc_tli_create: could not bind to anonymous port");
234*ce0e08e2SPeter Avalos 					goto freedata;
235*ce0e08e2SPeter Avalos 				}
236*ce0e08e2SPeter Avalos 			}
237*ce0e08e2SPeter Avalos 			_listen(fd, SOMAXCONN);
238*ce0e08e2SPeter Avalos 		} else {
239*ce0e08e2SPeter Avalos 			if (_bind(fd,
240*ce0e08e2SPeter Avalos 			    (struct sockaddr *)bindaddr->addr.buf,
241*ce0e08e2SPeter Avalos 			    (socklen_t)si.si_alen) < 0) {
242*ce0e08e2SPeter Avalos 				warnx(
243*ce0e08e2SPeter Avalos 		"svc_tli_create: could not bind to requested address");
244*ce0e08e2SPeter Avalos 				goto freedata;
245*ce0e08e2SPeter Avalos 			}
246*ce0e08e2SPeter Avalos 			_listen(fd, (int)bindaddr->qlen);
247*ce0e08e2SPeter Avalos 		}
248*ce0e08e2SPeter Avalos 
249*ce0e08e2SPeter Avalos 	}
250*ce0e08e2SPeter Avalos 	/*
251*ce0e08e2SPeter Avalos 	 * call transport specific function.
252*ce0e08e2SPeter Avalos 	 */
253*ce0e08e2SPeter Avalos 	switch (si.si_socktype) {
254*ce0e08e2SPeter Avalos 		case SOCK_STREAM:
255*ce0e08e2SPeter Avalos 			slen = sizeof ss;
256*ce0e08e2SPeter Avalos 			if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen)
257*ce0e08e2SPeter Avalos 			    == 0) {
258*ce0e08e2SPeter Avalos 				/* accepted socket */
259*ce0e08e2SPeter Avalos 				xprt = svc_fd_create(fd, sendsz, recvsz);
260*ce0e08e2SPeter Avalos 			} else
261*ce0e08e2SPeter Avalos 				xprt = svc_vc_create(fd, sendsz, recvsz);
262*ce0e08e2SPeter Avalos 			if (!nconf || !xprt)
263*ce0e08e2SPeter Avalos 				break;
264*ce0e08e2SPeter Avalos #if 0
265*ce0e08e2SPeter Avalos 			/* XXX fvdl */
266*ce0e08e2SPeter Avalos 			if (strcmp(nconf->nc_protofmly, "inet") == 0 ||
267*ce0e08e2SPeter Avalos 			    strcmp(nconf->nc_protofmly, "inet6") == 0)
268*ce0e08e2SPeter Avalos 				(void) __svc_vc_setflag(xprt, TRUE);
269*ce0e08e2SPeter Avalos #endif
270*ce0e08e2SPeter Avalos 			break;
271*ce0e08e2SPeter Avalos 		case SOCK_DGRAM:
272*ce0e08e2SPeter Avalos 			xprt = svc_dg_create(fd, sendsz, recvsz);
273*ce0e08e2SPeter Avalos 			break;
274*ce0e08e2SPeter Avalos 		default:
275*ce0e08e2SPeter Avalos 			warnx("svc_tli_create: bad service type");
276*ce0e08e2SPeter Avalos 			goto freedata;
277*ce0e08e2SPeter Avalos 	}
278*ce0e08e2SPeter Avalos 
279*ce0e08e2SPeter Avalos 	if (xprt == NULL)
280*ce0e08e2SPeter Avalos 		/*
281*ce0e08e2SPeter Avalos 		 * The error messages here are spitted out by the lower layers:
282*ce0e08e2SPeter Avalos 		 * svc_vc_create(), svc_fd_create() and svc_dg_create().
283*ce0e08e2SPeter Avalos 		 */
284*ce0e08e2SPeter Avalos 		goto freedata;
285*ce0e08e2SPeter Avalos 
286*ce0e08e2SPeter Avalos 	/* Fill in type of service */
287*ce0e08e2SPeter Avalos 	xprt->xp_type = __rpc_socktype2seman(si.si_socktype);
288*ce0e08e2SPeter Avalos 
289*ce0e08e2SPeter Avalos 	if (nconf) {
290*ce0e08e2SPeter Avalos 		xprt->xp_netid = strdup(nconf->nc_netid);
291*ce0e08e2SPeter Avalos 		xprt->xp_tp = strdup(nconf->nc_device);
292*ce0e08e2SPeter Avalos 	}
293*ce0e08e2SPeter Avalos 	return (xprt);
294*ce0e08e2SPeter Avalos 
295*ce0e08e2SPeter Avalos freedata:
296*ce0e08e2SPeter Avalos 	if (madefd)
297*ce0e08e2SPeter Avalos 		_close(fd);
298*ce0e08e2SPeter Avalos 	if (xprt) {
299*ce0e08e2SPeter Avalos 		if (!madefd) /* so that svc_destroy doesnt close fd */
300*ce0e08e2SPeter Avalos 			xprt->xp_fd = RPC_ANYFD;
301*ce0e08e2SPeter Avalos 		SVC_DESTROY(xprt);
302*ce0e08e2SPeter Avalos 	}
303*ce0e08e2SPeter Avalos 	return (NULL);
304*ce0e08e2SPeter Avalos }
305