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