1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate /* 31*7c478bd9Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 32*7c478bd9Sstevel@tonic-gate * The Regents of the University of California 33*7c478bd9Sstevel@tonic-gate * All Rights Reserved 34*7c478bd9Sstevel@tonic-gate * 35*7c478bd9Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 36*7c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 37*7c478bd9Sstevel@tonic-gate * contributors. 38*7c478bd9Sstevel@tonic-gate */ 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate /* 43*7c478bd9Sstevel@tonic-gate * svc_udp.c, 44*7c478bd9Sstevel@tonic-gate * Server side for UDP/IP based RPC. (Does some caching in the hopes of 45*7c478bd9Sstevel@tonic-gate * achieving execute-at-most-once semantics.) 46*7c478bd9Sstevel@tonic-gate */ 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 49*7c478bd9Sstevel@tonic-gate #include <rpc/clnt_soc.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 51*7c478bd9Sstevel@tonic-gate #include <errno.h> 52*7c478bd9Sstevel@tonic-gate #include <syslog.h> 53*7c478bd9Sstevel@tonic-gate #include <malloc.h> 54*7c478bd9Sstevel@tonic-gate #include <stdio.h> 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate #define rpc_buffer(xprt) ((xprt)->xp_p1) 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate static struct xp_ops *svcudp_ops(); 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate extern int errno; 62*7c478bd9Sstevel@tonic-gate extern SVCXPRT *svc_xprt_alloc(); 63*7c478bd9Sstevel@tonic-gate extern void svc_xprt_free(); 64*7c478bd9Sstevel@tonic-gate extern int _socket(int, int, int); 65*7c478bd9Sstevel@tonic-gate extern int _bind(int, const struct sockaddr *, int); 66*7c478bd9Sstevel@tonic-gate extern int _getsockname(int, struct sockaddr *, int *); 67*7c478bd9Sstevel@tonic-gate extern int _listen(int, int); 68*7c478bd9Sstevel@tonic-gate extern int _accept(int, struct sockaddr *, int *); 69*7c478bd9Sstevel@tonic-gate extern int bindresvport(int, struct sockaddr_in *); 70*7c478bd9Sstevel@tonic-gate extern int _recvfrom(int, char *, int, int, 71*7c478bd9Sstevel@tonic-gate struct sockaddr *, int *); 72*7c478bd9Sstevel@tonic-gate extern int _sendto(int, const char *, int, int, 73*7c478bd9Sstevel@tonic-gate const struct sockaddr *, int); 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate static int cache_get(SVCXPRT *, struct rpc_msg *, 76*7c478bd9Sstevel@tonic-gate char **, uint_t *); 77*7c478bd9Sstevel@tonic-gate static void cache_set(SVCXPRT *, uint_t); 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate /* 80*7c478bd9Sstevel@tonic-gate * kept in xprt->xp_p2 81*7c478bd9Sstevel@tonic-gate */ 82*7c478bd9Sstevel@tonic-gate struct svcudp_data { 83*7c478bd9Sstevel@tonic-gate u_int su_iosz; /* byte size of send.recv buffer */ 84*7c478bd9Sstevel@tonic-gate uint32_t su_xid; /* transaction id */ 85*7c478bd9Sstevel@tonic-gate XDR su_xdrs; /* XDR handle */ 86*7c478bd9Sstevel@tonic-gate char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */ 87*7c478bd9Sstevel@tonic-gate char * su_cache; /* cached data, NULL if no cache */ 88*7c478bd9Sstevel@tonic-gate }; 89*7c478bd9Sstevel@tonic-gate #define su_data(xprt) ((struct svcudp_data *)(xprt->xp_p2)) 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate /* 92*7c478bd9Sstevel@tonic-gate * Usage: 93*7c478bd9Sstevel@tonic-gate * xprt = svcudp_create(sock); 94*7c478bd9Sstevel@tonic-gate * 95*7c478bd9Sstevel@tonic-gate * If sock<0 then a socket is created, else sock is used. 96*7c478bd9Sstevel@tonic-gate * If the socket, sock is not bound to a port then svcudp_create 97*7c478bd9Sstevel@tonic-gate * binds it to an arbitrary port. In any (successful) case, 98*7c478bd9Sstevel@tonic-gate * xprt->xp_sock is the registered socket number and xprt->xp_port is the 99*7c478bd9Sstevel@tonic-gate * associated port number. 100*7c478bd9Sstevel@tonic-gate * Once *xprt is initialized, it is registered as a transporter; 101*7c478bd9Sstevel@tonic-gate * see (svc.h, xprt_register). 102*7c478bd9Sstevel@tonic-gate * The routines returns NULL if a problem occurred. 103*7c478bd9Sstevel@tonic-gate */ 104*7c478bd9Sstevel@tonic-gate SVCXPRT * 105*7c478bd9Sstevel@tonic-gate svcudp_bufcreate(sock, sendsz, recvsz) 106*7c478bd9Sstevel@tonic-gate register int sock; 107*7c478bd9Sstevel@tonic-gate u_int sendsz, recvsz; 108*7c478bd9Sstevel@tonic-gate { 109*7c478bd9Sstevel@tonic-gate bool_t madesock = FALSE; 110*7c478bd9Sstevel@tonic-gate register SVCXPRT *xprt; 111*7c478bd9Sstevel@tonic-gate register struct svcudp_data *su; 112*7c478bd9Sstevel@tonic-gate struct sockaddr_in addr; 113*7c478bd9Sstevel@tonic-gate int len = sizeof (struct sockaddr_in); 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate if (sock == RPC_ANYSOCK) { 116*7c478bd9Sstevel@tonic-gate if ((sock = _socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 117*7c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "svcudp_create: socket", 118*7c478bd9Sstevel@tonic-gate " creation problem: %m"); 119*7c478bd9Sstevel@tonic-gate return ((SVCXPRT *)NULL); 120*7c478bd9Sstevel@tonic-gate } 121*7c478bd9Sstevel@tonic-gate madesock = TRUE; 122*7c478bd9Sstevel@tonic-gate } 123*7c478bd9Sstevel@tonic-gate memset((char *)&addr, 0, sizeof (addr)); 124*7c478bd9Sstevel@tonic-gate addr.sin_family = AF_INET; 125*7c478bd9Sstevel@tonic-gate if (bindresvport(sock, &addr)) { 126*7c478bd9Sstevel@tonic-gate addr.sin_port = 0; 127*7c478bd9Sstevel@tonic-gate (void) _bind(sock, (struct sockaddr *)&addr, len); 128*7c478bd9Sstevel@tonic-gate } 129*7c478bd9Sstevel@tonic-gate if (_getsockname(sock, (struct sockaddr *)&addr, &len) != 0) { 130*7c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "svcudp_create -", 131*7c478bd9Sstevel@tonic-gate " cannot getsockname: %m"); 132*7c478bd9Sstevel@tonic-gate if (madesock) 133*7c478bd9Sstevel@tonic-gate (void) close(sock); 134*7c478bd9Sstevel@tonic-gate return ((SVCXPRT *)NULL); 135*7c478bd9Sstevel@tonic-gate } 136*7c478bd9Sstevel@tonic-gate xprt = svc_xprt_alloc(); 137*7c478bd9Sstevel@tonic-gate if (xprt == NULL) { 138*7c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "svcudp_create: out of memory"); 139*7c478bd9Sstevel@tonic-gate if (madesock) 140*7c478bd9Sstevel@tonic-gate (void) close(sock); 141*7c478bd9Sstevel@tonic-gate return ((SVCXPRT *)NULL); 142*7c478bd9Sstevel@tonic-gate } 143*7c478bd9Sstevel@tonic-gate su = (struct svcudp_data *)mem_alloc(sizeof (*su)); 144*7c478bd9Sstevel@tonic-gate if (su == NULL) { 145*7c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "svcudp_create: out of memory"); 146*7c478bd9Sstevel@tonic-gate svc_xprt_free(xprt); 147*7c478bd9Sstevel@tonic-gate if (madesock) 148*7c478bd9Sstevel@tonic-gate (void) close(sock); 149*7c478bd9Sstevel@tonic-gate return ((SVCXPRT *)NULL); 150*7c478bd9Sstevel@tonic-gate } 151*7c478bd9Sstevel@tonic-gate su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4; 152*7c478bd9Sstevel@tonic-gate if ((rpc_buffer(xprt) = (char *)mem_alloc(su->su_iosz)) == NULL) { 153*7c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "svcudp_create: out of memory"); 154*7c478bd9Sstevel@tonic-gate mem_free((char *) su, sizeof (*su)); 155*7c478bd9Sstevel@tonic-gate svc_xprt_free(xprt); 156*7c478bd9Sstevel@tonic-gate if (madesock) 157*7c478bd9Sstevel@tonic-gate (void) close(sock); 158*7c478bd9Sstevel@tonic-gate return ((SVCXPRT *)NULL); 159*7c478bd9Sstevel@tonic-gate } 160*7c478bd9Sstevel@tonic-gate xdrmem_create( 161*7c478bd9Sstevel@tonic-gate &(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE); 162*7c478bd9Sstevel@tonic-gate su->su_cache = NULL; 163*7c478bd9Sstevel@tonic-gate xprt->xp_p2 = (caddr_t)su; 164*7c478bd9Sstevel@tonic-gate xprt->xp_netid = NULL; 165*7c478bd9Sstevel@tonic-gate xprt->xp_verf.oa_base = su->su_verfbody; 166*7c478bd9Sstevel@tonic-gate xprt->xp_ops = svcudp_ops(); 167*7c478bd9Sstevel@tonic-gate xprt->xp_port = ntohs(addr.sin_port); 168*7c478bd9Sstevel@tonic-gate xprt->xp_sock = sock; 169*7c478bd9Sstevel@tonic-gate xprt->xp_rtaddr.buf = &xprt->xp_raddr[0]; 170*7c478bd9Sstevel@tonic-gate xprt_register(xprt); 171*7c478bd9Sstevel@tonic-gate return (xprt); 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate SVCXPRT * 175*7c478bd9Sstevel@tonic-gate svcudp_create(sock) 176*7c478bd9Sstevel@tonic-gate int sock; 177*7c478bd9Sstevel@tonic-gate { 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate return (svcudp_bufcreate(sock, UDPMSGSIZE, UDPMSGSIZE)); 180*7c478bd9Sstevel@tonic-gate } 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate static enum xprt_stat 183*7c478bd9Sstevel@tonic-gate svcudp_stat(xprt) 184*7c478bd9Sstevel@tonic-gate SVCXPRT *xprt; 185*7c478bd9Sstevel@tonic-gate { 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate return (XPRT_IDLE); 188*7c478bd9Sstevel@tonic-gate } 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate static bool_t 191*7c478bd9Sstevel@tonic-gate svcudp_recv(xprt, msg) 192*7c478bd9Sstevel@tonic-gate register SVCXPRT *xprt; 193*7c478bd9Sstevel@tonic-gate struct rpc_msg *msg; 194*7c478bd9Sstevel@tonic-gate { 195*7c478bd9Sstevel@tonic-gate register struct svcudp_data *su = su_data(xprt); 196*7c478bd9Sstevel@tonic-gate register XDR *xdrs = &(su->su_xdrs); 197*7c478bd9Sstevel@tonic-gate register int rlen; 198*7c478bd9Sstevel@tonic-gate char *reply; 199*7c478bd9Sstevel@tonic-gate uint_t replylen; 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate again: 202*7c478bd9Sstevel@tonic-gate xprt->xp_addrlen = sizeof (struct sockaddr_in); 203*7c478bd9Sstevel@tonic-gate rlen = _recvfrom(xprt->xp_sock, rpc_buffer(xprt), (int) su->su_iosz, 204*7c478bd9Sstevel@tonic-gate 0, (struct sockaddr *)&(xprt->xp_raddr), &(xprt->xp_addrlen)); 205*7c478bd9Sstevel@tonic-gate if (rlen == -1 && errno == EINTR) 206*7c478bd9Sstevel@tonic-gate goto again; 207*7c478bd9Sstevel@tonic-gate if (rlen < 4*sizeof (uint32_t)) 208*7c478bd9Sstevel@tonic-gate return (FALSE); 209*7c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_DECODE; 210*7c478bd9Sstevel@tonic-gate XDR_SETPOS(xdrs, 0); 211*7c478bd9Sstevel@tonic-gate if (! xdr_callmsg(xdrs, msg)) 212*7c478bd9Sstevel@tonic-gate return (FALSE); 213*7c478bd9Sstevel@tonic-gate su->su_xid = msg->rm_xid; 214*7c478bd9Sstevel@tonic-gate if (su->su_cache != NULL) { 215*7c478bd9Sstevel@tonic-gate if (cache_get(xprt, msg, &reply, &replylen)) { 216*7c478bd9Sstevel@tonic-gate (void) _sendto(xprt->xp_sock, reply, (int) replylen, 0, 217*7c478bd9Sstevel@tonic-gate (struct sockaddr *) &xprt->xp_raddr, 218*7c478bd9Sstevel@tonic-gate xprt->xp_addrlen); 219*7c478bd9Sstevel@tonic-gate return (TRUE); 220*7c478bd9Sstevel@tonic-gate } 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate return (TRUE); 223*7c478bd9Sstevel@tonic-gate } 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate static bool_t 226*7c478bd9Sstevel@tonic-gate svcudp_reply(xprt, msg) 227*7c478bd9Sstevel@tonic-gate register SVCXPRT *xprt; 228*7c478bd9Sstevel@tonic-gate struct rpc_msg *msg; 229*7c478bd9Sstevel@tonic-gate { 230*7c478bd9Sstevel@tonic-gate register struct svcudp_data *su = su_data(xprt); 231*7c478bd9Sstevel@tonic-gate register XDR *xdrs = &(su->su_xdrs); 232*7c478bd9Sstevel@tonic-gate register int slen; 233*7c478bd9Sstevel@tonic-gate register bool_t stat = FALSE; 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_ENCODE; 236*7c478bd9Sstevel@tonic-gate XDR_SETPOS(xdrs, 0); 237*7c478bd9Sstevel@tonic-gate msg->rm_xid = su->su_xid; 238*7c478bd9Sstevel@tonic-gate if (xdr_replymsg(xdrs, msg)) { 239*7c478bd9Sstevel@tonic-gate slen = (int)XDR_GETPOS(xdrs); 240*7c478bd9Sstevel@tonic-gate if (_sendto(xprt->xp_sock, rpc_buffer(xprt), slen, 0, 241*7c478bd9Sstevel@tonic-gate (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen) 242*7c478bd9Sstevel@tonic-gate == slen) { 243*7c478bd9Sstevel@tonic-gate stat = TRUE; 244*7c478bd9Sstevel@tonic-gate if (su->su_cache && slen >= 0) { 245*7c478bd9Sstevel@tonic-gate (void) cache_set(xprt, (uint_t) slen); 246*7c478bd9Sstevel@tonic-gate } 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate return (stat); 250*7c478bd9Sstevel@tonic-gate } 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate static bool_t 253*7c478bd9Sstevel@tonic-gate svcudp_getargs(xprt, xdr_args, args_ptr) 254*7c478bd9Sstevel@tonic-gate SVCXPRT *xprt; 255*7c478bd9Sstevel@tonic-gate xdrproc_t xdr_args; 256*7c478bd9Sstevel@tonic-gate caddr_t args_ptr; 257*7c478bd9Sstevel@tonic-gate { 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate return ((*xdr_args)(&(su_data(xprt)->su_xdrs), args_ptr)); 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate static bool_t 263*7c478bd9Sstevel@tonic-gate svcudp_freeargs(xprt, xdr_args, args_ptr) 264*7c478bd9Sstevel@tonic-gate SVCXPRT *xprt; 265*7c478bd9Sstevel@tonic-gate xdrproc_t xdr_args; 266*7c478bd9Sstevel@tonic-gate caddr_t args_ptr; 267*7c478bd9Sstevel@tonic-gate { 268*7c478bd9Sstevel@tonic-gate register XDR *xdrs = &(su_data(xprt)->su_xdrs); 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_FREE; 271*7c478bd9Sstevel@tonic-gate return ((*xdr_args)(xdrs, args_ptr)); 272*7c478bd9Sstevel@tonic-gate } 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate static void 275*7c478bd9Sstevel@tonic-gate svcudp_destroy(xprt) 276*7c478bd9Sstevel@tonic-gate register SVCXPRT *xprt; 277*7c478bd9Sstevel@tonic-gate { 278*7c478bd9Sstevel@tonic-gate register struct svcudp_data *su = su_data(xprt); 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate xprt_unregister(xprt); 281*7c478bd9Sstevel@tonic-gate (void) close(xprt->xp_sock); 282*7c478bd9Sstevel@tonic-gate XDR_DESTROY(&(su->su_xdrs)); 283*7c478bd9Sstevel@tonic-gate mem_free(rpc_buffer(xprt), su->su_iosz); 284*7c478bd9Sstevel@tonic-gate mem_free((caddr_t)su, sizeof (struct svcudp_data)); 285*7c478bd9Sstevel@tonic-gate svc_xprt_free(xprt); 286*7c478bd9Sstevel@tonic-gate } 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate /* **********this could be a separate file********************* */ 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate /* 292*7c478bd9Sstevel@tonic-gate * Fifo cache for udp server 293*7c478bd9Sstevel@tonic-gate * Copies pointers to reply buffers into fifo cache 294*7c478bd9Sstevel@tonic-gate * Buffers are sent again if retransmissions are detected. 295*7c478bd9Sstevel@tonic-gate */ 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate #define SPARSENESS 4 /* 75% sparse */ 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate #define ALLOC(type, size) \ 300*7c478bd9Sstevel@tonic-gate (type *) mem_alloc((unsigned) (sizeof (type) * (size))) 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate #define BZERO(addr, type, size) \ 303*7c478bd9Sstevel@tonic-gate memset((char *) (addr), 0, sizeof (type) * (int) (size)) 304*7c478bd9Sstevel@tonic-gate 305*7c478bd9Sstevel@tonic-gate #define FREE(addr, type, size) \ 306*7c478bd9Sstevel@tonic-gate (void) mem_free((char *) (addr), (sizeof (type) * (size))) 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate /* 309*7c478bd9Sstevel@tonic-gate * An entry in the cache 310*7c478bd9Sstevel@tonic-gate */ 311*7c478bd9Sstevel@tonic-gate typedef struct cache_node *cache_ptr; 312*7c478bd9Sstevel@tonic-gate struct cache_node { 313*7c478bd9Sstevel@tonic-gate /* 314*7c478bd9Sstevel@tonic-gate * Index into cache is xid, proc, vers, prog and address 315*7c478bd9Sstevel@tonic-gate */ 316*7c478bd9Sstevel@tonic-gate uint32_t cache_xid; 317*7c478bd9Sstevel@tonic-gate uint32_t cache_proc; 318*7c478bd9Sstevel@tonic-gate uint32_t cache_vers; 319*7c478bd9Sstevel@tonic-gate uint32_t cache_prog; 320*7c478bd9Sstevel@tonic-gate struct sockaddr_in cache_addr; 321*7c478bd9Sstevel@tonic-gate /* 322*7c478bd9Sstevel@tonic-gate * The cached reply and length 323*7c478bd9Sstevel@tonic-gate */ 324*7c478bd9Sstevel@tonic-gate char * cache_reply; 325*7c478bd9Sstevel@tonic-gate uint32_t cache_replylen; 326*7c478bd9Sstevel@tonic-gate /* 327*7c478bd9Sstevel@tonic-gate * Next node on the list, if there is a collision 328*7c478bd9Sstevel@tonic-gate */ 329*7c478bd9Sstevel@tonic-gate cache_ptr cache_next; 330*7c478bd9Sstevel@tonic-gate }; 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate /* 335*7c478bd9Sstevel@tonic-gate * The entire cache 336*7c478bd9Sstevel@tonic-gate */ 337*7c478bd9Sstevel@tonic-gate struct udp_cache { 338*7c478bd9Sstevel@tonic-gate uint32_t uc_size; /* size of cache */ 339*7c478bd9Sstevel@tonic-gate cache_ptr *uc_entries; /* hash table of entries in cache */ 340*7c478bd9Sstevel@tonic-gate cache_ptr *uc_fifo; /* fifo list of entries in cache */ 341*7c478bd9Sstevel@tonic-gate uint32_t uc_nextvictim; /* points to next victim in fifo list */ 342*7c478bd9Sstevel@tonic-gate uint32_t uc_prog; /* saved program number */ 343*7c478bd9Sstevel@tonic-gate uint32_t uc_vers; /* saved version number */ 344*7c478bd9Sstevel@tonic-gate uint32_t uc_proc; /* saved procedure number */ 345*7c478bd9Sstevel@tonic-gate struct sockaddr_in uc_addr; /* saved caller's address */ 346*7c478bd9Sstevel@tonic-gate }; 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate 349*7c478bd9Sstevel@tonic-gate /* 350*7c478bd9Sstevel@tonic-gate * the hashing function 351*7c478bd9Sstevel@tonic-gate */ 352*7c478bd9Sstevel@tonic-gate #define CACHE_LOC(transp, xid) \ 353*7c478bd9Sstevel@tonic-gate (xid % (SPARSENESS*((struct udp_cache *) \ 354*7c478bd9Sstevel@tonic-gate su_data(transp)->su_cache)->uc_size)) 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate 357*7c478bd9Sstevel@tonic-gate /* 358*7c478bd9Sstevel@tonic-gate * Enable use of the cache. 359*7c478bd9Sstevel@tonic-gate * Note: there is no disable. 360*7c478bd9Sstevel@tonic-gate */ 361*7c478bd9Sstevel@tonic-gate int 362*7c478bd9Sstevel@tonic-gate svcudp_enablecache(transp, size) 363*7c478bd9Sstevel@tonic-gate SVCXPRT *transp; 364*7c478bd9Sstevel@tonic-gate uint_t size; 365*7c478bd9Sstevel@tonic-gate { 366*7c478bd9Sstevel@tonic-gate struct svcudp_data *su = su_data(transp); 367*7c478bd9Sstevel@tonic-gate struct udp_cache *uc; 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate if (su->su_cache != NULL) { 370*7c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "enablecache: cache already enabled"); 371*7c478bd9Sstevel@tonic-gate return (0); 372*7c478bd9Sstevel@tonic-gate } 373*7c478bd9Sstevel@tonic-gate uc = ALLOC(struct udp_cache, 1); 374*7c478bd9Sstevel@tonic-gate if (uc == NULL) { 375*7c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "enablecache: could not allocate cache"); 376*7c478bd9Sstevel@tonic-gate return (0); 377*7c478bd9Sstevel@tonic-gate } 378*7c478bd9Sstevel@tonic-gate uc->uc_size = size; 379*7c478bd9Sstevel@tonic-gate uc->uc_nextvictim = 0; 380*7c478bd9Sstevel@tonic-gate uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS); 381*7c478bd9Sstevel@tonic-gate if (uc->uc_entries == NULL) { 382*7c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "enablecache: could not", 383*7c478bd9Sstevel@tonic-gate " allocate cache data"); 384*7c478bd9Sstevel@tonic-gate FREE(uc, struct udp_cache, 1); 385*7c478bd9Sstevel@tonic-gate return (0); 386*7c478bd9Sstevel@tonic-gate } 387*7c478bd9Sstevel@tonic-gate BZERO(uc->uc_entries, cache_ptr, size * SPARSENESS); 388*7c478bd9Sstevel@tonic-gate uc->uc_fifo = ALLOC(cache_ptr, size); 389*7c478bd9Sstevel@tonic-gate if (uc->uc_fifo == NULL) { 390*7c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "enablecache: could not", 391*7c478bd9Sstevel@tonic-gate " allocate cache fifo"); 392*7c478bd9Sstevel@tonic-gate FREE((char *)uc->uc_entries, cache_ptr, size * SPARSENESS); 393*7c478bd9Sstevel@tonic-gate FREE((char *)uc, struct udp_cache, 1); 394*7c478bd9Sstevel@tonic-gate return (0); 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate BZERO(uc->uc_fifo, cache_ptr, size); 397*7c478bd9Sstevel@tonic-gate su->su_cache = (char *) uc; 398*7c478bd9Sstevel@tonic-gate return (1); 399*7c478bd9Sstevel@tonic-gate } 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate /* 403*7c478bd9Sstevel@tonic-gate * Set an entry in the cache 404*7c478bd9Sstevel@tonic-gate */ 405*7c478bd9Sstevel@tonic-gate static void 406*7c478bd9Sstevel@tonic-gate cache_set(xprt, replylen) 407*7c478bd9Sstevel@tonic-gate SVCXPRT *xprt; 408*7c478bd9Sstevel@tonic-gate uint_t replylen; 409*7c478bd9Sstevel@tonic-gate { 410*7c478bd9Sstevel@tonic-gate register cache_ptr victim; 411*7c478bd9Sstevel@tonic-gate register cache_ptr *vicp; 412*7c478bd9Sstevel@tonic-gate register struct svcudp_data *su = su_data(xprt); 413*7c478bd9Sstevel@tonic-gate struct udp_cache *uc = (struct udp_cache *) su->su_cache; 414*7c478bd9Sstevel@tonic-gate u_int loc; 415*7c478bd9Sstevel@tonic-gate char *newbuf; 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate /* 418*7c478bd9Sstevel@tonic-gate * Find space for the new entry, either by 419*7c478bd9Sstevel@tonic-gate * reusing an old entry, or by mallocing a new one 420*7c478bd9Sstevel@tonic-gate */ 421*7c478bd9Sstevel@tonic-gate victim = uc->uc_fifo[uc->uc_nextvictim]; 422*7c478bd9Sstevel@tonic-gate if (victim != NULL) { 423*7c478bd9Sstevel@tonic-gate loc = CACHE_LOC(xprt, victim->cache_xid); 424*7c478bd9Sstevel@tonic-gate for (vicp = &uc->uc_entries[loc]; 425*7c478bd9Sstevel@tonic-gate *vicp != NULL && *vicp != victim; 426*7c478bd9Sstevel@tonic-gate vicp = &(*vicp)->cache_next) 427*7c478bd9Sstevel@tonic-gate ; 428*7c478bd9Sstevel@tonic-gate if (*vicp == NULL) { 429*7c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "cache_set: victim not found"); 430*7c478bd9Sstevel@tonic-gate return; 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate *vicp = victim->cache_next; /* remote from cache */ 433*7c478bd9Sstevel@tonic-gate newbuf = victim->cache_reply; 434*7c478bd9Sstevel@tonic-gate } else { 435*7c478bd9Sstevel@tonic-gate victim = ALLOC(struct cache_node, 1); 436*7c478bd9Sstevel@tonic-gate if (victim == NULL) { 437*7c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "cache_set: victim alloc", 438*7c478bd9Sstevel@tonic-gate " failed"); 439*7c478bd9Sstevel@tonic-gate return; 440*7c478bd9Sstevel@tonic-gate } 441*7c478bd9Sstevel@tonic-gate newbuf = (char *)mem_alloc(su->su_iosz); 442*7c478bd9Sstevel@tonic-gate if (newbuf == NULL) { 443*7c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "cache_set: could not", 444*7c478bd9Sstevel@tonic-gate " allocate new rpc_buffer"); 445*7c478bd9Sstevel@tonic-gate FREE(victim, struct cache_node, 1); 446*7c478bd9Sstevel@tonic-gate return; 447*7c478bd9Sstevel@tonic-gate } 448*7c478bd9Sstevel@tonic-gate } 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate /* 451*7c478bd9Sstevel@tonic-gate * Store it away 452*7c478bd9Sstevel@tonic-gate */ 453*7c478bd9Sstevel@tonic-gate victim->cache_replylen = replylen; 454*7c478bd9Sstevel@tonic-gate victim->cache_reply = rpc_buffer(xprt); 455*7c478bd9Sstevel@tonic-gate rpc_buffer(xprt) = newbuf; 456*7c478bd9Sstevel@tonic-gate xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), 457*7c478bd9Sstevel@tonic-gate su->su_iosz, XDR_ENCODE); 458*7c478bd9Sstevel@tonic-gate victim->cache_xid = su->su_xid; 459*7c478bd9Sstevel@tonic-gate victim->cache_proc = uc->uc_proc; 460*7c478bd9Sstevel@tonic-gate victim->cache_vers = uc->uc_vers; 461*7c478bd9Sstevel@tonic-gate victim->cache_prog = uc->uc_prog; 462*7c478bd9Sstevel@tonic-gate victim->cache_addr = uc->uc_addr; 463*7c478bd9Sstevel@tonic-gate loc = CACHE_LOC(xprt, victim->cache_xid); 464*7c478bd9Sstevel@tonic-gate victim->cache_next = uc->uc_entries[loc]; 465*7c478bd9Sstevel@tonic-gate uc->uc_entries[loc] = victim; 466*7c478bd9Sstevel@tonic-gate uc->uc_fifo[uc->uc_nextvictim++] = victim; 467*7c478bd9Sstevel@tonic-gate uc->uc_nextvictim %= uc->uc_size; 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate /* 471*7c478bd9Sstevel@tonic-gate * Try to get an entry from the cache 472*7c478bd9Sstevel@tonic-gate * return 1 if found, 0 if not found 473*7c478bd9Sstevel@tonic-gate */ 474*7c478bd9Sstevel@tonic-gate static int 475*7c478bd9Sstevel@tonic-gate cache_get(xprt, msg, replyp, replylenp) 476*7c478bd9Sstevel@tonic-gate SVCXPRT *xprt; 477*7c478bd9Sstevel@tonic-gate struct rpc_msg *msg; 478*7c478bd9Sstevel@tonic-gate char **replyp; 479*7c478bd9Sstevel@tonic-gate uint_t *replylenp; 480*7c478bd9Sstevel@tonic-gate { 481*7c478bd9Sstevel@tonic-gate u_int loc; 482*7c478bd9Sstevel@tonic-gate register cache_ptr ent; 483*7c478bd9Sstevel@tonic-gate register struct svcudp_data *su = su_data(xprt); 484*7c478bd9Sstevel@tonic-gate register struct udp_cache *uc = (struct udp_cache *) su->su_cache; 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate #define EQADDR(a1, a2) \ 487*7c478bd9Sstevel@tonic-gate (memcmp((char *)&a1, (char *)&a2, sizeof (a1)) == 0) 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate loc = CACHE_LOC(xprt, su->su_xid); 490*7c478bd9Sstevel@tonic-gate for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) { 491*7c478bd9Sstevel@tonic-gate if (ent->cache_xid == su->su_xid && 492*7c478bd9Sstevel@tonic-gate ent->cache_proc == uc->uc_proc && 493*7c478bd9Sstevel@tonic-gate ent->cache_vers == uc->uc_vers && 494*7c478bd9Sstevel@tonic-gate ent->cache_prog == uc->uc_prog && 495*7c478bd9Sstevel@tonic-gate EQADDR(ent->cache_addr, uc->uc_addr)) { 496*7c478bd9Sstevel@tonic-gate *replyp = ent->cache_reply; 497*7c478bd9Sstevel@tonic-gate *replylenp = ent->cache_replylen; 498*7c478bd9Sstevel@tonic-gate return (1); 499*7c478bd9Sstevel@tonic-gate } 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate /* 502*7c478bd9Sstevel@tonic-gate * Failed to find entry 503*7c478bd9Sstevel@tonic-gate * Remember a few things so we can do a set later 504*7c478bd9Sstevel@tonic-gate */ 505*7c478bd9Sstevel@tonic-gate uc->uc_proc = msg->rm_call.cb_proc; 506*7c478bd9Sstevel@tonic-gate uc->uc_vers = msg->rm_call.cb_vers; 507*7c478bd9Sstevel@tonic-gate uc->uc_prog = msg->rm_call.cb_prog; 508*7c478bd9Sstevel@tonic-gate memcpy((char *)&uc->uc_addr, (char *)&xprt->xp_raddr, 509*7c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in)); 510*7c478bd9Sstevel@tonic-gate return (0); 511*7c478bd9Sstevel@tonic-gate } 512*7c478bd9Sstevel@tonic-gate 513*7c478bd9Sstevel@tonic-gate static struct xp_ops * 514*7c478bd9Sstevel@tonic-gate svcudp_ops() 515*7c478bd9Sstevel@tonic-gate { 516*7c478bd9Sstevel@tonic-gate static struct xp_ops ops; 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate if (ops.xp_recv == NULL) { 519*7c478bd9Sstevel@tonic-gate ops.xp_recv = svcudp_recv; 520*7c478bd9Sstevel@tonic-gate ops.xp_stat = svcudp_stat; 521*7c478bd9Sstevel@tonic-gate ops.xp_getargs = svcudp_getargs; 522*7c478bd9Sstevel@tonic-gate ops.xp_reply = svcudp_reply; 523*7c478bd9Sstevel@tonic-gate ops.xp_freeargs = svcudp_freeargs; 524*7c478bd9Sstevel@tonic-gate ops.xp_destroy = svcudp_destroy; 525*7c478bd9Sstevel@tonic-gate } 526*7c478bd9Sstevel@tonic-gate return (&ops); 527*7c478bd9Sstevel@tonic-gate } 528