svc_generic.c revision 1.2 1 /* $NetBSD: svc_generic.c,v 1.2 2000/06/07 18:27:40 fvdl Exp $ */
2
3 /*
4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5 * unrestricted use provided that this legend is included on all tape
6 * media and as a part of the software program in whole or part. Users
7 * may copy or modify Sun RPC without charge, but are not authorized
8 * to license or distribute it to anyone else except as part of a product or
9 * program developed by the user.
10 *
11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14 *
15 * Sun RPC is provided with no support and without any obligation on the
16 * part of Sun Microsystems, Inc. to assist in its use, correction,
17 * modification or enhancement.
18 *
19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21 * OR ANY PART THEREOF.
22 *
23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24 * or profits or other special, indirect and consequential damages, even if
25 * Sun has been advised of the possibility of such damages.
26 *
27 * Sun Microsystems, Inc.
28 * 2550 Garcia Avenue
29 * Mountain View, California 94043
30 */
31
32 /*
33 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
34 */
35
36 /* #ident "@(#)svc_generic.c 1.19 94/04/24 SMI" */
37
38 #if 0
39 #if !defined(lint) && defined(SCCSIDS)
40 static char sccsid[] = "@(#)svc_generic.c 1.21 89/02/28 Copyr 1988 Sun Micro";
41 #endif
42 #endif
43
44 /*
45 * svc_generic.c, Server side for RPC.
46 *
47 */
48
49 #include "namespace.h"
50 #include "reentrant.h"
51 #include <sys/types.h>
52 #include <sys/socket.h>
53 #include <netinet/in.h>
54 #include <rpc/rpc.h>
55 #include <stdio.h>
56 #include <errno.h>
57 #include <malloc.h>
58 #include <string.h>
59 #include <unistd.h>
60 #include <err.h>
61
62 #include "rpc_com.h"
63
64 #ifdef __weak_alias
65 __weak_alias(svc_create,_svc_create)
66 __weak_alias(svc_tp_create,_svc_tp_create)
67 __weak_alias(svc_tli_create,_svc_tli_create)
68 #endif
69
70 extern int __svc_vc_setflag __P((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 */
81 int
82 svc_create(dispatch, prognum, versnum, nettype)
83 void (*dispatch) __P((struct svc_req *, SVCXPRT *));
84 rpcprog_t prognum; /* Program number */
85 rpcvers_t versnum; /* Version number */
86 const char *nettype; /* Networktype token */
87 {
88 struct xlist {
89 SVCXPRT *xprt; /* Server handle */
90 struct xlist *next; /* Next item */
91 } *l;
92 static struct xlist *xprtlist; /* A link list of all the handles */
93 int num = 0;
94 SVCXPRT *xprt;
95 struct netconfig *nconf;
96 void *handle;
97 #ifdef __REENT
98 extern mutex_t xprtlist_lock;
99 #endif
100
101 /* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */
102
103 if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
104 warnx("svc_create: unknown protocol");
105 return (0);
106 }
107 while ((nconf = __rpc_getconf(handle))) {
108 mutex_lock(&xprtlist_lock);
109 for (l = xprtlist; l; l = l->next) {
110 if (strcmp(l->xprt->xp_netid, nconf->nc_netid) == 0) {
111 /* Found an old one, use it */
112 (void) rpcb_unset(prognum, versnum, nconf);
113 if (svc_reg(l->xprt, prognum, versnum,
114 dispatch, nconf) == FALSE)
115 warnx(
116 "svc_create: could not register prog %u vers %u on %s",
117 (unsigned)prognum, (unsigned)versnum,
118 nconf->nc_netid);
119 else
120 num++;
121 break;
122 }
123 }
124 if (l == (struct xlist *)NULL) {
125 /* It was not found. Now create a new one */
126 xprt = svc_tp_create(dispatch, prognum, versnum, nconf);
127 if (xprt) {
128 l = (struct xlist *)malloc(sizeof (*l));
129 if (l == (struct xlist *)NULL) {
130 warnx("svc_create: no memory");
131 mutex_unlock(&xprtlist_lock);
132 return (0);
133 }
134 l->xprt = xprt;
135 l->next = xprtlist;
136 xprtlist = l;
137 num++;
138 }
139 }
140 mutex_unlock(&xprtlist_lock);
141 }
142 __rpc_endconf(handle);
143 /*
144 * In case of num == 0; the error messages are generated by the
145 * underlying layers; and hence not needed here.
146 */
147 return (num);
148 }
149
150 /*
151 * The high level interface to svc_tli_create().
152 * It tries to create a server for "nconf" and registers the service
153 * with the rpcbind. It calls svc_tli_create();
154 */
155 SVCXPRT *
156 svc_tp_create(dispatch, prognum, versnum, nconf)
157 void (*dispatch) __P((struct svc_req *, SVCXPRT *));
158 rpcprog_t prognum; /* Program number */
159 rpcvers_t versnum; /* Version number */
160 const struct netconfig *nconf; /* Netconfig structure for the network */
161 {
162 SVCXPRT *xprt;
163
164 if (nconf == (struct netconfig *)NULL) {
165 warnx(
166 "svc_tp_create: invalid netconfig structure for prog %u vers %u",
167 (unsigned)prognum, (unsigned)versnum);
168 return ((SVCXPRT *)NULL);
169 }
170 xprt = svc_tli_create(RPC_ANYFD, nconf, (struct t_bind *)NULL, 0, 0);
171 if (xprt == (SVCXPRT *)NULL) {
172 return ((SVCXPRT *)NULL);
173 }
174 (void) rpcb_unset(prognum, versnum, (struct netconfig *) nconf);
175 if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
176 warnx(
177 "svc_tp_create: Could not register prog %u vers %u on %s",
178 (unsigned)prognum, (unsigned)versnum,
179 nconf->nc_netid);
180 SVC_DESTROY(xprt);
181 return ((SVCXPRT *)NULL);
182 }
183 return (xprt);
184 }
185
186 /*
187 * If fd is RPC_ANYFD, then it opens a fd for the given transport
188 * provider (nconf cannot be NULL then). If the t_state is T_UNBND and
189 * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For
190 * NULL bindadr and Connection oriented transports, the value of qlen
191 * is set to 8.
192 *
193 * If sendsz or recvsz are zero, their default values are chosen.
194 */
195 SVCXPRT *
196 svc_tli_create(fd, nconf, bindaddr, sendsz, recvsz)
197 int fd; /* Connection end point */
198 const struct netconfig *nconf; /* Netconfig struct for nettoken */
199 const struct t_bind *bindaddr; /* Local bind address */
200 u_int sendsz; /* Max sendsize */
201 u_int recvsz; /* Max recvsize */
202 {
203 register SVCXPRT *xprt = NULL; /* service handle */
204 bool_t madefd = FALSE; /* whether fd opened here */
205 struct __rpc_sockinfo si;
206 struct sockaddr_storage ss;
207 int active = 0;
208 socklen_t slen;
209
210 if (fd == RPC_ANYFD) {
211 if (nconf == (struct netconfig *)NULL) {
212 warnx("svc_tli_create: invalid netconfig");
213 return ((SVCXPRT *)NULL);
214 }
215 fd = __rpc_nconf2fd(nconf);
216 if (fd == -1) {
217 warnx(
218 "svc_tli_create: could not open connection for %s",
219 nconf->nc_netid);
220 return ((SVCXPRT *)NULL);
221 }
222 __rpc_nconf2sockinfo(nconf, &si);
223 madefd = TRUE;
224 } else {
225 /*
226 * It is an open descriptor. Get the transport info.
227 */
228 if (!__rpc_fd2sockinfo(fd, &si)) {
229 warnx(
230 "svc_tli_create: could not get transport information");
231 return ((SVCXPRT *)NULL);
232 }
233 }
234
235 /*
236 * If the fd is unbound, try to bind it.
237 */
238 if (madefd || !__rpc_sockisbound(fd)) {
239 if (bindaddr == NULL) {
240 if (bindresvport(fd, NULL) < 0) {
241 memset(&ss, 0, sizeof ss);
242 ss.ss_family = si.si_af;
243 ss.ss_len = si.si_alen;
244 if (bind(fd, (struct sockaddr *)(void *)&ss,
245 si.si_alen) < 0) {
246 warnx(
247 "svc_tli_create: could not bind to anonymous port");
248 goto freedata;
249 }
250 }
251 listen(fd, SOMAXCONN);
252 } else {
253 if (bind(fd, (struct sockaddr *)&bindaddr->addr.buf,
254 si.si_alen) < 0) {
255 warnx(
256 "svc_tli_create: could not bind to requested address");
257 goto freedata;
258 }
259 listen(fd, bindaddr->qlen);
260 }
261
262 }
263 /*
264 * call transport specific function.
265 */
266 switch (si.si_socktype) {
267 case SOCK_STREAM:
268 slen = sizeof ss;
269 if (getpeername(fd, (struct sockaddr *)&ss, &slen)
270 == 0) {
271 active = 1;
272 /* accepted socket */
273 xprt = svc_fd_create(fd, sendsz, recvsz);
274 } else
275 xprt = svc_vc_create(fd, sendsz, recvsz);
276 if (!nconf || !xprt)
277 break;
278 #if 0
279 /* XXX fvdl */
280 if (strcmp(nconf->nc_protofmly, "inet") == 0 ||
281 strcmp(nconf->nc_protofmly, "inet6") == 0)
282 (void) __svc_vc_setflag(xprt, TRUE);
283 #endif
284 break;
285 case SOCK_DGRAM:
286 xprt = svc_dg_create(fd, sendsz, recvsz);
287 break;
288 default:
289 warnx("svc_tli_create: bad service type");
290 goto freedata;
291 }
292
293 if (xprt == (SVCXPRT *)NULL)
294 /*
295 * The error messages here are spitted out by the lower layers:
296 * svc_vc_create(), svc_fd_create() and svc_dg_create().
297 */
298 goto freedata;
299
300 /* Fill in type of service */
301 xprt->xp_type = __rpc_socktype2seman(si.si_socktype);
302
303 if (nconf) {
304 xprt->xp_netid = strdup(nconf->nc_netid);
305 xprt->xp_tp = strdup(nconf->nc_device);
306 }
307 return (xprt);
308
309 freedata:
310 if (madefd)
311 (void) close(fd);
312 if (xprt) {
313 if (!madefd) /* so that svc_destroy doesnt close fd */
314 xprt->xp_fd = RPC_ANYFD;
315 SVC_DESTROY(xprt);
316 }
317 return ((SVCXPRT *)NULL);
318 }
319