1*84d9c625SLionel Sambuc /* $NetBSD: svc_dg.c,v 1.17 2013/03/11 20:19:29 tron Exp $ */
22fe8fb19SBen Gras
32fe8fb19SBen Gras /*
4*84d9c625SLionel Sambuc * Copyright (c) 2010, Oracle America, Inc.
52fe8fb19SBen Gras *
6*84d9c625SLionel Sambuc * Redistribution and use in source and binary forms, with or without
7*84d9c625SLionel Sambuc * modification, are permitted provided that the following conditions are
8*84d9c625SLionel Sambuc * met:
92fe8fb19SBen Gras *
10*84d9c625SLionel Sambuc * * Redistributions of source code must retain the above copyright
11*84d9c625SLionel Sambuc * notice, this list of conditions and the following disclaimer.
12*84d9c625SLionel Sambuc * * Redistributions in binary form must reproduce the above
13*84d9c625SLionel Sambuc * copyright notice, this list of conditions and the following
14*84d9c625SLionel Sambuc * disclaimer in the documentation and/or other materials
15*84d9c625SLionel Sambuc * provided with the distribution.
16*84d9c625SLionel Sambuc * * Neither the name of the "Oracle America, Inc." nor the names of its
17*84d9c625SLionel Sambuc * contributors may be used to endorse or promote products derived
18*84d9c625SLionel Sambuc * from this software without specific prior written permission.
192fe8fb19SBen Gras *
20*84d9c625SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*84d9c625SLionel Sambuc * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*84d9c625SLionel Sambuc * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*84d9c625SLionel Sambuc * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24*84d9c625SLionel Sambuc * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25*84d9c625SLionel Sambuc * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26*84d9c625SLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27*84d9c625SLionel Sambuc * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28*84d9c625SLionel Sambuc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29*84d9c625SLionel Sambuc * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30*84d9c625SLionel Sambuc * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31*84d9c625SLionel Sambuc * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
322fe8fb19SBen Gras */
332fe8fb19SBen Gras
342fe8fb19SBen Gras /*
352fe8fb19SBen Gras * Copyright (c) 1986-1991 by Sun Microsystems Inc.
362fe8fb19SBen Gras */
372fe8fb19SBen Gras
382fe8fb19SBen Gras /* #ident "@(#)svc_dg.c 1.17 94/04/24 SMI" */
392fe8fb19SBen Gras
402fe8fb19SBen Gras
412fe8fb19SBen Gras /*
422fe8fb19SBen Gras * svc_dg.c, Server side for connectionless RPC.
432fe8fb19SBen Gras *
442fe8fb19SBen Gras * Does some caching in the hopes of achieving execute-at-most-once semantics.
452fe8fb19SBen Gras */
462fe8fb19SBen Gras
472fe8fb19SBen Gras #include <sys/cdefs.h>
482fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
49*84d9c625SLionel Sambuc __RCSID("$NetBSD: svc_dg.c,v 1.17 2013/03/11 20:19:29 tron Exp $");
502fe8fb19SBen Gras #endif
512fe8fb19SBen Gras
522fe8fb19SBen Gras #include "namespace.h"
532fe8fb19SBen Gras #include "reentrant.h"
542fe8fb19SBen Gras #include <sys/types.h>
552fe8fb19SBen Gras #include <sys/socket.h>
562fe8fb19SBen Gras #include <rpc/rpc.h>
572fe8fb19SBen Gras #include <assert.h>
582fe8fb19SBen Gras #include <errno.h>
592fe8fb19SBen Gras #include <unistd.h>
602fe8fb19SBen Gras #include <stdio.h>
612fe8fb19SBen Gras #include <stdlib.h>
622fe8fb19SBen Gras #include <string.h>
632fe8fb19SBen Gras #ifdef RPC_CACHE_DEBUG
642fe8fb19SBen Gras #include <netconfig.h>
652fe8fb19SBen Gras #include <netdir.h>
662fe8fb19SBen Gras #endif
672fe8fb19SBen Gras #include <err.h>
682fe8fb19SBen Gras
69*84d9c625SLionel Sambuc #include "svc_fdset.h"
702fe8fb19SBen Gras #include "rpc_internal.h"
712fe8fb19SBen Gras #include "svc_dg.h"
722fe8fb19SBen Gras
732fe8fb19SBen Gras #define su_data(xprt) ((struct svc_dg_data *)(xprt->xp_p2))
742fe8fb19SBen Gras #define rpc_buffer(xprt) ((xprt)->xp_p1)
752fe8fb19SBen Gras
762fe8fb19SBen Gras #ifdef __weak_alias
772fe8fb19SBen Gras __weak_alias(svc_dg_create,_svc_dg_create)
782fe8fb19SBen Gras #endif
792fe8fb19SBen Gras
802fe8fb19SBen Gras #ifndef MAX
812fe8fb19SBen Gras #define MAX(a, b) (((a) > (b)) ? (a) : (b))
822fe8fb19SBen Gras #endif
832fe8fb19SBen Gras
84f14fb602SLionel Sambuc static void svc_dg_ops(SVCXPRT *);
85f14fb602SLionel Sambuc static enum xprt_stat svc_dg_stat(SVCXPRT *);
86f14fb602SLionel Sambuc static bool_t svc_dg_recv(SVCXPRT *, struct rpc_msg *);
87f14fb602SLionel Sambuc static bool_t svc_dg_reply(SVCXPRT *, struct rpc_msg *);
88f14fb602SLionel Sambuc static bool_t svc_dg_getargs(SVCXPRT *, xdrproc_t, caddr_t);
89f14fb602SLionel Sambuc static bool_t svc_dg_freeargs(SVCXPRT *, xdrproc_t, caddr_t);
90f14fb602SLionel Sambuc static void svc_dg_destroy(SVCXPRT *);
91f14fb602SLionel Sambuc static bool_t svc_dg_control(SVCXPRT *, const u_int, void *);
92f14fb602SLionel Sambuc static int cache_get(SVCXPRT *, struct rpc_msg *, char **, size_t *);
93f14fb602SLionel Sambuc static void cache_set(SVCXPRT *, size_t);
942fe8fb19SBen Gras
952fe8fb19SBen Gras /*
962fe8fb19SBen Gras * Usage:
972fe8fb19SBen Gras * xprt = svc_dg_create(sock, sendsize, recvsize);
982fe8fb19SBen Gras * Does other connectionless specific initializations.
992fe8fb19SBen Gras * Once *xprt is initialized, it is registered.
1002fe8fb19SBen Gras * see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable
1012fe8fb19SBen Gras * system defaults are chosen.
1022fe8fb19SBen Gras * The routines returns NULL if a problem occurred.
1032fe8fb19SBen Gras */
1042fe8fb19SBen Gras static const char svc_dg_str[] = "svc_dg_create: %s";
1052fe8fb19SBen Gras static const char svc_dg_err1[] = "could not get transport information";
1062fe8fb19SBen Gras static const char svc_dg_err2[] = " transport does not support data transfer";
1072fe8fb19SBen Gras static const char __no_mem_str[] = "out of memory";
1082fe8fb19SBen Gras
1092fe8fb19SBen Gras SVCXPRT *
svc_dg_create(int fd,u_int sendsize,u_int recvsize)110f14fb602SLionel Sambuc svc_dg_create(int fd, u_int sendsize, u_int recvsize)
1112fe8fb19SBen Gras {
1122fe8fb19SBen Gras SVCXPRT *xprt;
1132fe8fb19SBen Gras struct svc_dg_data *su = NULL;
1142fe8fb19SBen Gras struct __rpc_sockinfo si;
1152fe8fb19SBen Gras struct sockaddr_storage ss;
1162fe8fb19SBen Gras socklen_t slen;
1172fe8fb19SBen Gras
1182fe8fb19SBen Gras if (!__rpc_fd2sockinfo(fd, &si)) {
1192fe8fb19SBen Gras warnx(svc_dg_str, svc_dg_err1);
1202fe8fb19SBen Gras return (NULL);
1212fe8fb19SBen Gras }
1222fe8fb19SBen Gras /*
1232fe8fb19SBen Gras * Find the receive and the send size
1242fe8fb19SBen Gras */
1252fe8fb19SBen Gras sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
1262fe8fb19SBen Gras recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
1272fe8fb19SBen Gras if ((sendsize == 0) || (recvsize == 0)) {
1282fe8fb19SBen Gras warnx(svc_dg_str, svc_dg_err2);
1292fe8fb19SBen Gras return (NULL);
1302fe8fb19SBen Gras }
1312fe8fb19SBen Gras
1322fe8fb19SBen Gras xprt = mem_alloc(sizeof (SVCXPRT));
1332fe8fb19SBen Gras if (xprt == NULL)
134*84d9c625SLionel Sambuc goto outofmem;
1352fe8fb19SBen Gras memset(xprt, 0, sizeof (SVCXPRT));
1362fe8fb19SBen Gras
1372fe8fb19SBen Gras su = mem_alloc(sizeof (*su));
1382fe8fb19SBen Gras if (su == NULL)
139*84d9c625SLionel Sambuc goto outofmem;
1402fe8fb19SBen Gras su->su_iosz = ((MAX(sendsize, recvsize) + 3) / 4) * 4;
1412fe8fb19SBen Gras if ((rpc_buffer(xprt) = malloc(su->su_iosz)) == NULL)
142*84d9c625SLionel Sambuc goto outofmem;
143f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(u_int, su->su_iosz));
144f14fb602SLionel Sambuc xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), (u_int)su->su_iosz,
1452fe8fb19SBen Gras XDR_DECODE);
1462fe8fb19SBen Gras su->su_cache = NULL;
1472fe8fb19SBen Gras xprt->xp_fd = fd;
1482fe8fb19SBen Gras xprt->xp_p2 = (caddr_t)(void *)su;
1492fe8fb19SBen Gras xprt->xp_verf.oa_base = su->su_verfbody;
1502fe8fb19SBen Gras svc_dg_ops(xprt);
1512fe8fb19SBen Gras xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
1522fe8fb19SBen Gras
1532fe8fb19SBen Gras slen = sizeof ss;
1542fe8fb19SBen Gras if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
1552fe8fb19SBen Gras goto freedata;
1562fe8fb19SBen Gras xprt->xp_ltaddr.buf = mem_alloc(sizeof (struct sockaddr_storage));
1572fe8fb19SBen Gras xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_storage);
1582fe8fb19SBen Gras xprt->xp_ltaddr.len = slen;
1592fe8fb19SBen Gras memcpy(xprt->xp_ltaddr.buf, &ss, slen);
1602fe8fb19SBen Gras
161*84d9c625SLionel Sambuc if (!xprt_register(xprt))
162*84d9c625SLionel Sambuc goto freedata;
1632fe8fb19SBen Gras return (xprt);
164*84d9c625SLionel Sambuc
165*84d9c625SLionel Sambuc outofmem:
1662fe8fb19SBen Gras (void) warnx(svc_dg_str, __no_mem_str);
167*84d9c625SLionel Sambuc freedata:
1682fe8fb19SBen Gras if (xprt) {
1692fe8fb19SBen Gras if (su)
1702fe8fb19SBen Gras (void) mem_free(su, sizeof (*su));
1712fe8fb19SBen Gras (void) mem_free(xprt, sizeof (SVCXPRT));
1722fe8fb19SBen Gras }
1732fe8fb19SBen Gras return (NULL);
1742fe8fb19SBen Gras }
1752fe8fb19SBen Gras
1762fe8fb19SBen Gras /*ARGSUSED*/
1772fe8fb19SBen Gras static enum xprt_stat
svc_dg_stat(SVCXPRT * xprt)178f14fb602SLionel Sambuc svc_dg_stat(SVCXPRT *xprt)
1792fe8fb19SBen Gras {
1802fe8fb19SBen Gras return (XPRT_IDLE);
1812fe8fb19SBen Gras }
1822fe8fb19SBen Gras
1832fe8fb19SBen Gras static bool_t
svc_dg_recv(SVCXPRT * xprt,struct rpc_msg * msg)184f14fb602SLionel Sambuc svc_dg_recv(SVCXPRT *xprt, struct rpc_msg *msg)
1852fe8fb19SBen Gras {
1862fe8fb19SBen Gras struct svc_dg_data *su;
1872fe8fb19SBen Gras XDR *xdrs;
1882fe8fb19SBen Gras char *reply;
1892fe8fb19SBen Gras struct sockaddr_storage ss;
1902fe8fb19SBen Gras socklen_t alen;
1912fe8fb19SBen Gras size_t replylen;
1922fe8fb19SBen Gras ssize_t rlen;
1932fe8fb19SBen Gras
1942fe8fb19SBen Gras _DIAGASSERT(xprt != NULL);
1952fe8fb19SBen Gras _DIAGASSERT(msg != NULL);
1962fe8fb19SBen Gras
1972fe8fb19SBen Gras su = su_data(xprt);
1982fe8fb19SBen Gras xdrs = &(su->su_xdrs);
1992fe8fb19SBen Gras
2002fe8fb19SBen Gras again:
2012fe8fb19SBen Gras alen = sizeof (struct sockaddr_storage);
2022fe8fb19SBen Gras rlen = recvfrom(xprt->xp_fd, rpc_buffer(xprt), su->su_iosz, 0,
2032fe8fb19SBen Gras (struct sockaddr *)(void *)&ss, &alen);
2042fe8fb19SBen Gras if (rlen == -1 && errno == EINTR)
2052fe8fb19SBen Gras goto again;
2062fe8fb19SBen Gras if (rlen == -1 || (rlen < (ssize_t)(4 * sizeof (u_int32_t))))
2072fe8fb19SBen Gras return (FALSE);
2082fe8fb19SBen Gras if (xprt->xp_rtaddr.len < alen) {
2092fe8fb19SBen Gras if (xprt->xp_rtaddr.len != 0)
2102fe8fb19SBen Gras mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.len);
2112fe8fb19SBen Gras xprt->xp_rtaddr.buf = mem_alloc(alen);
2122fe8fb19SBen Gras xprt->xp_rtaddr.len = alen;
2132fe8fb19SBen Gras }
2142fe8fb19SBen Gras memcpy(xprt->xp_rtaddr.buf, &ss, alen);
2152fe8fb19SBen Gras #ifdef PORTMAP
2162fe8fb19SBen Gras if (ss.ss_family == AF_INET) {
2172fe8fb19SBen Gras xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf;
2182fe8fb19SBen Gras xprt->xp_addrlen = sizeof (struct sockaddr_in);
2192fe8fb19SBen Gras }
2202fe8fb19SBen Gras #endif
2212fe8fb19SBen Gras xdrs->x_op = XDR_DECODE;
2222fe8fb19SBen Gras XDR_SETPOS(xdrs, 0);
2232fe8fb19SBen Gras if (! xdr_callmsg(xdrs, msg)) {
2242fe8fb19SBen Gras return (FALSE);
2252fe8fb19SBen Gras }
2262fe8fb19SBen Gras su->su_xid = msg->rm_xid;
2272fe8fb19SBen Gras if (su->su_cache != NULL) {
2282fe8fb19SBen Gras if (cache_get(xprt, msg, &reply, &replylen)) {
2292fe8fb19SBen Gras (void)sendto(xprt->xp_fd, reply, replylen, 0,
2302fe8fb19SBen Gras (struct sockaddr *)(void *)&ss, alen);
2312fe8fb19SBen Gras return (FALSE);
2322fe8fb19SBen Gras }
2332fe8fb19SBen Gras }
2342fe8fb19SBen Gras return (TRUE);
2352fe8fb19SBen Gras }
2362fe8fb19SBen Gras
2372fe8fb19SBen Gras static bool_t
svc_dg_reply(SVCXPRT * xprt,struct rpc_msg * msg)238f14fb602SLionel Sambuc svc_dg_reply(SVCXPRT *xprt, struct rpc_msg *msg)
2392fe8fb19SBen Gras {
2402fe8fb19SBen Gras struct svc_dg_data *su;
2412fe8fb19SBen Gras XDR *xdrs;
2422fe8fb19SBen Gras bool_t stat = FALSE;
2432fe8fb19SBen Gras size_t slen;
2442fe8fb19SBen Gras
2452fe8fb19SBen Gras _DIAGASSERT(xprt != NULL);
2462fe8fb19SBen Gras _DIAGASSERT(msg != NULL);
2472fe8fb19SBen Gras
2482fe8fb19SBen Gras su = su_data(xprt);
2492fe8fb19SBen Gras xdrs = &(su->su_xdrs);
2502fe8fb19SBen Gras
2512fe8fb19SBen Gras xdrs->x_op = XDR_ENCODE;
2522fe8fb19SBen Gras XDR_SETPOS(xdrs, 0);
2532fe8fb19SBen Gras msg->rm_xid = su->su_xid;
2542fe8fb19SBen Gras if (xdr_replymsg(xdrs, msg)) {
2552fe8fb19SBen Gras slen = XDR_GETPOS(xdrs);
2562fe8fb19SBen Gras if (sendto(xprt->xp_fd, rpc_buffer(xprt), slen, 0,
2572fe8fb19SBen Gras (struct sockaddr *)xprt->xp_rtaddr.buf,
2582fe8fb19SBen Gras (socklen_t)xprt->xp_rtaddr.len) == (ssize_t) slen) {
2592fe8fb19SBen Gras stat = TRUE;
2602fe8fb19SBen Gras if (su->su_cache)
2612fe8fb19SBen Gras cache_set(xprt, slen);
2622fe8fb19SBen Gras }
2632fe8fb19SBen Gras }
2642fe8fb19SBen Gras return (stat);
2652fe8fb19SBen Gras }
2662fe8fb19SBen Gras
2672fe8fb19SBen Gras static bool_t
svc_dg_getargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)268f14fb602SLionel Sambuc svc_dg_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
2692fe8fb19SBen Gras {
2702fe8fb19SBen Gras return (*xdr_args)(&(su_data(xprt)->su_xdrs), args_ptr);
2712fe8fb19SBen Gras }
2722fe8fb19SBen Gras
2732fe8fb19SBen Gras static bool_t
svc_dg_freeargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)274f14fb602SLionel Sambuc svc_dg_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
2752fe8fb19SBen Gras {
2762fe8fb19SBen Gras XDR *xdrs;
2772fe8fb19SBen Gras
2782fe8fb19SBen Gras _DIAGASSERT(xprt != NULL);
2792fe8fb19SBen Gras
2802fe8fb19SBen Gras xdrs = &(su_data(xprt)->su_xdrs);
2812fe8fb19SBen Gras xdrs->x_op = XDR_FREE;
2822fe8fb19SBen Gras return (*xdr_args)(xdrs, args_ptr);
2832fe8fb19SBen Gras }
2842fe8fb19SBen Gras
2852fe8fb19SBen Gras static void
svc_dg_destroy(SVCXPRT * xprt)286f14fb602SLionel Sambuc svc_dg_destroy(SVCXPRT *xprt)
2872fe8fb19SBen Gras {
2882fe8fb19SBen Gras struct svc_dg_data *su;
2892fe8fb19SBen Gras
2902fe8fb19SBen Gras _DIAGASSERT(xprt != NULL);
2912fe8fb19SBen Gras
2922fe8fb19SBen Gras su = su_data(xprt);
2932fe8fb19SBen Gras
2942fe8fb19SBen Gras xprt_unregister(xprt);
2952fe8fb19SBen Gras if (xprt->xp_fd != -1)
2962fe8fb19SBen Gras (void)close(xprt->xp_fd);
2972fe8fb19SBen Gras XDR_DESTROY(&(su->su_xdrs));
2982fe8fb19SBen Gras (void) mem_free(rpc_buffer(xprt), su->su_iosz);
2992fe8fb19SBen Gras (void) mem_free(su, sizeof (*su));
3002fe8fb19SBen Gras if (xprt->xp_rtaddr.buf)
3012fe8fb19SBen Gras (void) mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
3022fe8fb19SBen Gras if (xprt->xp_ltaddr.buf)
3032fe8fb19SBen Gras (void) mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
3042fe8fb19SBen Gras if (xprt->xp_tp)
3052fe8fb19SBen Gras (void) free(xprt->xp_tp);
3062fe8fb19SBen Gras (void) mem_free(xprt, sizeof (SVCXPRT));
3072fe8fb19SBen Gras }
3082fe8fb19SBen Gras
3092fe8fb19SBen Gras static bool_t
3102fe8fb19SBen Gras /*ARGSUSED*/
svc_dg_control(SVCXPRT * xprt,const u_int rq,void * in)311f14fb602SLionel Sambuc svc_dg_control(SVCXPRT *xprt, const u_int rq, void *in)
3122fe8fb19SBen Gras {
3132fe8fb19SBen Gras return (FALSE);
3142fe8fb19SBen Gras }
3152fe8fb19SBen Gras
3162fe8fb19SBen Gras static void
svc_dg_ops(SVCXPRT * xprt)317f14fb602SLionel Sambuc svc_dg_ops(SVCXPRT *xprt)
3182fe8fb19SBen Gras {
3192fe8fb19SBen Gras static struct xp_ops ops;
3202fe8fb19SBen Gras static struct xp_ops2 ops2;
3212fe8fb19SBen Gras #ifdef _REENTRANT
3222fe8fb19SBen Gras extern mutex_t ops_lock;
3232fe8fb19SBen Gras #endif
3242fe8fb19SBen Gras
3252fe8fb19SBen Gras _DIAGASSERT(xprt != NULL);
3262fe8fb19SBen Gras
3272fe8fb19SBen Gras /* VARIABLES PROTECTED BY ops_lock: ops */
3282fe8fb19SBen Gras
3292fe8fb19SBen Gras mutex_lock(&ops_lock);
3302fe8fb19SBen Gras if (ops.xp_recv == NULL) {
3312fe8fb19SBen Gras ops.xp_recv = svc_dg_recv;
3322fe8fb19SBen Gras ops.xp_stat = svc_dg_stat;
3332fe8fb19SBen Gras ops.xp_getargs = svc_dg_getargs;
3342fe8fb19SBen Gras ops.xp_reply = svc_dg_reply;
3352fe8fb19SBen Gras ops.xp_freeargs = svc_dg_freeargs;
3362fe8fb19SBen Gras ops.xp_destroy = svc_dg_destroy;
3372fe8fb19SBen Gras ops2.xp_control = svc_dg_control;
3382fe8fb19SBen Gras }
3392fe8fb19SBen Gras xprt->xp_ops = &ops;
3402fe8fb19SBen Gras xprt->xp_ops2 = &ops2;
3412fe8fb19SBen Gras mutex_unlock(&ops_lock);
3422fe8fb19SBen Gras }
3432fe8fb19SBen Gras
3442fe8fb19SBen Gras /* The CACHING COMPONENT */
3452fe8fb19SBen Gras
3462fe8fb19SBen Gras /*
3472fe8fb19SBen Gras * Could have been a separate file, but some part of it depends upon the
3482fe8fb19SBen Gras * private structure of the client handle.
3492fe8fb19SBen Gras *
3502fe8fb19SBen Gras * Fifo cache for cl server
3512fe8fb19SBen Gras * Copies pointers to reply buffers into fifo cache
3522fe8fb19SBen Gras * Buffers are sent again if retransmissions are detected.
3532fe8fb19SBen Gras */
3542fe8fb19SBen Gras
3552fe8fb19SBen Gras #define SPARSENESS 4 /* 75% sparse */
3562fe8fb19SBen Gras
3572fe8fb19SBen Gras #define ALLOC(type, size) \
3582fe8fb19SBen Gras mem_alloc((sizeof (type) * (size)))
3592fe8fb19SBen Gras
3602fe8fb19SBen Gras #define MEMZERO(addr, type, size) \
3612fe8fb19SBen Gras (void) memset((void *) (addr), 0, sizeof (type) * (int) (size))
3622fe8fb19SBen Gras
3632fe8fb19SBen Gras #define FREE(addr, type, size) \
3642fe8fb19SBen Gras mem_free((addr), (sizeof (type) * (size)))
3652fe8fb19SBen Gras
3662fe8fb19SBen Gras /*
3672fe8fb19SBen Gras * An entry in the cache
3682fe8fb19SBen Gras */
3692fe8fb19SBen Gras typedef struct cache_node *cache_ptr;
3702fe8fb19SBen Gras struct cache_node {
3712fe8fb19SBen Gras /*
3722fe8fb19SBen Gras * Index into cache is xid, proc, vers, prog and address
3732fe8fb19SBen Gras */
3742fe8fb19SBen Gras u_int32_t cache_xid;
3752fe8fb19SBen Gras rpcproc_t cache_proc;
3762fe8fb19SBen Gras rpcvers_t cache_vers;
3772fe8fb19SBen Gras rpcprog_t cache_prog;
3782fe8fb19SBen Gras struct netbuf cache_addr;
3792fe8fb19SBen Gras /*
3802fe8fb19SBen Gras * The cached reply and length
3812fe8fb19SBen Gras */
3822fe8fb19SBen Gras char *cache_reply;
3832fe8fb19SBen Gras size_t cache_replylen;
3842fe8fb19SBen Gras /*
3852fe8fb19SBen Gras * Next node on the list, if there is a collision
3862fe8fb19SBen Gras */
3872fe8fb19SBen Gras cache_ptr cache_next;
3882fe8fb19SBen Gras };
3892fe8fb19SBen Gras
3902fe8fb19SBen Gras /*
3912fe8fb19SBen Gras * The entire cache
3922fe8fb19SBen Gras */
3932fe8fb19SBen Gras struct cl_cache {
3942fe8fb19SBen Gras u_int uc_size; /* size of cache */
3952fe8fb19SBen Gras cache_ptr *uc_entries; /* hash table of entries in cache */
3962fe8fb19SBen Gras cache_ptr *uc_fifo; /* fifo list of entries in cache */
3972fe8fb19SBen Gras u_int uc_nextvictim; /* points to next victim in fifo list */
3982fe8fb19SBen Gras rpcprog_t uc_prog; /* saved program number */
3992fe8fb19SBen Gras rpcvers_t uc_vers; /* saved version number */
4002fe8fb19SBen Gras rpcproc_t uc_proc; /* saved procedure number */
4012fe8fb19SBen Gras };
4022fe8fb19SBen Gras
4032fe8fb19SBen Gras
4042fe8fb19SBen Gras /*
4052fe8fb19SBen Gras * the hashing function
4062fe8fb19SBen Gras */
4072fe8fb19SBen Gras #define CACHE_LOC(transp, xid) \
4082fe8fb19SBen Gras (xid % (SPARSENESS * ((struct cl_cache *) \
4092fe8fb19SBen Gras su_data(transp)->su_cache)->uc_size))
4102fe8fb19SBen Gras
4112fe8fb19SBen Gras #ifdef _REENTRANT
4122fe8fb19SBen Gras extern mutex_t dupreq_lock;
4132fe8fb19SBen Gras #endif
4142fe8fb19SBen Gras
4152fe8fb19SBen Gras /*
4162fe8fb19SBen Gras * Enable use of the cache. Returns 1 on success, 0 on failure.
4172fe8fb19SBen Gras * Note: there is no disable.
4182fe8fb19SBen Gras */
4192fe8fb19SBen Gras static const char cache_enable_str[] = "svc_enablecache: %s %s";
4202fe8fb19SBen Gras static const char alloc_err[] = "could not allocate cache ";
4212fe8fb19SBen Gras static const char enable_err[] = "cache already enabled";
4222fe8fb19SBen Gras
4232fe8fb19SBen Gras int
svc_dg_enablecache(SVCXPRT * transp,u_int size)424f14fb602SLionel Sambuc svc_dg_enablecache(SVCXPRT *transp, u_int size)
4252fe8fb19SBen Gras {
4262fe8fb19SBen Gras struct svc_dg_data *su;
4272fe8fb19SBen Gras struct cl_cache *uc;
4282fe8fb19SBen Gras
4292fe8fb19SBen Gras _DIAGASSERT(transp != NULL);
4302fe8fb19SBen Gras
4312fe8fb19SBen Gras su = su_data(transp);
4322fe8fb19SBen Gras
4332fe8fb19SBen Gras mutex_lock(&dupreq_lock);
4342fe8fb19SBen Gras if (su->su_cache != NULL) {
4352fe8fb19SBen Gras (void) warnx(cache_enable_str, enable_err, " ");
4362fe8fb19SBen Gras mutex_unlock(&dupreq_lock);
4372fe8fb19SBen Gras return (0);
4382fe8fb19SBen Gras }
4392fe8fb19SBen Gras uc = ALLOC(struct cl_cache, 1);
4402fe8fb19SBen Gras if (uc == NULL) {
4412fe8fb19SBen Gras warnx(cache_enable_str, alloc_err, " ");
4422fe8fb19SBen Gras mutex_unlock(&dupreq_lock);
4432fe8fb19SBen Gras return (0);
4442fe8fb19SBen Gras }
4452fe8fb19SBen Gras uc->uc_size = size;
4462fe8fb19SBen Gras uc->uc_nextvictim = 0;
4472fe8fb19SBen Gras uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS);
4482fe8fb19SBen Gras if (uc->uc_entries == NULL) {
4492fe8fb19SBen Gras warnx(cache_enable_str, alloc_err, "data");
4502fe8fb19SBen Gras FREE(uc, struct cl_cache, 1);
4512fe8fb19SBen Gras mutex_unlock(&dupreq_lock);
4522fe8fb19SBen Gras return (0);
4532fe8fb19SBen Gras }
4542fe8fb19SBen Gras MEMZERO(uc->uc_entries, cache_ptr, size * SPARSENESS);
4552fe8fb19SBen Gras uc->uc_fifo = ALLOC(cache_ptr, size);
4562fe8fb19SBen Gras if (uc->uc_fifo == NULL) {
4572fe8fb19SBen Gras warnx(cache_enable_str, alloc_err, "fifo");
4582fe8fb19SBen Gras FREE(uc->uc_entries, cache_ptr, size * SPARSENESS);
4592fe8fb19SBen Gras FREE(uc, struct cl_cache, 1);
4602fe8fb19SBen Gras mutex_unlock(&dupreq_lock);
4612fe8fb19SBen Gras return (0);
4622fe8fb19SBen Gras }
4632fe8fb19SBen Gras MEMZERO(uc->uc_fifo, cache_ptr, size);
4642fe8fb19SBen Gras su->su_cache = (char *)(void *)uc;
4652fe8fb19SBen Gras mutex_unlock(&dupreq_lock);
4662fe8fb19SBen Gras return (1);
4672fe8fb19SBen Gras }
4682fe8fb19SBen Gras
4692fe8fb19SBen Gras /*
4702fe8fb19SBen Gras * Set an entry in the cache. It assumes that the uc entry is set from
4712fe8fb19SBen Gras * the earlier call to cache_get() for the same procedure. This will always
4722fe8fb19SBen Gras * happen because cache_get() is calle by svc_dg_recv and cache_set() is called
4732fe8fb19SBen Gras * by svc_dg_reply(). All this hoopla because the right RPC parameters are
4742fe8fb19SBen Gras * not available at svc_dg_reply time.
4752fe8fb19SBen Gras */
4762fe8fb19SBen Gras
4772fe8fb19SBen Gras static const char cache_set_str[] = "cache_set: %s";
4782fe8fb19SBen Gras static const char cache_set_err1[] = "victim not found";
4792fe8fb19SBen Gras static const char cache_set_err2[] = "victim alloc failed";
4802fe8fb19SBen Gras static const char cache_set_err3[] = "could not allocate new rpc buffer";
4812fe8fb19SBen Gras
4822fe8fb19SBen Gras static void
cache_set(SVCXPRT * xprt,size_t replylen)483f14fb602SLionel Sambuc cache_set(SVCXPRT *xprt, size_t replylen)
4842fe8fb19SBen Gras {
4852fe8fb19SBen Gras cache_ptr victim;
4862fe8fb19SBen Gras cache_ptr *vicp;
4872fe8fb19SBen Gras struct svc_dg_data *su;
4882fe8fb19SBen Gras struct cl_cache *uc;
4892fe8fb19SBen Gras u_int loc;
4902fe8fb19SBen Gras char *newbuf;
4912fe8fb19SBen Gras #ifdef RPC_CACHE_DEBUG
4922fe8fb19SBen Gras struct netconfig *nconf;
4932fe8fb19SBen Gras char *uaddr;
4942fe8fb19SBen Gras #endif
4952fe8fb19SBen Gras
4962fe8fb19SBen Gras _DIAGASSERT(xprt != NULL);
4972fe8fb19SBen Gras
4982fe8fb19SBen Gras su = su_data(xprt);
4992fe8fb19SBen Gras uc = (struct cl_cache *) su->su_cache;
5002fe8fb19SBen Gras
5012fe8fb19SBen Gras mutex_lock(&dupreq_lock);
5022fe8fb19SBen Gras /*
5032fe8fb19SBen Gras * Find space for the new entry, either by
5042fe8fb19SBen Gras * reusing an old entry, or by mallocing a new one
5052fe8fb19SBen Gras */
5062fe8fb19SBen Gras victim = uc->uc_fifo[uc->uc_nextvictim];
5072fe8fb19SBen Gras if (victim != NULL) {
5082fe8fb19SBen Gras loc = CACHE_LOC(xprt, victim->cache_xid);
5092fe8fb19SBen Gras for (vicp = &uc->uc_entries[loc];
5102fe8fb19SBen Gras *vicp != NULL && *vicp != victim;
5112fe8fb19SBen Gras vicp = &(*vicp)->cache_next)
5122fe8fb19SBen Gras ;
5132fe8fb19SBen Gras if (*vicp == NULL) {
5142fe8fb19SBen Gras warnx(cache_set_str, cache_set_err1);
5152fe8fb19SBen Gras mutex_unlock(&dupreq_lock);
5162fe8fb19SBen Gras return;
5172fe8fb19SBen Gras }
5182fe8fb19SBen Gras *vicp = victim->cache_next; /* remove from cache */
5192fe8fb19SBen Gras newbuf = victim->cache_reply;
5202fe8fb19SBen Gras } else {
5212fe8fb19SBen Gras victim = ALLOC(struct cache_node, 1);
5222fe8fb19SBen Gras if (victim == NULL) {
5232fe8fb19SBen Gras warnx(cache_set_str, cache_set_err2);
5242fe8fb19SBen Gras mutex_unlock(&dupreq_lock);
5252fe8fb19SBen Gras return;
5262fe8fb19SBen Gras }
5272fe8fb19SBen Gras newbuf = mem_alloc(su->su_iosz);
5282fe8fb19SBen Gras if (newbuf == NULL) {
5292fe8fb19SBen Gras warnx(cache_set_str, cache_set_err3);
5302fe8fb19SBen Gras FREE(victim, struct cache_node, 1);
5312fe8fb19SBen Gras mutex_unlock(&dupreq_lock);
5322fe8fb19SBen Gras return;
5332fe8fb19SBen Gras }
5342fe8fb19SBen Gras }
5352fe8fb19SBen Gras
5362fe8fb19SBen Gras /*
5372fe8fb19SBen Gras * Store it away
5382fe8fb19SBen Gras */
5392fe8fb19SBen Gras #ifdef RPC_CACHE_DEBUG
5402fe8fb19SBen Gras if (nconf = getnetconfigent(xprt->xp_netid)) {
5412fe8fb19SBen Gras uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr);
5422fe8fb19SBen Gras freenetconfigent(nconf);
5432fe8fb19SBen Gras printf(
5442fe8fb19SBen Gras "cache set for xid= %x prog=%d vers=%d proc=%d for rmtaddr=%s\n",
5452fe8fb19SBen Gras su->su_xid, uc->uc_prog, uc->uc_vers,
5462fe8fb19SBen Gras uc->uc_proc, uaddr);
5472fe8fb19SBen Gras free(uaddr);
5482fe8fb19SBen Gras }
5492fe8fb19SBen Gras #endif
5502fe8fb19SBen Gras victim->cache_replylen = replylen;
5512fe8fb19SBen Gras victim->cache_reply = rpc_buffer(xprt);
5522fe8fb19SBen Gras rpc_buffer(xprt) = newbuf;
553f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(u_int, su->su_iosz));
554f14fb602SLionel Sambuc xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), (u_int)su->su_iosz,
555f14fb602SLionel Sambuc XDR_ENCODE);
5562fe8fb19SBen Gras victim->cache_xid = su->su_xid;
5572fe8fb19SBen Gras victim->cache_proc = uc->uc_proc;
5582fe8fb19SBen Gras victim->cache_vers = uc->uc_vers;
5592fe8fb19SBen Gras victim->cache_prog = uc->uc_prog;
5602fe8fb19SBen Gras victim->cache_addr = xprt->xp_rtaddr;
5612fe8fb19SBen Gras victim->cache_addr.buf = ALLOC(char, xprt->xp_rtaddr.len);
5622fe8fb19SBen Gras (void) memcpy(victim->cache_addr.buf, xprt->xp_rtaddr.buf,
5632fe8fb19SBen Gras (size_t)xprt->xp_rtaddr.len);
5642fe8fb19SBen Gras loc = CACHE_LOC(xprt, victim->cache_xid);
5652fe8fb19SBen Gras victim->cache_next = uc->uc_entries[loc];
5662fe8fb19SBen Gras uc->uc_entries[loc] = victim;
5672fe8fb19SBen Gras uc->uc_fifo[uc->uc_nextvictim++] = victim;
5682fe8fb19SBen Gras uc->uc_nextvictim %= uc->uc_size;
5692fe8fb19SBen Gras mutex_unlock(&dupreq_lock);
5702fe8fb19SBen Gras }
5712fe8fb19SBen Gras
5722fe8fb19SBen Gras /*
5732fe8fb19SBen Gras * Try to get an entry from the cache
5742fe8fb19SBen Gras * return 1 if found, 0 if not found and set the stage for cache_set()
5752fe8fb19SBen Gras */
5762fe8fb19SBen Gras static int
cache_get(SVCXPRT * xprt,struct rpc_msg * msg,char ** replyp,size_t * replylenp)577f14fb602SLionel Sambuc cache_get(SVCXPRT *xprt, struct rpc_msg *msg, char **replyp, size_t *replylenp)
5782fe8fb19SBen Gras {
5792fe8fb19SBen Gras u_int loc;
5802fe8fb19SBen Gras cache_ptr ent;
5812fe8fb19SBen Gras struct svc_dg_data *su;
5822fe8fb19SBen Gras struct cl_cache *uc;
5832fe8fb19SBen Gras #ifdef RPC_CACHE_DEBUG
5842fe8fb19SBen Gras struct netconfig *nconf;
5852fe8fb19SBen Gras char *uaddr;
5862fe8fb19SBen Gras #endif
5872fe8fb19SBen Gras
5882fe8fb19SBen Gras _DIAGASSERT(xprt != NULL);
5892fe8fb19SBen Gras _DIAGASSERT(msg != NULL);
5902fe8fb19SBen Gras _DIAGASSERT(replyp != NULL);
5912fe8fb19SBen Gras _DIAGASSERT(replylenp != NULL);
5922fe8fb19SBen Gras
5932fe8fb19SBen Gras su = su_data(xprt);
5942fe8fb19SBen Gras uc = (struct cl_cache *) su->su_cache;
5952fe8fb19SBen Gras
5962fe8fb19SBen Gras mutex_lock(&dupreq_lock);
5972fe8fb19SBen Gras loc = CACHE_LOC(xprt, su->su_xid);
5982fe8fb19SBen Gras for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) {
5992fe8fb19SBen Gras if (ent->cache_xid == su->su_xid &&
6002fe8fb19SBen Gras ent->cache_proc == msg->rm_call.cb_proc &&
6012fe8fb19SBen Gras ent->cache_vers == msg->rm_call.cb_vers &&
6022fe8fb19SBen Gras ent->cache_prog == msg->rm_call.cb_prog &&
6032fe8fb19SBen Gras ent->cache_addr.len == xprt->xp_rtaddr.len &&
6042fe8fb19SBen Gras (memcmp(ent->cache_addr.buf, xprt->xp_rtaddr.buf,
6052fe8fb19SBen Gras xprt->xp_rtaddr.len) == 0)) {
6062fe8fb19SBen Gras #ifdef RPC_CACHE_DEBUG
6072fe8fb19SBen Gras if (nconf = getnetconfigent(xprt->xp_netid)) {
6082fe8fb19SBen Gras uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr);
6092fe8fb19SBen Gras freenetconfigent(nconf);
6102fe8fb19SBen Gras printf(
6112fe8fb19SBen Gras "cache entry found for xid=%x prog=%d vers=%d proc=%d for rmtaddr=%s\n",
6122fe8fb19SBen Gras su->su_xid, msg->rm_call.cb_prog,
6132fe8fb19SBen Gras msg->rm_call.cb_vers,
6142fe8fb19SBen Gras msg->rm_call.cb_proc, uaddr);
6152fe8fb19SBen Gras free(uaddr);
6162fe8fb19SBen Gras }
6172fe8fb19SBen Gras #endif
6182fe8fb19SBen Gras *replyp = ent->cache_reply;
6192fe8fb19SBen Gras *replylenp = ent->cache_replylen;
6202fe8fb19SBen Gras mutex_unlock(&dupreq_lock);
6212fe8fb19SBen Gras return (1);
6222fe8fb19SBen Gras }
6232fe8fb19SBen Gras }
6242fe8fb19SBen Gras /*
6252fe8fb19SBen Gras * Failed to find entry
6262fe8fb19SBen Gras * Remember a few things so we can do a set later
6272fe8fb19SBen Gras */
6282fe8fb19SBen Gras uc->uc_proc = msg->rm_call.cb_proc;
6292fe8fb19SBen Gras uc->uc_vers = msg->rm_call.cb_vers;
6302fe8fb19SBen Gras uc->uc_prog = msg->rm_call.cb_prog;
6312fe8fb19SBen Gras mutex_unlock(&dupreq_lock);
6322fe8fb19SBen Gras return (0);
6332fe8fb19SBen Gras }
634