source: rtems-libbsd/freebsd/lib/libc/rpc/svc_vc.c

6-freebsd-12
Last change on this file was bb80d9d, checked in by Sebastian Huber <sebastian.huber@…>, on 08/09/18 at 12:02:09

Update to FreeBSD head 2017-12-01

Git mirror commit e724f51f811a4b2bd29447f8b85ab5c2f9b88266.

Update #3472.

  • Property mode set to 100644
File size: 19.4 KB
Line 
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)
36static char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
37static 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
76static SVCXPRT *makefd_xprt(int, u_int, u_int);
77static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *);
78static enum xprt_stat rendezvous_stat(SVCXPRT *);
79static void svc_vc_destroy(SVCXPRT *);
80static void __svc_vc_dodestroy (SVCXPRT *);
81static int read_vc(void *, void *, int);
82static int write_vc(void *, void *, int);
83static enum xprt_stat svc_vc_stat(SVCXPRT *);
84static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *);
85static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *);
86static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *);
87static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *);
88static void svc_vc_rendezvous_ops(SVCXPRT *);
89static void svc_vc_ops(SVCXPRT *);
90static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
91static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
92                                             void *in);
93
94struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */
95        u_int sendsize;
96        u_int recvsize;
97        int maxrec;
98};
99
100struct 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 */
128SVCXPRT *
129svc_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);
176cleanup_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 */
188SVCXPRT *
189svc_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
235freedata:
236        if (ret->xp_ltaddr.buf != NULL)
237                mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen);
238
239        return NULL;
240}
241
242static SVCXPRT *
243makefd_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);
276done:
277        return (xprt);
278}
279
280/*ARGSUSED*/
281static bool_t
282rendezvous_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;
297again:
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*/
374static enum xprt_stat
375rendezvous_stat(SVCXPRT *xprt)
376{
377
378        return (XPRT_IDLE);
379}
380
381static void
382svc_vc_destroy(SVCXPRT *xprt)
383{
384        assert(xprt != NULL);
385       
386        xprt_unregister(xprt);
387        __svc_vc_dodestroy(xprt);
388}
389
390static 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*/
420static bool_t
421svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
422{
423        return (FALSE);
424}
425
426static bool_t
427svc_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 */
454static int
455read_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
505fatal_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 */
514static int
515write_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
558static enum xprt_stat
559svc_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
574static bool_t
575svc_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
602static bool_t
603svc_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
613static bool_t
614svc_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
627static bool_t
628svc_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
669static void
670svc_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
692static void
693svc_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 */
720int
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 */
743bool_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}
Note: See TracBrowser for help on using the repository browser.