xref: /minix3/lib/libc/rpc/svc_dg.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
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