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