source: rtems-libbsd/freebsd/lib/libc/rpc/svc_dg.c @ f41a394

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since f41a394 was 60b1d40, checked in by Sebastian Huber <sebastian.huber@…>, on 06/09/16 at 08:23:57

RPC(3): Import from FreeBSD

  • Property mode set to 100644
File size: 19.7 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2
3/*      $NetBSD: svc_dg.c,v 1.4 2000/07/06 03:10:35 christos Exp $      */
4
5/*-
6 * Copyright (c) 2009, Sun Microsystems, Inc.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 * - Redistributions of source code must retain the above copyright notice,
12 *   this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright notice,
14 *   this list of conditions and the following disclaimer in the documentation
15 *   and/or other materials provided with the distribution.
16 * - Neither the name of Sun Microsystems, Inc. nor the names of its
17 *   contributors may be used to endorse or promote products derived
18 *   from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
35 */
36
37#if defined(LIBC_SCCS) && !defined(lint)
38#ident  "@(#)svc_dg.c   1.17    94/04/24 SMI"
39#endif
40#include <sys/cdefs.h>
41__FBSDID("$FreeBSD$");
42
43/*
44 * svc_dg.c, Server side for connectionless RPC.
45 *
46 * Does some caching in the hopes of achieving execute-at-most-once semantics.
47 */
48
49#include "namespace.h"
50#include "reentrant.h"
51#include <sys/types.h>
52#include <sys/socket.h>
53#include <rpc/rpc.h>
54#include <rpc/svc_dg.h>
55#include <assert.h>
56#include <errno.h>
57#include <unistd.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <string.h>
61#ifdef RPC_CACHE_DEBUG
62#include <netconfig.h>
63#include <netdir.h>
64#endif
65#include <err.h>
66#include "un-namespace.h"
67
68#include "rpc_com.h"
69#include "mt_misc.h"
70
71#define su_data(xprt)   ((struct svc_dg_data *)(xprt->xp_p2))
72#define rpc_buffer(xprt) ((xprt)->xp_p1)
73
74#ifndef MAX
75#define MAX(a, b)       (((a) > (b)) ? (a) : (b))
76#endif
77
78static void svc_dg_ops(SVCXPRT *);
79static enum xprt_stat svc_dg_stat(SVCXPRT *);
80static bool_t svc_dg_recv(SVCXPRT *, struct rpc_msg *);
81static bool_t svc_dg_reply(SVCXPRT *, struct rpc_msg *);
82static bool_t svc_dg_getargs(SVCXPRT *, xdrproc_t, void *);
83static bool_t svc_dg_freeargs(SVCXPRT *, xdrproc_t, void *);
84static void svc_dg_destroy(SVCXPRT *);
85static bool_t svc_dg_control(SVCXPRT *, const u_int, void *);
86static int cache_get(SVCXPRT *, struct rpc_msg *, char **, size_t *);
87static void cache_set(SVCXPRT *, size_t);
88int svc_dg_enablecache(SVCXPRT *, u_int);
89
90/*
91 * Usage:
92 *      xprt = svc_dg_create(sock, sendsize, recvsize);
93 * Does other connectionless specific initializations.
94 * Once *xprt is initialized, it is registered.
95 * see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable
96 * system defaults are chosen.
97 * The routines returns NULL if a problem occurred.
98 */
99static const char svc_dg_str[] = "svc_dg_create: %s";
100static const char svc_dg_err1[] = "could not get transport information";
101static const char svc_dg_err2[] = "transport does not support data transfer";
102static const char svc_dg_err3[] = "getsockname failed";
103static const char svc_dg_err4[] = "cannot set IP_RECVDSTADDR";
104static const char __no_mem_str[] = "out of memory";
105
106SVCXPRT *
107svc_dg_create(fd, sendsize, recvsize)
108        int fd;
109        u_int sendsize;
110        u_int recvsize;
111{
112        SVCXPRT *xprt;
113        struct svc_dg_data *su = NULL;
114        struct __rpc_sockinfo si;
115        struct sockaddr_storage ss;
116        socklen_t slen;
117
118        if (!__rpc_fd2sockinfo(fd, &si)) {
119                warnx(svc_dg_str, svc_dg_err1);
120                return (NULL);
121        }
122        /*
123         * Find the receive and the send size
124         */
125        sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
126        recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
127        if ((sendsize == 0) || (recvsize == 0)) {
128                warnx(svc_dg_str, svc_dg_err2);
129                return (NULL);
130        }
131
132        xprt = svc_xprt_alloc();
133        if (xprt == NULL)
134                goto freedata;
135
136        su = mem_alloc(sizeof (*su));
137        if (su == NULL)
138                goto freedata;
139        su->su_iosz = ((MAX(sendsize, recvsize) + 3) / 4) * 4;
140        if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL)
141                goto freedata;
142        xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz,
143                XDR_DECODE);
144        su->su_cache = NULL;
145        xprt->xp_fd = fd;
146        xprt->xp_p2 = su;
147        xprt->xp_verf.oa_base = su->su_verfbody;
148        svc_dg_ops(xprt);
149        xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
150
151        slen = sizeof ss;
152        if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
153                warnx(svc_dg_str, svc_dg_err3);
154                goto freedata_nowarn;
155        }
156        xprt->xp_ltaddr.buf = mem_alloc(sizeof (struct sockaddr_storage));
157        xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_storage);
158        xprt->xp_ltaddr.len = slen;
159        memcpy(xprt->xp_ltaddr.buf, &ss, slen);
160
161        if (ss.ss_family == AF_INET) {
162                struct sockaddr_in *sin;
163                static const int true_value = 1;
164
165                sin = (struct sockaddr_in *)(void *)&ss;
166                if (sin->sin_addr.s_addr == INADDR_ANY) {
167                    su->su_srcaddr.buf = mem_alloc(sizeof (ss));
168                    su->su_srcaddr.maxlen = sizeof (ss);
169
170                    if (_setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR,
171                                    &true_value, sizeof(true_value))) {
172                            warnx(svc_dg_str,  svc_dg_err4);
173                            goto freedata_nowarn;
174                    }
175                }
176        }
177
178        xprt_register(xprt);
179        return (xprt);
180freedata:
181        (void) warnx(svc_dg_str, __no_mem_str);
182freedata_nowarn:
183        if (xprt) {
184                if (su)
185                        (void) mem_free(su, sizeof (*su));
186                svc_xprt_free(xprt);
187        }
188        return (NULL);
189}
190
191/*ARGSUSED*/
192static enum xprt_stat
193svc_dg_stat(xprt)
194        SVCXPRT *xprt;
195{
196        return (XPRT_IDLE);
197}
198
199static int
200svc_dg_recvfrom(int fd, char *buf, int buflen,
201    struct sockaddr *raddr, socklen_t *raddrlen,
202    struct sockaddr *laddr, socklen_t *laddrlen)
203{
204        struct msghdr msg;
205        struct iovec msg_iov[1];
206        struct sockaddr_in *lin = (struct sockaddr_in *)laddr;
207        int rlen;
208        bool_t have_lin = FALSE;
209        char tmp[CMSG_LEN(sizeof(*lin))];
210        struct cmsghdr *cmsg;
211
212        memset((char *)&msg, 0, sizeof(msg));
213        msg_iov[0].iov_base = buf;
214        msg_iov[0].iov_len = buflen;
215        msg.msg_iov = msg_iov;
216        msg.msg_iovlen = 1;
217        msg.msg_namelen = *raddrlen;
218        msg.msg_name = (char *)raddr;
219        if (laddr != NULL) {
220            msg.msg_control = (caddr_t)tmp;
221            msg.msg_controllen = CMSG_LEN(sizeof(*lin));
222        }
223        rlen = _recvmsg(fd, &msg, 0);
224        if (rlen >= 0)
225                *raddrlen = msg.msg_namelen;
226
227        if (rlen == -1 || laddr == NULL ||
228            msg.msg_controllen < sizeof(struct cmsghdr) ||
229            msg.msg_flags & MSG_CTRUNC)
230                return rlen;
231
232        for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
233             cmsg = CMSG_NXTHDR(&msg, cmsg)) {
234                if (cmsg->cmsg_level == IPPROTO_IP &&
235                    cmsg->cmsg_type == IP_RECVDSTADDR) {
236                        have_lin = TRUE;
237                        memcpy(&lin->sin_addr,
238                            (struct in_addr *)CMSG_DATA(cmsg),
239                            sizeof(struct in_addr));
240                        break;
241                }
242        }
243
244        lin->sin_family = AF_INET;
245        lin->sin_port = 0;
246        *laddrlen = sizeof(struct sockaddr_in);
247
248        if (!have_lin)
249                lin->sin_addr.s_addr = INADDR_ANY;
250
251        return rlen;
252}
253
254static bool_t
255svc_dg_recv(xprt, msg)
256        SVCXPRT *xprt;
257        struct rpc_msg *msg;
258{
259        struct svc_dg_data *su = su_data(xprt);
260        XDR *xdrs = &(su->su_xdrs);
261        char *reply;
262        struct sockaddr_storage ss;
263        socklen_t alen;
264        size_t replylen;
265        ssize_t rlen;
266
267again:
268        alen = sizeof (struct sockaddr_storage);
269        rlen = svc_dg_recvfrom(xprt->xp_fd, rpc_buffer(xprt), su->su_iosz,
270            (struct sockaddr *)(void *)&ss, &alen,
271            (struct sockaddr *)su->su_srcaddr.buf, &su->su_srcaddr.len);
272        if (rlen == -1 && errno == EINTR)
273                goto again;
274        if (rlen == -1 || (rlen < (ssize_t)(4 * sizeof (u_int32_t))))
275                return (FALSE);
276        if (xprt->xp_rtaddr.len < alen) {
277                if (xprt->xp_rtaddr.len != 0)
278                        mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.len);
279                xprt->xp_rtaddr.buf = mem_alloc(alen);
280                xprt->xp_rtaddr.len = alen;
281        }
282        memcpy(xprt->xp_rtaddr.buf, &ss, alen);
283#ifdef PORTMAP
284        if (ss.ss_family == AF_INET) {
285                xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf;
286                xprt->xp_addrlen = sizeof (struct sockaddr_in);
287        }
288#endif                          /* PORTMAP */
289        xdrs->x_op = XDR_DECODE;
290        XDR_SETPOS(xdrs, 0);
291        if (! xdr_callmsg(xdrs, msg)) {
292                return (FALSE);
293        }
294        su->su_xid = msg->rm_xid;
295        if (su->su_cache != NULL) {
296                if (cache_get(xprt, msg, &reply, &replylen)) {
297                        (void)_sendto(xprt->xp_fd, reply, replylen, 0,
298                            (struct sockaddr *)(void *)&ss, alen);
299                        return (FALSE);
300                }
301        }
302        return (TRUE);
303}
304
305static int
306svc_dg_sendto(int fd, char *buf, int buflen,
307    const struct sockaddr *raddr, socklen_t raddrlen,
308    const struct sockaddr *laddr, socklen_t laddrlen)
309{
310        struct msghdr msg;
311        struct iovec msg_iov[1];
312        struct sockaddr_in *laddr_in = (struct sockaddr_in *)laddr;
313        struct in_addr *lin = &laddr_in->sin_addr;
314        char tmp[CMSG_SPACE(sizeof(*lin))];
315        struct cmsghdr *cmsg;
316
317        memset((char *)&msg, 0, sizeof(msg));
318        msg_iov[0].iov_base = buf;
319        msg_iov[0].iov_len = buflen;
320        msg.msg_iov = msg_iov;
321        msg.msg_iovlen = 1;
322        msg.msg_namelen = raddrlen;
323        msg.msg_name = (char *)raddr;
324
325        if (laddr != NULL && laddr->sa_family == AF_INET &&
326            lin->s_addr != INADDR_ANY) {
327                msg.msg_control = (caddr_t)tmp;
328                msg.msg_controllen = CMSG_LEN(sizeof(*lin));
329                cmsg = CMSG_FIRSTHDR(&msg);
330                cmsg->cmsg_len = CMSG_LEN(sizeof(*lin));
331                cmsg->cmsg_level = IPPROTO_IP;
332                cmsg->cmsg_type = IP_SENDSRCADDR;
333                memcpy(CMSG_DATA(cmsg), lin, sizeof(*lin));
334        }
335
336        return _sendmsg(fd, &msg, 0);
337}
338
339static bool_t
340svc_dg_reply(xprt, msg)
341        SVCXPRT *xprt;
342        struct rpc_msg *msg;
343{
344        struct svc_dg_data *su = su_data(xprt);
345        XDR *xdrs = &(su->su_xdrs);
346        bool_t stat = TRUE;
347        size_t slen;
348        xdrproc_t xdr_proc;
349        caddr_t xdr_where;
350
351        xdrs->x_op = XDR_ENCODE;
352        XDR_SETPOS(xdrs, 0);
353        msg->rm_xid = su->su_xid;
354        if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
355            msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
356                xdr_proc = msg->acpted_rply.ar_results.proc;
357                xdr_where = msg->acpted_rply.ar_results.where;
358                msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
359                msg->acpted_rply.ar_results.where = NULL;
360
361                if (!xdr_replymsg(xdrs, msg) ||
362                    !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where))
363                        stat = FALSE;
364        } else {
365                stat = xdr_replymsg(xdrs, msg);
366        }
367        if (stat) {
368                slen = XDR_GETPOS(xdrs);
369                if (svc_dg_sendto(xprt->xp_fd, rpc_buffer(xprt), slen,
370                    (struct sockaddr *)xprt->xp_rtaddr.buf,
371                    (socklen_t)xprt->xp_rtaddr.len,
372                    (struct sockaddr *)su->su_srcaddr.buf,
373                    (socklen_t)su->su_srcaddr.len) == (ssize_t) slen) {
374                        stat = TRUE;
375                        if (su->su_cache)
376                                cache_set(xprt, slen);
377                }
378        }
379        return (stat);
380}
381
382static bool_t
383svc_dg_getargs(xprt, xdr_args, args_ptr)
384        SVCXPRT *xprt;
385        xdrproc_t xdr_args;
386        void *args_ptr;
387{
388        struct svc_dg_data *su;
389
390        assert(xprt != NULL);
391        su = su_data(xprt);
392        return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt),
393                &su->su_xdrs, xdr_args, args_ptr));
394}
395
396static bool_t
397svc_dg_freeargs(xprt, xdr_args, args_ptr)
398        SVCXPRT *xprt;
399        xdrproc_t xdr_args;
400        void *args_ptr;
401{
402        XDR *xdrs = &(su_data(xprt)->su_xdrs);
403
404        xdrs->x_op = XDR_FREE;
405        return (*xdr_args)(xdrs, args_ptr);
406}
407
408static void
409svc_dg_destroy(xprt)
410        SVCXPRT *xprt;
411{
412        struct svc_dg_data *su = su_data(xprt);
413
414        xprt_unregister(xprt);
415        if (xprt->xp_fd != -1)
416                (void)_close(xprt->xp_fd);
417        XDR_DESTROY(&(su->su_xdrs));
418        (void) mem_free(rpc_buffer(xprt), su->su_iosz);
419        if (su->su_srcaddr.buf)
420                (void) mem_free(su->su_srcaddr.buf, su->su_srcaddr.maxlen);
421        (void) mem_free(su, sizeof (*su));
422        if (xprt->xp_rtaddr.buf)
423                (void) mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
424        if (xprt->xp_ltaddr.buf)
425                (void) mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
426        if (xprt->xp_tp)
427                (void) free(xprt->xp_tp);
428        svc_xprt_free(xprt);
429}
430
431static bool_t
432/*ARGSUSED*/
433svc_dg_control(xprt, rq, in)
434        SVCXPRT *xprt;
435        const u_int     rq;
436        void            *in;
437{
438        return (FALSE);
439}
440
441static void
442svc_dg_ops(xprt)
443        SVCXPRT *xprt;
444{
445        static struct xp_ops ops;
446        static struct xp_ops2 ops2;
447
448/* VARIABLES PROTECTED BY ops_lock: ops */
449
450        mutex_lock(&ops_lock);
451        if (ops.xp_recv == NULL) {
452                ops.xp_recv = svc_dg_recv;
453                ops.xp_stat = svc_dg_stat;
454                ops.xp_getargs = svc_dg_getargs;
455                ops.xp_reply = svc_dg_reply;
456                ops.xp_freeargs = svc_dg_freeargs;
457                ops.xp_destroy = svc_dg_destroy;
458                ops2.xp_control = svc_dg_control;
459        }
460        xprt->xp_ops = &ops;
461        xprt->xp_ops2 = &ops2;
462        mutex_unlock(&ops_lock);
463}
464
465/*  The CACHING COMPONENT */
466
467/*
468 * Could have been a separate file, but some part of it depends upon the
469 * private structure of the client handle.
470 *
471 * Fifo cache for cl server
472 * Copies pointers to reply buffers into fifo cache
473 * Buffers are sent again if retransmissions are detected.
474 */
475
476#define SPARSENESS 4    /* 75% sparse */
477
478#define ALLOC(type, size)       \
479        (type *) mem_alloc((sizeof (type) * (size)))
480
481#define MEMZERO(addr, type, size)        \
482        (void) memset((void *) (addr), 0, sizeof (type) * (int) (size))
483
484#define FREE(addr, type, size)  \
485        mem_free((addr), (sizeof (type) * (size)))
486
487/*
488 * An entry in the cache
489 */
490typedef struct cache_node *cache_ptr;
491struct cache_node {
492        /*
493         * Index into cache is xid, proc, vers, prog and address
494         */
495        u_int32_t cache_xid;
496        rpcproc_t cache_proc;
497        rpcvers_t cache_vers;
498        rpcprog_t cache_prog;
499        struct netbuf cache_addr;
500        /*
501         * The cached reply and length
502         */
503        char *cache_reply;
504        size_t cache_replylen;
505        /*
506         * Next node on the list, if there is a collision
507         */
508        cache_ptr cache_next;
509};
510
511/*
512 * The entire cache
513 */
514struct cl_cache {
515        u_int uc_size;          /* size of cache */
516        cache_ptr *uc_entries;  /* hash table of entries in cache */
517        cache_ptr *uc_fifo;     /* fifo list of entries in cache */
518        u_int uc_nextvictim;    /* points to next victim in fifo list */
519        rpcprog_t uc_prog;      /* saved program number */
520        rpcvers_t uc_vers;      /* saved version number */
521        rpcproc_t uc_proc;      /* saved procedure number */
522};
523
524
525/*
526 * the hashing function
527 */
528#define CACHE_LOC(transp, xid)  \
529        (xid % (SPARSENESS * ((struct cl_cache *) \
530                su_data(transp)->su_cache)->uc_size))
531
532/*
533 * Enable use of the cache. Returns 1 on success, 0 on failure.
534 * Note: there is no disable.
535 */
536static const char cache_enable_str[] = "svc_enablecache: %s %s";
537static const char alloc_err[] = "could not allocate cache ";
538static const char enable_err[] = "cache already enabled";
539
540int
541svc_dg_enablecache(transp, size)
542        SVCXPRT *transp;
543        u_int size;
544{
545        struct svc_dg_data *su = su_data(transp);
546        struct cl_cache *uc;
547
548        mutex_lock(&dupreq_lock);
549        if (su->su_cache != NULL) {
550                (void) warnx(cache_enable_str, enable_err, " ");
551                mutex_unlock(&dupreq_lock);
552                return (0);
553        }
554        uc = ALLOC(struct cl_cache, 1);
555        if (uc == NULL) {
556                warnx(cache_enable_str, alloc_err, " ");
557                mutex_unlock(&dupreq_lock);
558                return (0);
559        }
560        uc->uc_size = size;
561        uc->uc_nextvictim = 0;
562        uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS);
563        if (uc->uc_entries == NULL) {
564                warnx(cache_enable_str, alloc_err, "data");
565                FREE(uc, struct cl_cache, 1);
566                mutex_unlock(&dupreq_lock);
567                return (0);
568        }
569        MEMZERO(uc->uc_entries, cache_ptr, size * SPARSENESS);
570        uc->uc_fifo = ALLOC(cache_ptr, size);
571        if (uc->uc_fifo == NULL) {
572                warnx(cache_enable_str, alloc_err, "fifo");
573                FREE(uc->uc_entries, cache_ptr, size * SPARSENESS);
574                FREE(uc, struct cl_cache, 1);
575                mutex_unlock(&dupreq_lock);
576                return (0);
577        }
578        MEMZERO(uc->uc_fifo, cache_ptr, size);
579        su->su_cache = (char *)(void *)uc;
580        mutex_unlock(&dupreq_lock);
581        return (1);
582}
583
584/*
585 * Set an entry in the cache.  It assumes that the uc entry is set from
586 * the earlier call to cache_get() for the same procedure.  This will always
587 * happen because cache_get() is calle by svc_dg_recv and cache_set() is called
588 * by svc_dg_reply().  All this hoopla because the right RPC parameters are
589 * not available at svc_dg_reply time.
590 */
591
592static const char cache_set_str[] = "cache_set: %s";
593static const char cache_set_err1[] = "victim not found";
594static const char cache_set_err2[] = "victim alloc failed";
595static const char cache_set_err3[] = "could not allocate new rpc buffer";
596
597static void
598cache_set(xprt, replylen)
599        SVCXPRT *xprt;
600        size_t replylen;
601{
602        cache_ptr victim;
603        cache_ptr *vicp;
604        struct svc_dg_data *su = su_data(xprt);
605        struct cl_cache *uc = (struct cl_cache *) su->su_cache;
606        u_int loc;
607        char *newbuf;
608#ifdef RPC_CACHE_DEBUG
609        struct netconfig *nconf;
610        char *uaddr;
611#endif
612
613        mutex_lock(&dupreq_lock);
614        /*
615         * Find space for the new entry, either by
616         * reusing an old entry, or by mallocing a new one
617         */
618        victim = uc->uc_fifo[uc->uc_nextvictim];
619        if (victim != NULL) {
620                loc = CACHE_LOC(xprt, victim->cache_xid);
621                for (vicp = &uc->uc_entries[loc];
622                        *vicp != NULL && *vicp != victim;
623                        vicp = &(*vicp)->cache_next)
624                        ;
625                if (*vicp == NULL) {
626                        warnx(cache_set_str, cache_set_err1);
627                        mutex_unlock(&dupreq_lock);
628                        return;
629                }
630                *vicp = victim->cache_next;     /* remove from cache */
631                newbuf = victim->cache_reply;
632        } else {
633                victim = ALLOC(struct cache_node, 1);
634                if (victim == NULL) {
635                        warnx(cache_set_str, cache_set_err2);
636                        mutex_unlock(&dupreq_lock);
637                        return;
638                }
639                newbuf = mem_alloc(su->su_iosz);
640                if (newbuf == NULL) {
641                        warnx(cache_set_str, cache_set_err3);
642                        FREE(victim, struct cache_node, 1);
643                        mutex_unlock(&dupreq_lock);
644                        return;
645                }
646        }
647
648        /*
649         * Store it away
650         */
651#ifdef RPC_CACHE_DEBUG
652        if (nconf = getnetconfigent(xprt->xp_netid)) {
653                uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr);
654                freenetconfigent(nconf);
655                printf(
656        "cache set for xid= %x prog=%d vers=%d proc=%d for rmtaddr=%s\n",
657                        su->su_xid, uc->uc_prog, uc->uc_vers,
658                        uc->uc_proc, uaddr);
659                free(uaddr);
660        }
661#endif
662        victim->cache_replylen = replylen;
663        victim->cache_reply = rpc_buffer(xprt);
664        rpc_buffer(xprt) = newbuf;
665        xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt),
666                        su->su_iosz, XDR_ENCODE);
667        victim->cache_xid = su->su_xid;
668        victim->cache_proc = uc->uc_proc;
669        victim->cache_vers = uc->uc_vers;
670        victim->cache_prog = uc->uc_prog;
671        victim->cache_addr = xprt->xp_rtaddr;
672        victim->cache_addr.buf = ALLOC(char, xprt->xp_rtaddr.len);
673        (void) memcpy(victim->cache_addr.buf, xprt->xp_rtaddr.buf,
674            (size_t)xprt->xp_rtaddr.len);
675        loc = CACHE_LOC(xprt, victim->cache_xid);
676        victim->cache_next = uc->uc_entries[loc];
677        uc->uc_entries[loc] = victim;
678        uc->uc_fifo[uc->uc_nextvictim++] = victim;
679        uc->uc_nextvictim %= uc->uc_size;
680        mutex_unlock(&dupreq_lock);
681}
682
683/*
684 * Try to get an entry from the cache
685 * return 1 if found, 0 if not found and set the stage for cache_set()
686 */
687static int
688cache_get(xprt, msg, replyp, replylenp)
689        SVCXPRT *xprt;
690        struct rpc_msg *msg;
691        char **replyp;
692        size_t *replylenp;
693{
694        u_int loc;
695        cache_ptr ent;
696        struct svc_dg_data *su = su_data(xprt);
697        struct cl_cache *uc = (struct cl_cache *) su->su_cache;
698#ifdef RPC_CACHE_DEBUG
699        struct netconfig *nconf;
700        char *uaddr;
701#endif
702
703        mutex_lock(&dupreq_lock);
704        loc = CACHE_LOC(xprt, su->su_xid);
705        for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) {
706                if (ent->cache_xid == su->su_xid &&
707                        ent->cache_proc == msg->rm_call.cb_proc &&
708                        ent->cache_vers == msg->rm_call.cb_vers &&
709                        ent->cache_prog == msg->rm_call.cb_prog &&
710                        ent->cache_addr.len == xprt->xp_rtaddr.len &&
711                        (memcmp(ent->cache_addr.buf, xprt->xp_rtaddr.buf,
712                                xprt->xp_rtaddr.len) == 0)) {
713#ifdef RPC_CACHE_DEBUG
714                        if (nconf = getnetconfigent(xprt->xp_netid)) {
715                                uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr);
716                                freenetconfigent(nconf);
717                                printf(
718        "cache entry found for xid=%x prog=%d vers=%d proc=%d for rmtaddr=%s\n",
719                                        su->su_xid, msg->rm_call.cb_prog,
720                                        msg->rm_call.cb_vers,
721                                        msg->rm_call.cb_proc, uaddr);
722                                free(uaddr);
723                        }
724#endif
725                        *replyp = ent->cache_reply;
726                        *replylenp = ent->cache_replylen;
727                        mutex_unlock(&dupreq_lock);
728                        return (1);
729                }
730        }
731        /*
732         * Failed to find entry
733         * Remember a few things so we can do a set later
734         */
735        uc->uc_proc = msg->rm_call.cb_proc;
736        uc->uc_vers = msg->rm_call.cb_vers;
737        uc->uc_prog = msg->rm_call.cb_prog;
738        mutex_unlock(&dupreq_lock);
739        return (0);
740}
Note: See TracBrowser for help on using the repository browser.