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