svc_generic.c revision 261046
1/*	$NetBSD: svc_generic.c,v 1.3 2000/07/06 03:10:35 christos Exp $	*/
2
3/*-
4 * Copyright (c) 2009, Sun Microsystems, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * - Redistributions of source code must retain the above copyright notice,
10 *   this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright notice,
12 *   this list of conditions and the following disclaimer in the documentation
13 *   and/or other materials provided with the distribution.
14 * - Neither the name of Sun Microsystems, Inc. nor the names of its
15 *   contributors may be used to endorse or promote products derived
16 *   from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/*
32 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
33 */
34
35#if defined(LIBC_SCCS) && !defined(lint)
36#ident	"@(#)svc_generic.c	1.19	94/04/24 SMI"
37static char sccsid[] = "@(#)svc_generic.c 1.21 89/02/28 Copyr 1988 Sun Micro";
38#endif
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: stable/10/sys/rpc/svc_generic.c 261046 2014-01-22 23:45:27Z mav $");
41
42/*
43 * svc_generic.c, Server side for RPC.
44 *
45 */
46
47#include "opt_inet6.h"
48
49#include <sys/param.h>
50#include <sys/lock.h>
51#include <sys/kernel.h>
52#include <sys/malloc.h>
53#include <sys/mutex.h>
54#include <sys/protosw.h>
55#include <sys/queue.h>
56#include <sys/socket.h>
57#include <sys/socketvar.h>
58#include <sys/systm.h>
59#include <sys/sx.h>
60#include <sys/ucred.h>
61
62#include <net/vnet.h>
63
64#include <rpc/rpc.h>
65#include <rpc/rpcb_clnt.h>
66#include <rpc/nettype.h>
67
68#include <rpc/rpc_com.h>
69
70extern int __svc_vc_setflag(SVCXPRT *, int);
71
72/*
73 * The highest level interface for server creation.
74 * It tries for all the nettokens in that particular class of token
75 * and returns the number of handles it can create and/or find.
76 *
77 * It creates a link list of all the handles it could create.
78 * If svc_create() is called multiple times, it uses the handle
79 * created earlier instead of creating a new handle every time.
80 */
81int
82svc_create(
83	SVCPOOL *pool,
84	void (*dispatch)(struct svc_req *, SVCXPRT *),
85	rpcprog_t prognum,		/* Program number */
86	rpcvers_t versnum,		/* Version number */
87	const char *nettype)		/* Networktype token */
88{
89	int num = 0;
90	SVCXPRT *xprt;
91	struct netconfig *nconf;
92	void *handle;
93
94	if ((handle = __rpc_setconf(nettype)) == NULL) {
95		printf("svc_create: unknown protocol");
96		return (0);
97	}
98	while ((nconf = __rpc_getconf(handle)) != NULL) {
99		mtx_lock(&pool->sp_lock);
100		TAILQ_FOREACH(xprt, &pool->sp_xlist, xp_link) {
101			if (strcmp(xprt->xp_netid, nconf->nc_netid) == 0) {
102				/* Found an old one, use it */
103				mtx_unlock(&pool->sp_lock);
104				(void) rpcb_unset(prognum, versnum, nconf);
105				if (svc_reg(xprt, prognum, versnum,
106					dispatch, nconf) == FALSE) {
107					printf(
108		"svc_create: could not register prog %u vers %u on %s\n",
109					(unsigned)prognum, (unsigned)versnum,
110					 nconf->nc_netid);
111					mtx_lock(&pool->sp_lock);
112				} else {
113					num++;
114					mtx_lock(&pool->sp_lock);
115					break;
116				}
117			}
118		}
119		mtx_unlock(&pool->sp_lock);
120		if (xprt == NULL) {
121			/* It was not found. Now create a new one */
122			xprt = svc_tp_create(pool, dispatch, prognum, versnum,
123			    NULL, nconf);
124			if (xprt) {
125				num++;
126				SVC_RELEASE(xprt);
127			}
128		}
129	}
130	__rpc_endconf(handle);
131	/*
132	 * In case of num == 0; the error messages are generated by the
133	 * underlying layers; and hence not needed here.
134	 */
135	return (num);
136}
137
138/*
139 * The high level interface to svc_tli_create().
140 * It tries to create a server for "nconf" and registers the service
141 * with the rpcbind. It calls svc_tli_create();
142 */
143SVCXPRT *
144svc_tp_create(
145	SVCPOOL *pool,
146	void (*dispatch)(struct svc_req *, SVCXPRT *),
147	rpcprog_t prognum,		/* Program number */
148	rpcvers_t versnum,		/* Version number */
149	const char *uaddr,		/* Address (or null for default) */
150	const struct netconfig *nconf) /* Netconfig structure for the network */
151{
152	struct netconfig nconfcopy;
153	struct netbuf *taddr;
154	struct t_bind bind;
155	SVCXPRT *xprt;
156
157	if (nconf == NULL) {
158		printf(
159	"svc_tp_create: invalid netconfig structure for prog %u vers %u\n",
160				(unsigned)prognum, (unsigned)versnum);
161		return (NULL);
162	}
163	if (uaddr) {
164		taddr = uaddr2taddr(nconf, uaddr);
165		bind.addr = *taddr;
166		free(taddr, M_RPC);
167		bind.qlen = SOMAXCONN;
168		xprt = svc_tli_create(pool, NULL, nconf, &bind, 0, 0);
169		free(bind.addr.buf, M_RPC);
170	} else {
171		xprt = svc_tli_create(pool, NULL, nconf, NULL, 0, 0);
172	}
173	if (xprt == NULL) {
174		return (NULL);
175	}
176	/*LINTED const castaway*/
177	nconfcopy = *nconf;
178	(void) rpcb_unset(prognum, versnum, &nconfcopy);
179	if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
180		printf(
181		"svc_tp_create: Could not register prog %u vers %u on %s\n",
182				(unsigned)prognum, (unsigned)versnum,
183				nconf->nc_netid);
184		xprt_unregister(xprt);
185		SVC_RELEASE(xprt);
186		return (NULL);
187	}
188	return (xprt);
189}
190
191/*
192 * If so is NULL, then it opens a socket for the given transport
193 * provider (nconf cannot be NULL then). If the t_state is T_UNBND and
194 * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For
195 * NULL bindadr and Connection oriented transports, the value of qlen
196 * is set to 8.
197 *
198 * If sendsz or recvsz are zero, their default values are chosen.
199 */
200SVCXPRT *
201svc_tli_create(
202	SVCPOOL *pool,
203	struct socket *so,		/* Connection end point */
204	const struct netconfig *nconf,	/* Netconfig struct for nettoken */
205	const struct t_bind *bindaddr,	/* Local bind address */
206	size_t sendsz,			/* Max sendsize */
207	size_t recvsz)			/* Max recvsize */
208{
209	SVCXPRT *xprt = NULL;		/* service handle */
210	bool_t madeso = FALSE;		/* whether so opened here  */
211	struct __rpc_sockinfo si;
212	struct sockaddr_storage ss;
213
214	if (!so) {
215		if (nconf == NULL) {
216			printf("svc_tli_create: invalid netconfig\n");
217			return (NULL);
218		}
219		so = __rpc_nconf2socket(nconf);
220		if (!so) {
221			printf(
222			    "svc_tli_create: could not open connection for %s\n",
223					nconf->nc_netid);
224			return (NULL);
225		}
226		__rpc_nconf2sockinfo(nconf, &si);
227		madeso = TRUE;
228	} else {
229		/*
230		 * It is an open socket. Get the transport info.
231		 */
232		if (!__rpc_socket2sockinfo(so, &si)) {
233			printf(
234		"svc_tli_create: could not get transport information\n");
235			return (NULL);
236		}
237	}
238
239	/*
240	 * If the socket is unbound, try to bind it.
241	 */
242	if (madeso || !__rpc_sockisbound(so)) {
243		if (bindaddr == NULL) {
244			if (bindresvport(so, NULL)) {
245				memset(&ss, 0, sizeof ss);
246				ss.ss_family = si.si_af;
247				ss.ss_len = si.si_alen;
248				if (sobind(so, (struct sockaddr *)&ss,
249					curthread)) {
250					printf(
251			"svc_tli_create: could not bind to anonymous port\n");
252					goto freedata;
253				}
254			}
255			solisten(so, SOMAXCONN, curthread);
256		} else {
257			if (bindresvport(so,
258				(struct sockaddr *)bindaddr->addr.buf)) {
259				printf(
260		"svc_tli_create: could not bind to requested address\n");
261				goto freedata;
262			}
263			solisten(so, (int)bindaddr->qlen, curthread);
264		}
265
266	}
267	/*
268	 * call transport specific function.
269	 */
270	switch (si.si_socktype) {
271		case SOCK_STREAM:
272#if 0
273			slen = sizeof ss;
274			if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen)
275			    == 0) {
276				/* accepted socket */
277				xprt = svc_fd_create(fd, sendsz, recvsz);
278			} else
279#endif
280				xprt = svc_vc_create(pool, so, sendsz, recvsz);
281			if (!nconf || !xprt)
282				break;
283#if 0
284			/* XXX fvdl */
285			if (strcmp(nconf->nc_protofmly, "inet") == 0 ||
286			    strcmp(nconf->nc_protofmly, "inet6") == 0)
287				(void) __svc_vc_setflag(xprt, TRUE);
288#endif
289			break;
290		case SOCK_DGRAM:
291			xprt = svc_dg_create(pool, so, sendsz, recvsz);
292			break;
293		default:
294			printf("svc_tli_create: bad service type");
295			goto freedata;
296	}
297
298	if (xprt == NULL)
299		/*
300		 * The error messages here are spitted out by the lower layers:
301		 * svc_vc_create(), svc_fd_create() and svc_dg_create().
302		 */
303		goto freedata;
304
305	/* Fill in type of service */
306	xprt->xp_type = __rpc_socktype2seman(si.si_socktype);
307
308	if (nconf) {
309		xprt->xp_netid = strdup(nconf->nc_netid, M_RPC);
310	}
311	return (xprt);
312
313freedata:
314	if (madeso)
315		(void)soclose(so);
316	if (xprt) {
317		if (!madeso) /* so that svc_destroy doesnt close fd */
318			xprt->xp_socket = NULL;
319		xprt_unregister(xprt);
320	}
321	return (NULL);
322}
323