1 | #include <machine/rtems-bsd-user-space.h> |
---|
2 | |
---|
3 | /* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ |
---|
4 | |
---|
5 | /*- |
---|
6 | * SPDX-License-Identifier: BSD-3-Clause |
---|
7 | * |
---|
8 | * Copyright (c) 2009, Sun Microsystems, Inc. |
---|
9 | * All rights reserved. |
---|
10 | * |
---|
11 | * Redistribution and use in source and binary forms, with or without |
---|
12 | * modification, are permitted provided that the following conditions are met: |
---|
13 | * - Redistributions of source code must retain the above copyright notice, |
---|
14 | * this list of conditions and the following disclaimer. |
---|
15 | * - Redistributions in binary form must reproduce the above copyright notice, |
---|
16 | * this list of conditions and the following disclaimer in the documentation |
---|
17 | * and/or other materials provided with the distribution. |
---|
18 | * - Neither the name of Sun Microsystems, Inc. nor the names of its |
---|
19 | * contributors may be used to endorse or promote products derived |
---|
20 | * from this software without specific prior written permission. |
---|
21 | * |
---|
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
---|
23 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
---|
26 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
---|
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
---|
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
---|
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
---|
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
---|
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
---|
32 | * POSSIBILITY OF SUCH DAMAGE. |
---|
33 | */ |
---|
34 | |
---|
35 | #if defined(LIBC_SCCS) && !defined(lint) |
---|
36 | static char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; |
---|
37 | static char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; |
---|
38 | #endif |
---|
39 | #include <sys/cdefs.h> |
---|
40 | __FBSDID("$FreeBSD$"); |
---|
41 | |
---|
42 | /* |
---|
43 | * svc_vc.c, Server side for Connection Oriented based RPC. |
---|
44 | * |
---|
45 | * Actually implements two flavors of transporter - |
---|
46 | * a tcp rendezvouser (a listner and connection establisher) |
---|
47 | * and a record/tcp stream. |
---|
48 | */ |
---|
49 | |
---|
50 | #include "namespace.h" |
---|
51 | #include "reentrant.h" |
---|
52 | #include <sys/param.h> |
---|
53 | #include <sys/poll.h> |
---|
54 | #include <sys/socket.h> |
---|
55 | #include <sys/un.h> |
---|
56 | #include <sys/time.h> |
---|
57 | #include <sys/uio.h> |
---|
58 | #include <netinet/in.h> |
---|
59 | #include <netinet/tcp.h> |
---|
60 | |
---|
61 | #include <assert.h> |
---|
62 | #include <err.h> |
---|
63 | #include <errno.h> |
---|
64 | #include <fcntl.h> |
---|
65 | #include <stdio.h> |
---|
66 | #include <stdlib.h> |
---|
67 | #include <string.h> |
---|
68 | #include <unistd.h> |
---|
69 | |
---|
70 | #include <rpc/rpc.h> |
---|
71 | |
---|
72 | #include "rpc_com.h" |
---|
73 | #include "mt_misc.h" |
---|
74 | #include "un-namespace.h" |
---|
75 | |
---|
76 | static SVCXPRT *makefd_xprt(int, u_int, u_int); |
---|
77 | static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *); |
---|
78 | static enum xprt_stat rendezvous_stat(SVCXPRT *); |
---|
79 | static void svc_vc_destroy(SVCXPRT *); |
---|
80 | static void __svc_vc_dodestroy (SVCXPRT *); |
---|
81 | static int read_vc(void *, void *, int); |
---|
82 | static int write_vc(void *, void *, int); |
---|
83 | static enum xprt_stat svc_vc_stat(SVCXPRT *); |
---|
84 | static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *); |
---|
85 | static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *); |
---|
86 | static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *); |
---|
87 | static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *); |
---|
88 | static void svc_vc_rendezvous_ops(SVCXPRT *); |
---|
89 | static void svc_vc_ops(SVCXPRT *); |
---|
90 | static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); |
---|
91 | static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, |
---|
92 | void *in); |
---|
93 | |
---|
94 | struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */ |
---|
95 | u_int sendsize; |
---|
96 | u_int recvsize; |
---|
97 | int maxrec; |
---|
98 | }; |
---|
99 | |
---|
100 | struct cf_conn { /* kept in xprt->xp_p1 for actual connection */ |
---|
101 | enum xprt_stat strm_stat; |
---|
102 | u_int32_t x_id; |
---|
103 | XDR xdrs; |
---|
104 | char verf_body[MAX_AUTH_BYTES]; |
---|
105 | u_int sendsize; |
---|
106 | u_int recvsize; |
---|
107 | int maxrec; |
---|
108 | bool_t nonblock; |
---|
109 | struct timeval last_recv_time; |
---|
110 | }; |
---|
111 | |
---|
112 | /* |
---|
113 | * Usage: |
---|
114 | * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); |
---|
115 | * |
---|
116 | * Creates, registers, and returns a (rpc) tcp based transporter. |
---|
117 | * Once *xprt is initialized, it is registered as a transporter |
---|
118 | * see (svc.h, xprt_register). This routine returns |
---|
119 | * a NULL if a problem occurred. |
---|
120 | * |
---|
121 | * The filedescriptor passed in is expected to refer to a bound, but |
---|
122 | * not yet connected socket. |
---|
123 | * |
---|
124 | * Since streams do buffered io similar to stdio, the caller can specify |
---|
125 | * how big the send and receive buffers are via the second and third parms; |
---|
126 | * 0 => use the system default. |
---|
127 | */ |
---|
128 | SVCXPRT * |
---|
129 | svc_vc_create(int fd, u_int sendsize, u_int recvsize) |
---|
130 | { |
---|
131 | SVCXPRT *xprt = NULL; |
---|
132 | struct cf_rendezvous *r = NULL; |
---|
133 | struct __rpc_sockinfo si; |
---|
134 | struct sockaddr_storage sslocal; |
---|
135 | socklen_t slen; |
---|
136 | |
---|
137 | if (!__rpc_fd2sockinfo(fd, &si)) |
---|
138 | return NULL; |
---|
139 | |
---|
140 | r = mem_alloc(sizeof(*r)); |
---|
141 | if (r == NULL) { |
---|
142 | warnx("svc_vc_create: out of memory"); |
---|
143 | goto cleanup_svc_vc_create; |
---|
144 | } |
---|
145 | r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); |
---|
146 | r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); |
---|
147 | r->maxrec = __svc_maxrec; |
---|
148 | xprt = svc_xprt_alloc(); |
---|
149 | if (xprt == NULL) { |
---|
150 | warnx("svc_vc_create: out of memory"); |
---|
151 | goto cleanup_svc_vc_create; |
---|
152 | } |
---|
153 | xprt->xp_p1 = r; |
---|
154 | xprt->xp_verf = _null_auth; |
---|
155 | svc_vc_rendezvous_ops(xprt); |
---|
156 | xprt->xp_port = (u_short)-1; /* It is the rendezvouser */ |
---|
157 | xprt->xp_fd = fd; |
---|
158 | |
---|
159 | slen = sizeof (struct sockaddr_storage); |
---|
160 | if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) { |
---|
161 | warnx("svc_vc_create: could not retrieve local addr"); |
---|
162 | goto cleanup_svc_vc_create; |
---|
163 | } |
---|
164 | |
---|
165 | xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len; |
---|
166 | xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len); |
---|
167 | if (xprt->xp_ltaddr.buf == NULL) { |
---|
168 | warnx("svc_vc_create: no mem for local addr"); |
---|
169 | goto cleanup_svc_vc_create; |
---|
170 | } |
---|
171 | memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len); |
---|
172 | |
---|
173 | xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); |
---|
174 | xprt_register(xprt); |
---|
175 | return (xprt); |
---|
176 | cleanup_svc_vc_create: |
---|
177 | if (xprt) |
---|
178 | mem_free(xprt, sizeof(*xprt)); |
---|
179 | if (r != NULL) |
---|
180 | mem_free(r, sizeof(*r)); |
---|
181 | return (NULL); |
---|
182 | } |
---|
183 | |
---|
184 | /* |
---|
185 | * Like svtcp_create(), except the routine takes any *open* UNIX file |
---|
186 | * descriptor as its first input. |
---|
187 | */ |
---|
188 | SVCXPRT * |
---|
189 | svc_fd_create(int fd, u_int sendsize, u_int recvsize) |
---|
190 | { |
---|
191 | struct sockaddr_storage ss; |
---|
192 | socklen_t slen; |
---|
193 | SVCXPRT *ret; |
---|
194 | |
---|
195 | assert(fd != -1); |
---|
196 | |
---|
197 | ret = makefd_xprt(fd, sendsize, recvsize); |
---|
198 | if (ret == NULL) |
---|
199 | return NULL; |
---|
200 | |
---|
201 | slen = sizeof (struct sockaddr_storage); |
---|
202 | if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { |
---|
203 | warnx("svc_fd_create: could not retrieve local addr"); |
---|
204 | goto freedata; |
---|
205 | } |
---|
206 | ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len; |
---|
207 | ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len); |
---|
208 | if (ret->xp_ltaddr.buf == NULL) { |
---|
209 | warnx("svc_fd_create: no mem for local addr"); |
---|
210 | goto freedata; |
---|
211 | } |
---|
212 | memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len); |
---|
213 | |
---|
214 | slen = sizeof (struct sockaddr_storage); |
---|
215 | if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { |
---|
216 | warnx("svc_fd_create: could not retrieve remote addr"); |
---|
217 | goto freedata; |
---|
218 | } |
---|
219 | ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len; |
---|
220 | ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len); |
---|
221 | if (ret->xp_rtaddr.buf == NULL) { |
---|
222 | warnx("svc_fd_create: no mem for local addr"); |
---|
223 | goto freedata; |
---|
224 | } |
---|
225 | memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len); |
---|
226 | #ifdef PORTMAP |
---|
227 | if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) { |
---|
228 | ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf; |
---|
229 | ret->xp_addrlen = sizeof (struct sockaddr_in); |
---|
230 | } |
---|
231 | #endif /* PORTMAP */ |
---|
232 | |
---|
233 | return ret; |
---|
234 | |
---|
235 | freedata: |
---|
236 | if (ret->xp_ltaddr.buf != NULL) |
---|
237 | mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen); |
---|
238 | |
---|
239 | return NULL; |
---|
240 | } |
---|
241 | |
---|
242 | static SVCXPRT * |
---|
243 | makefd_xprt(int fd, u_int sendsize, u_int recvsize) |
---|
244 | { |
---|
245 | SVCXPRT *xprt; |
---|
246 | struct cf_conn *cd; |
---|
247 | const char *netid; |
---|
248 | struct __rpc_sockinfo si; |
---|
249 | |
---|
250 | assert(fd != -1); |
---|
251 | |
---|
252 | xprt = svc_xprt_alloc(); |
---|
253 | if (xprt == NULL) { |
---|
254 | warnx("svc_vc: makefd_xprt: out of memory"); |
---|
255 | goto done; |
---|
256 | } |
---|
257 | cd = mem_alloc(sizeof(struct cf_conn)); |
---|
258 | if (cd == NULL) { |
---|
259 | warnx("svc_tcp: makefd_xprt: out of memory"); |
---|
260 | svc_xprt_free(xprt); |
---|
261 | xprt = NULL; |
---|
262 | goto done; |
---|
263 | } |
---|
264 | cd->strm_stat = XPRT_IDLE; |
---|
265 | xdrrec_create(&(cd->xdrs), sendsize, recvsize, |
---|
266 | xprt, read_vc, write_vc); |
---|
267 | xprt->xp_p1 = cd; |
---|
268 | xprt->xp_verf.oa_base = cd->verf_body; |
---|
269 | svc_vc_ops(xprt); /* truly deals with calls */ |
---|
270 | xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ |
---|
271 | xprt->xp_fd = fd; |
---|
272 | if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid)) |
---|
273 | xprt->xp_netid = strdup(netid); |
---|
274 | |
---|
275 | xprt_register(xprt); |
---|
276 | done: |
---|
277 | return (xprt); |
---|
278 | } |
---|
279 | |
---|
280 | /*ARGSUSED*/ |
---|
281 | static bool_t |
---|
282 | rendezvous_request(SVCXPRT *xprt, struct rpc_msg *msg) |
---|
283 | { |
---|
284 | int sock, flags; |
---|
285 | struct cf_rendezvous *r; |
---|
286 | struct cf_conn *cd; |
---|
287 | struct sockaddr_storage addr, sslocal; |
---|
288 | socklen_t len, slen; |
---|
289 | struct __rpc_sockinfo si; |
---|
290 | SVCXPRT *newxprt; |
---|
291 | fd_set cleanfds; |
---|
292 | |
---|
293 | assert(xprt != NULL); |
---|
294 | assert(msg != NULL); |
---|
295 | |
---|
296 | r = (struct cf_rendezvous *)xprt->xp_p1; |
---|
297 | again: |
---|
298 | len = sizeof addr; |
---|
299 | if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, |
---|
300 | &len)) < 0) { |
---|
301 | if (errno == EINTR) |
---|
302 | goto again; |
---|
303 | /* |
---|
304 | * Clean out the most idle file descriptor when we're |
---|
305 | * running out. |
---|
306 | */ |
---|
307 | if (errno == EMFILE || errno == ENFILE) { |
---|
308 | cleanfds = svc_fdset; |
---|
309 | __svc_clean_idle(&cleanfds, 0, FALSE); |
---|
310 | goto again; |
---|
311 | } |
---|
312 | return (FALSE); |
---|
313 | } |
---|
314 | /* |
---|
315 | * make a new transporter (re-uses xprt) |
---|
316 | */ |
---|
317 | newxprt = makefd_xprt(sock, r->sendsize, r->recvsize); |
---|
318 | newxprt->xp_rtaddr.buf = mem_alloc(len); |
---|
319 | if (newxprt->xp_rtaddr.buf == NULL) |
---|
320 | return (FALSE); |
---|
321 | memcpy(newxprt->xp_rtaddr.buf, &addr, len); |
---|
322 | newxprt->xp_rtaddr.len = len; |
---|
323 | #ifdef PORTMAP |
---|
324 | if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) { |
---|
325 | newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf; |
---|
326 | newxprt->xp_addrlen = sizeof (struct sockaddr_in); |
---|
327 | } |
---|
328 | #endif /* PORTMAP */ |
---|
329 | if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) { |
---|
330 | len = 1; |
---|
331 | /* XXX fvdl - is this useful? */ |
---|
332 | _setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len)); |
---|
333 | } |
---|
334 | |
---|
335 | cd = (struct cf_conn *)newxprt->xp_p1; |
---|
336 | |
---|
337 | cd->recvsize = r->recvsize; |
---|
338 | cd->sendsize = r->sendsize; |
---|
339 | cd->maxrec = r->maxrec; |
---|
340 | |
---|
341 | if (cd->maxrec != 0) { |
---|
342 | flags = _fcntl(sock, F_GETFL, 0); |
---|
343 | if (flags == -1) |
---|
344 | return (FALSE); |
---|
345 | if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) |
---|
346 | return (FALSE); |
---|
347 | if (cd->recvsize > cd->maxrec) |
---|
348 | cd->recvsize = cd->maxrec; |
---|
349 | cd->nonblock = TRUE; |
---|
350 | __xdrrec_setnonblock(&cd->xdrs, cd->maxrec); |
---|
351 | } else |
---|
352 | cd->nonblock = FALSE; |
---|
353 | slen = sizeof(struct sockaddr_storage); |
---|
354 | if(_getsockname(sock, (struct sockaddr *)(void *)&sslocal, &slen) < 0) { |
---|
355 | warnx("svc_vc_create: could not retrieve local addr"); |
---|
356 | newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = 0; |
---|
357 | } else { |
---|
358 | newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = sslocal.ss_len; |
---|
359 | newxprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len); |
---|
360 | if (newxprt->xp_ltaddr.buf == NULL) { |
---|
361 | warnx("svc_vc_create: no mem for local addr"); |
---|
362 | newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = 0; |
---|
363 | } else { |
---|
364 | memcpy(newxprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len); |
---|
365 | } |
---|
366 | } |
---|
367 | |
---|
368 | gettimeofday(&cd->last_recv_time, NULL); |
---|
369 | |
---|
370 | return (FALSE); /* there is never an rpc msg to be processed */ |
---|
371 | } |
---|
372 | |
---|
373 | /*ARGSUSED*/ |
---|
374 | static enum xprt_stat |
---|
375 | rendezvous_stat(SVCXPRT *xprt) |
---|
376 | { |
---|
377 | |
---|
378 | return (XPRT_IDLE); |
---|
379 | } |
---|
380 | |
---|
381 | static void |
---|
382 | svc_vc_destroy(SVCXPRT *xprt) |
---|
383 | { |
---|
384 | assert(xprt != NULL); |
---|
385 | |
---|
386 | xprt_unregister(xprt); |
---|
387 | __svc_vc_dodestroy(xprt); |
---|
388 | } |
---|
389 | |
---|
390 | static void |
---|
391 | __svc_vc_dodestroy(SVCXPRT *xprt) |
---|
392 | { |
---|
393 | struct cf_conn *cd; |
---|
394 | struct cf_rendezvous *r; |
---|
395 | |
---|
396 | cd = (struct cf_conn *)xprt->xp_p1; |
---|
397 | |
---|
398 | if (xprt->xp_fd != RPC_ANYFD) |
---|
399 | (void)_close(xprt->xp_fd); |
---|
400 | if (xprt->xp_port != 0) { |
---|
401 | /* a rendezvouser socket */ |
---|
402 | r = (struct cf_rendezvous *)xprt->xp_p1; |
---|
403 | mem_free(r, sizeof (struct cf_rendezvous)); |
---|
404 | xprt->xp_port = 0; |
---|
405 | } else { |
---|
406 | /* an actual connection socket */ |
---|
407 | XDR_DESTROY(&(cd->xdrs)); |
---|
408 | mem_free(cd, sizeof(struct cf_conn)); |
---|
409 | } |
---|
410 | if (xprt->xp_rtaddr.buf) |
---|
411 | mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); |
---|
412 | if (xprt->xp_ltaddr.buf) |
---|
413 | mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); |
---|
414 | free(xprt->xp_tp); |
---|
415 | free(xprt->xp_netid); |
---|
416 | svc_xprt_free(xprt); |
---|
417 | } |
---|
418 | |
---|
419 | /*ARGSUSED*/ |
---|
420 | static bool_t |
---|
421 | svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in) |
---|
422 | { |
---|
423 | return (FALSE); |
---|
424 | } |
---|
425 | |
---|
426 | static bool_t |
---|
427 | svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in) |
---|
428 | { |
---|
429 | struct cf_rendezvous *cfp; |
---|
430 | |
---|
431 | cfp = (struct cf_rendezvous *)xprt->xp_p1; |
---|
432 | if (cfp == NULL) |
---|
433 | return (FALSE); |
---|
434 | switch (rq) { |
---|
435 | case SVCGET_CONNMAXREC: |
---|
436 | *(int *)in = cfp->maxrec; |
---|
437 | break; |
---|
438 | case SVCSET_CONNMAXREC: |
---|
439 | cfp->maxrec = *(int *)in; |
---|
440 | break; |
---|
441 | default: |
---|
442 | return (FALSE); |
---|
443 | } |
---|
444 | return (TRUE); |
---|
445 | } |
---|
446 | |
---|
447 | /* |
---|
448 | * reads data from the tcp or uip connection. |
---|
449 | * any error is fatal and the connection is closed. |
---|
450 | * (And a read of zero bytes is a half closed stream => error.) |
---|
451 | * All read operations timeout after 35 seconds. A timeout is |
---|
452 | * fatal for the connection. |
---|
453 | */ |
---|
454 | static int |
---|
455 | read_vc(void *xprtp, void *buf, int len) |
---|
456 | { |
---|
457 | SVCXPRT *xprt; |
---|
458 | int sock; |
---|
459 | int milliseconds = 35 * 1000; |
---|
460 | struct pollfd pollfd; |
---|
461 | struct cf_conn *cfp; |
---|
462 | |
---|
463 | xprt = (SVCXPRT *)xprtp; |
---|
464 | assert(xprt != NULL); |
---|
465 | |
---|
466 | sock = xprt->xp_fd; |
---|
467 | |
---|
468 | cfp = (struct cf_conn *)xprt->xp_p1; |
---|
469 | |
---|
470 | if (cfp->nonblock) { |
---|
471 | len = _read(sock, buf, (size_t)len); |
---|
472 | if (len < 0) { |
---|
473 | if (errno == EAGAIN) |
---|
474 | len = 0; |
---|
475 | else |
---|
476 | goto fatal_err; |
---|
477 | } |
---|
478 | if (len != 0) |
---|
479 | gettimeofday(&cfp->last_recv_time, NULL); |
---|
480 | return len; |
---|
481 | } |
---|
482 | |
---|
483 | do { |
---|
484 | pollfd.fd = sock; |
---|
485 | pollfd.events = POLLIN; |
---|
486 | pollfd.revents = 0; |
---|
487 | switch (_poll(&pollfd, 1, milliseconds)) { |
---|
488 | case -1: |
---|
489 | if (errno == EINTR) |
---|
490 | continue; |
---|
491 | /*FALLTHROUGH*/ |
---|
492 | case 0: |
---|
493 | goto fatal_err; |
---|
494 | |
---|
495 | default: |
---|
496 | break; |
---|
497 | } |
---|
498 | } while ((pollfd.revents & POLLIN) == 0); |
---|
499 | |
---|
500 | if ((len = _read(sock, buf, (size_t)len)) > 0) { |
---|
501 | gettimeofday(&cfp->last_recv_time, NULL); |
---|
502 | return (len); |
---|
503 | } |
---|
504 | |
---|
505 | fatal_err: |
---|
506 | ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; |
---|
507 | return (-1); |
---|
508 | } |
---|
509 | |
---|
510 | /* |
---|
511 | * writes data to the tcp connection. |
---|
512 | * Any error is fatal and the connection is closed. |
---|
513 | */ |
---|
514 | static int |
---|
515 | write_vc(void *xprtp, void *buf, int len) |
---|
516 | { |
---|
517 | SVCXPRT *xprt; |
---|
518 | int i, cnt; |
---|
519 | struct cf_conn *cd; |
---|
520 | struct timeval tv0, tv1; |
---|
521 | |
---|
522 | xprt = (SVCXPRT *)xprtp; |
---|
523 | assert(xprt != NULL); |
---|
524 | |
---|
525 | cd = (struct cf_conn *)xprt->xp_p1; |
---|
526 | |
---|
527 | if (cd->nonblock) |
---|
528 | gettimeofday(&tv0, NULL); |
---|
529 | |
---|
530 | for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) { |
---|
531 | i = _write(xprt->xp_fd, buf, (size_t)cnt); |
---|
532 | if (i < 0) { |
---|
533 | if (errno != EAGAIN || !cd->nonblock) { |
---|
534 | cd->strm_stat = XPRT_DIED; |
---|
535 | return (-1); |
---|
536 | } |
---|
537 | if (cd->nonblock) { |
---|
538 | /* |
---|
539 | * For non-blocking connections, do not |
---|
540 | * take more than 2 seconds writing the |
---|
541 | * data out. |
---|
542 | * |
---|
543 | * XXX 2 is an arbitrary amount. |
---|
544 | */ |
---|
545 | gettimeofday(&tv1, NULL); |
---|
546 | if (tv1.tv_sec - tv0.tv_sec >= 2) { |
---|
547 | cd->strm_stat = XPRT_DIED; |
---|
548 | return (-1); |
---|
549 | } |
---|
550 | } |
---|
551 | i = 0; |
---|
552 | } |
---|
553 | } |
---|
554 | |
---|
555 | return (len); |
---|
556 | } |
---|
557 | |
---|
558 | static enum xprt_stat |
---|
559 | svc_vc_stat(SVCXPRT *xprt) |
---|
560 | { |
---|
561 | struct cf_conn *cd; |
---|
562 | |
---|
563 | assert(xprt != NULL); |
---|
564 | |
---|
565 | cd = (struct cf_conn *)(xprt->xp_p1); |
---|
566 | |
---|
567 | if (cd->strm_stat == XPRT_DIED) |
---|
568 | return (XPRT_DIED); |
---|
569 | if (! xdrrec_eof(&(cd->xdrs))) |
---|
570 | return (XPRT_MOREREQS); |
---|
571 | return (XPRT_IDLE); |
---|
572 | } |
---|
573 | |
---|
574 | static bool_t |
---|
575 | svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg) |
---|
576 | { |
---|
577 | struct cf_conn *cd; |
---|
578 | XDR *xdrs; |
---|
579 | |
---|
580 | assert(xprt != NULL); |
---|
581 | assert(msg != NULL); |
---|
582 | |
---|
583 | cd = (struct cf_conn *)(xprt->xp_p1); |
---|
584 | xdrs = &(cd->xdrs); |
---|
585 | |
---|
586 | if (cd->nonblock) { |
---|
587 | if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE)) |
---|
588 | return FALSE; |
---|
589 | } else { |
---|
590 | (void)xdrrec_skiprecord(xdrs); |
---|
591 | } |
---|
592 | |
---|
593 | xdrs->x_op = XDR_DECODE; |
---|
594 | if (xdr_callmsg(xdrs, msg)) { |
---|
595 | cd->x_id = msg->rm_xid; |
---|
596 | return (TRUE); |
---|
597 | } |
---|
598 | cd->strm_stat = XPRT_DIED; |
---|
599 | return (FALSE); |
---|
600 | } |
---|
601 | |
---|
602 | static bool_t |
---|
603 | svc_vc_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr) |
---|
604 | { |
---|
605 | struct cf_conn *cd; |
---|
606 | |
---|
607 | assert(xprt != NULL); |
---|
608 | cd = (struct cf_conn *)(xprt->xp_p1); |
---|
609 | return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), |
---|
610 | &cd->xdrs, xdr_args, args_ptr)); |
---|
611 | } |
---|
612 | |
---|
613 | static bool_t |
---|
614 | svc_vc_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr) |
---|
615 | { |
---|
616 | XDR *xdrs; |
---|
617 | |
---|
618 | assert(xprt != NULL); |
---|
619 | /* args_ptr may be NULL */ |
---|
620 | |
---|
621 | xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs); |
---|
622 | |
---|
623 | xdrs->x_op = XDR_FREE; |
---|
624 | return ((*xdr_args)(xdrs, args_ptr)); |
---|
625 | } |
---|
626 | |
---|
627 | static bool_t |
---|
628 | svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg) |
---|
629 | { |
---|
630 | struct cf_conn *cd; |
---|
631 | XDR *xdrs; |
---|
632 | bool_t rstat; |
---|
633 | xdrproc_t xdr_proc; |
---|
634 | caddr_t xdr_where; |
---|
635 | u_int pos; |
---|
636 | |
---|
637 | assert(xprt != NULL); |
---|
638 | assert(msg != NULL); |
---|
639 | |
---|
640 | cd = (struct cf_conn *)(xprt->xp_p1); |
---|
641 | xdrs = &(cd->xdrs); |
---|
642 | |
---|
643 | xdrs->x_op = XDR_ENCODE; |
---|
644 | msg->rm_xid = cd->x_id; |
---|
645 | rstat = TRUE; |
---|
646 | if (msg->rm_reply.rp_stat == MSG_ACCEPTED && |
---|
647 | msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { |
---|
648 | xdr_proc = msg->acpted_rply.ar_results.proc; |
---|
649 | xdr_where = msg->acpted_rply.ar_results.where; |
---|
650 | msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; |
---|
651 | msg->acpted_rply.ar_results.where = NULL; |
---|
652 | |
---|
653 | pos = XDR_GETPOS(xdrs); |
---|
654 | if (!xdr_replymsg(xdrs, msg) || |
---|
655 | !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) { |
---|
656 | XDR_SETPOS(xdrs, pos); |
---|
657 | rstat = FALSE; |
---|
658 | } |
---|
659 | } else { |
---|
660 | rstat = xdr_replymsg(xdrs, msg); |
---|
661 | } |
---|
662 | |
---|
663 | if (rstat) |
---|
664 | (void)xdrrec_endofrecord(xdrs, TRUE); |
---|
665 | |
---|
666 | return (rstat); |
---|
667 | } |
---|
668 | |
---|
669 | static void |
---|
670 | svc_vc_ops(SVCXPRT *xprt) |
---|
671 | { |
---|
672 | static struct xp_ops ops; |
---|
673 | static struct xp_ops2 ops2; |
---|
674 | |
---|
675 | /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */ |
---|
676 | |
---|
677 | mutex_lock(&ops_lock); |
---|
678 | if (ops.xp_recv == NULL) { |
---|
679 | ops.xp_recv = svc_vc_recv; |
---|
680 | ops.xp_stat = svc_vc_stat; |
---|
681 | ops.xp_getargs = svc_vc_getargs; |
---|
682 | ops.xp_reply = svc_vc_reply; |
---|
683 | ops.xp_freeargs = svc_vc_freeargs; |
---|
684 | ops.xp_destroy = svc_vc_destroy; |
---|
685 | ops2.xp_control = svc_vc_control; |
---|
686 | } |
---|
687 | xprt->xp_ops = &ops; |
---|
688 | xprt->xp_ops2 = &ops2; |
---|
689 | mutex_unlock(&ops_lock); |
---|
690 | } |
---|
691 | |
---|
692 | static void |
---|
693 | svc_vc_rendezvous_ops(SVCXPRT *xprt) |
---|
694 | { |
---|
695 | static struct xp_ops ops; |
---|
696 | static struct xp_ops2 ops2; |
---|
697 | |
---|
698 | mutex_lock(&ops_lock); |
---|
699 | if (ops.xp_recv == NULL) { |
---|
700 | ops.xp_recv = rendezvous_request; |
---|
701 | ops.xp_stat = rendezvous_stat; |
---|
702 | ops.xp_getargs = |
---|
703 | (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort; |
---|
704 | ops.xp_reply = |
---|
705 | (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort; |
---|
706 | ops.xp_freeargs = |
---|
707 | (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort; |
---|
708 | ops.xp_destroy = svc_vc_destroy; |
---|
709 | ops2.xp_control = svc_vc_rendezvous_control; |
---|
710 | } |
---|
711 | xprt->xp_ops = &ops; |
---|
712 | xprt->xp_ops2 = &ops2; |
---|
713 | mutex_unlock(&ops_lock); |
---|
714 | } |
---|
715 | |
---|
716 | /* |
---|
717 | * Get the effective UID of the sending process. Used by rpcbind, keyserv |
---|
718 | * and rpc.yppasswdd on AF_LOCAL. |
---|
719 | */ |
---|
720 | int |
---|
721 | __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { |
---|
722 | int sock, ret; |
---|
723 | gid_t egid; |
---|
724 | uid_t euid; |
---|
725 | struct sockaddr *sa; |
---|
726 | |
---|
727 | sock = transp->xp_fd; |
---|
728 | sa = (struct sockaddr *)transp->xp_rtaddr.buf; |
---|
729 | if (sa->sa_family == AF_LOCAL) { |
---|
730 | ret = getpeereid(sock, &euid, &egid); |
---|
731 | if (ret == 0) |
---|
732 | *uid = euid; |
---|
733 | return (ret); |
---|
734 | } else |
---|
735 | return (-1); |
---|
736 | } |
---|
737 | |
---|
738 | /* |
---|
739 | * Destroy xprts that have not have had any activity in 'timeout' seconds. |
---|
740 | * If 'cleanblock' is true, blocking connections (the default) are also |
---|
741 | * cleaned. If timeout is 0, the least active connection is picked. |
---|
742 | */ |
---|
743 | bool_t |
---|
744 | __svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock) |
---|
745 | { |
---|
746 | int i, ncleaned; |
---|
747 | SVCXPRT *xprt, *least_active; |
---|
748 | struct timeval tv, tdiff, tmax; |
---|
749 | struct cf_conn *cd; |
---|
750 | |
---|
751 | gettimeofday(&tv, NULL); |
---|
752 | tmax.tv_sec = tmax.tv_usec = 0; |
---|
753 | least_active = NULL; |
---|
754 | rwlock_wrlock(&svc_fd_lock); |
---|
755 | for (i = ncleaned = 0; i <= svc_maxfd; i++) { |
---|
756 | if (FD_ISSET(i, fds)) { |
---|
757 | xprt = __svc_xports[i]; |
---|
758 | if (xprt == NULL || xprt->xp_ops == NULL || |
---|
759 | xprt->xp_ops->xp_recv != svc_vc_recv) |
---|
760 | continue; |
---|
761 | cd = (struct cf_conn *)xprt->xp_p1; |
---|
762 | if (!cleanblock && !cd->nonblock) |
---|
763 | continue; |
---|
764 | if (timeout == 0) { |
---|
765 | timersub(&tv, &cd->last_recv_time, &tdiff); |
---|
766 | if (timercmp(&tdiff, &tmax, >)) { |
---|
767 | tmax = tdiff; |
---|
768 | least_active = xprt; |
---|
769 | } |
---|
770 | continue; |
---|
771 | } |
---|
772 | if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) { |
---|
773 | __xprt_unregister_unlocked(xprt); |
---|
774 | __svc_vc_dodestroy(xprt); |
---|
775 | ncleaned++; |
---|
776 | } |
---|
777 | } |
---|
778 | } |
---|
779 | if (timeout == 0 && least_active != NULL) { |
---|
780 | __xprt_unregister_unlocked(least_active); |
---|
781 | __svc_vc_dodestroy(least_active); |
---|
782 | ncleaned++; |
---|
783 | } |
---|
784 | rwlock_unlock(&svc_fd_lock); |
---|
785 | return ncleaned > 0 ? TRUE : FALSE; |
---|
786 | } |
---|