xref: /freebsd/sys/rpc/svc_generic.c (revision dd21556857e8d40f66bf5ad54754d9d52669ebf7)
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 
65 extern int __svc_vc_setflag(SVCXPRT *, int);
66 
67 /*
68  * The high level interface to svc_tli_create().
69  * It tries to create a server for "nconf" and registers the service
70  * with the rpcbind. It calls svc_tli_create();
71  */
72 SVCXPRT *
73 svc_tp_create(
74 	SVCPOOL *pool,
75 	void (*dispatch)(struct svc_req *, SVCXPRT *),
76 	rpcprog_t prognum,		/* Program number */
77 	rpcvers_t versnum,		/* Version number */
78 	const char *uaddr,		/* Address (or null for default) */
79 	const struct netconfig *nconf) /* Netconfig structure for the network */
80 {
81 	struct netconfig nconfcopy;
82 	struct netbuf *taddr;
83 	struct t_bind bind;
84 	SVCXPRT *xprt;
85 
86 	if (nconf == NULL) {
87 		printf(
88 	"svc_tp_create: invalid netconfig structure for prog %u vers %u\n",
89 				(unsigned)prognum, (unsigned)versnum);
90 		return (NULL);
91 	}
92 	if (uaddr) {
93 		taddr = uaddr2taddr(nconf, uaddr);
94 		bind.addr = *taddr;
95 		free(taddr, M_RPC);
96 		bind.qlen = -1;
97 		xprt = svc_tli_create(pool, nconf, &bind, 0, 0);
98 		free(bind.addr.buf, M_RPC);
99 	} else {
100 		xprt = svc_tli_create(pool, nconf, NULL, 0, 0);
101 	}
102 	if (xprt == NULL) {
103 		return (NULL);
104 	}
105 	/*LINTED const castaway*/
106 	nconfcopy = *nconf;
107 	(void) rpcb_unset(prognum, versnum, &nconfcopy);
108 	if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
109 		printf(
110 		"svc_tp_create: Could not register prog %u vers %u on %s\n",
111 				(unsigned)prognum, (unsigned)versnum,
112 				nconf->nc_netid);
113 		xprt_unregister(xprt);
114 		SVC_RELEASE(xprt);
115 		return (NULL);
116 	}
117 	return (xprt);
118 }
119 
120 /*
121  * If so is NULL, then it opens a socket for the given transport
122  * provider (nconf cannot be NULL then). If the t_state is T_UNBND and
123  * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For
124  * NULL bindadr and Connection oriented transports, the value of qlen
125  * is set to 8.
126  *
127  * If sendsz or recvsz are zero, their default values are chosen.
128  */
129 SVCXPRT *
130 svc_tli_create(
131 	SVCPOOL *pool,
132 	const struct netconfig *nconf,	/* Netconfig struct for nettoken */
133 	const struct t_bind *bindaddr,	/* Local bind address */
134 	size_t sendsz,			/* Max sendsize */
135 	size_t recvsz)			/* Max recvsize */
136 {
137 	struct socket *so;
138 	SVCXPRT *xprt = NULL;		/* service handle */
139 	struct __rpc_sockinfo si;
140 	struct sockaddr_storage ss;
141 
142 	if (nconf == NULL) {
143 		printf("svc_tli_create: invalid netconfig\n");
144 		return (NULL);
145 	}
146 	so = __rpc_nconf2socket(nconf);
147 	if (!so) {
148 		printf(
149 		    "svc_tli_create: could not open connection for %s\n",
150 				nconf->nc_netid);
151 		return (NULL);
152 	}
153 	__rpc_nconf2sockinfo(nconf, &si);
154 
155 	if (bindaddr == NULL) {
156 		if (bindresvport(so, NULL)) {
157 			memset(&ss, 0, sizeof ss);
158 			ss.ss_family = si.si_af;
159 			ss.ss_len = si.si_alen;
160 			if (sobind(so, (struct sockaddr *)&ss,
161 				curthread)) {
162 				printf(
163 		"svc_tli_create: could not bind to anonymous port\n");
164 				goto freedata;
165 			}
166 		}
167 		solisten(so, -1, curthread);
168 	} else {
169 		if (bindresvport(so,
170 			(struct sockaddr *)bindaddr->addr.buf)) {
171 			printf(
172 	"svc_tli_create: could not bind to requested address\n");
173 			goto freedata;
174 		}
175 		solisten(so, (int)bindaddr->qlen, curthread);
176 	}
177 
178 	/*
179 	 * call transport specific function.
180 	 */
181 	switch (si.si_socktype) {
182 		case SOCK_STREAM:
183 #if 0
184 			slen = sizeof ss;
185 			if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen)
186 			    == 0) {
187 				/* accepted socket */
188 				xprt = svc_fd_create(fd, sendsz, recvsz);
189 			} else
190 #endif
191 				xprt = svc_vc_create(pool, so, sendsz, recvsz);
192 			if (!nconf || !xprt)
193 				break;
194 #if 0
195 			/* XXX fvdl */
196 			if (strcmp(nconf->nc_protofmly, "inet") == 0 ||
197 			    strcmp(nconf->nc_protofmly, "inet6") == 0)
198 				(void) __svc_vc_setflag(xprt, TRUE);
199 #endif
200 			break;
201 		case SOCK_DGRAM:
202 			xprt = svc_dg_create(pool, so, sendsz, recvsz);
203 			break;
204 		default:
205 			printf("svc_tli_create: bad service type");
206 			goto freedata;
207 	}
208 
209 	if (xprt == NULL)
210 		/*
211 		 * The error messages here are spitted out by the lower layers:
212 		 * svc_vc_create(), svc_fd_create() and svc_dg_create().
213 		 */
214 		goto freedata;
215 
216 	/* Fill in type of service */
217 	xprt->xp_type = __rpc_socktype2seman(si.si_socktype);
218 
219 	if (nconf) {
220 		xprt->xp_netid = strdup(nconf->nc_netid, M_RPC);
221 	}
222 	return (xprt);
223 
224 freedata:
225 	(void)soclose(so);
226 	if (xprt)
227 		xprt_unregister(xprt);
228 	return (NULL);
229 }
230