1*45094Smckusick /* @(#)svc_udp.c 2.2 88/07/29 4.0 RPCSRC */ 2*45094Smckusick /* 3*45094Smckusick * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 4*45094Smckusick * unrestricted use provided that this legend is included on all tape 5*45094Smckusick * media and as a part of the software program in whole or part. Users 6*45094Smckusick * may copy or modify Sun RPC without charge, but are not authorized 7*45094Smckusick * to license or distribute it to anyone else except as part of a product or 8*45094Smckusick * program developed by the user. 9*45094Smckusick * 10*45094Smckusick * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 11*45094Smckusick * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 12*45094Smckusick * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 13*45094Smckusick * 14*45094Smckusick * Sun RPC is provided with no support and without any obligation on the 15*45094Smckusick * part of Sun Microsystems, Inc. to assist in its use, correction, 16*45094Smckusick * modification or enhancement. 17*45094Smckusick * 18*45094Smckusick * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 19*45094Smckusick * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 20*45094Smckusick * OR ANY PART THEREOF. 21*45094Smckusick * 22*45094Smckusick * In no event will Sun Microsystems, Inc. be liable for any lost revenue 23*45094Smckusick * or profits or other special, indirect and consequential damages, even if 24*45094Smckusick * Sun has been advised of the possibility of such damages. 25*45094Smckusick * 26*45094Smckusick * Sun Microsystems, Inc. 27*45094Smckusick * 2550 Garcia Avenue 28*45094Smckusick * Mountain View, California 94043 29*45094Smckusick */ 30*45094Smckusick #if !defined(lint) && defined(SCCSIDS) 31*45094Smckusick static char sccsid[] = "@(#)svc_udp.c 1.24 87/08/11 Copyr 1984 Sun Micro"; 32*45094Smckusick #endif 33*45094Smckusick 34*45094Smckusick /* 35*45094Smckusick * svc_udp.c, 36*45094Smckusick * Server side for UDP/IP based RPC. (Does some caching in the hopes of 37*45094Smckusick * achieving execute-at-most-once semantics.) 38*45094Smckusick * 39*45094Smckusick * Copyright (C) 1984, Sun Microsystems, Inc. 40*45094Smckusick */ 41*45094Smckusick 42*45094Smckusick #include <stdio.h> 43*45094Smckusick #include <rpc/rpc.h> 44*45094Smckusick #include <sys/socket.h> 45*45094Smckusick #include <errno.h> 46*45094Smckusick 47*45094Smckusick 48*45094Smckusick #define rpc_buffer(xprt) ((xprt)->xp_p1) 49*45094Smckusick #define MAX(a, b) ((a > b) ? a : b) 50*45094Smckusick 51*45094Smckusick static bool_t svcudp_recv(); 52*45094Smckusick static bool_t svcudp_reply(); 53*45094Smckusick static enum xprt_stat svcudp_stat(); 54*45094Smckusick static bool_t svcudp_getargs(); 55*45094Smckusick static bool_t svcudp_freeargs(); 56*45094Smckusick static void svcudp_destroy(); 57*45094Smckusick 58*45094Smckusick static struct xp_ops svcudp_op = { 59*45094Smckusick svcudp_recv, 60*45094Smckusick svcudp_stat, 61*45094Smckusick svcudp_getargs, 62*45094Smckusick svcudp_reply, 63*45094Smckusick svcudp_freeargs, 64*45094Smckusick svcudp_destroy 65*45094Smckusick }; 66*45094Smckusick 67*45094Smckusick extern int errno; 68*45094Smckusick 69*45094Smckusick /* 70*45094Smckusick * kept in xprt->xp_p2 71*45094Smckusick */ 72*45094Smckusick struct svcudp_data { 73*45094Smckusick u_int su_iosz; /* byte size of send.recv buffer */ 74*45094Smckusick u_long su_xid; /* transaction id */ 75*45094Smckusick XDR su_xdrs; /* XDR handle */ 76*45094Smckusick char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */ 77*45094Smckusick char * su_cache; /* cached data, NULL if no cache */ 78*45094Smckusick }; 79*45094Smckusick #define su_data(xprt) ((struct svcudp_data *)(xprt->xp_p2)) 80*45094Smckusick 81*45094Smckusick /* 82*45094Smckusick * Usage: 83*45094Smckusick * xprt = svcudp_create(sock); 84*45094Smckusick * 85*45094Smckusick * If sock<0 then a socket is created, else sock is used. 86*45094Smckusick * If the socket, sock is not bound to a port then svcudp_create 87*45094Smckusick * binds it to an arbitrary port. In any (successful) case, 88*45094Smckusick * xprt->xp_sock is the registered socket number and xprt->xp_port is the 89*45094Smckusick * associated port number. 90*45094Smckusick * Once *xprt is initialized, it is registered as a transporter; 91*45094Smckusick * see (svc.h, xprt_register). 92*45094Smckusick * The routines returns NULL if a problem occurred. 93*45094Smckusick */ 94*45094Smckusick SVCXPRT * 95*45094Smckusick svcudp_bufcreate(sock, sendsz, recvsz) 96*45094Smckusick register int sock; 97*45094Smckusick u_int sendsz, recvsz; 98*45094Smckusick { 99*45094Smckusick bool_t madesock = FALSE; 100*45094Smckusick register SVCXPRT *xprt; 101*45094Smckusick register struct svcudp_data *su; 102*45094Smckusick struct sockaddr_in addr; 103*45094Smckusick int len = sizeof(struct sockaddr_in); 104*45094Smckusick 105*45094Smckusick if (sock == RPC_ANYSOCK) { 106*45094Smckusick if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 107*45094Smckusick perror("svcudp_create: socket creation problem"); 108*45094Smckusick return ((SVCXPRT *)NULL); 109*45094Smckusick } 110*45094Smckusick madesock = TRUE; 111*45094Smckusick } 112*45094Smckusick bzero((char *)&addr, sizeof (addr)); 113*45094Smckusick addr.sin_family = AF_INET; 114*45094Smckusick if (bindresvport(sock, &addr)) { 115*45094Smckusick addr.sin_port = 0; 116*45094Smckusick (void)bind(sock, (struct sockaddr *)&addr, len); 117*45094Smckusick } 118*45094Smckusick if (getsockname(sock, (struct sockaddr *)&addr, &len) != 0) { 119*45094Smckusick perror("svcudp_create - cannot getsockname"); 120*45094Smckusick if (madesock) 121*45094Smckusick (void)close(sock); 122*45094Smckusick return ((SVCXPRT *)NULL); 123*45094Smckusick } 124*45094Smckusick xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); 125*45094Smckusick if (xprt == NULL) { 126*45094Smckusick (void)fprintf(stderr, "svcudp_create: out of memory\n"); 127*45094Smckusick return (NULL); 128*45094Smckusick } 129*45094Smckusick su = (struct svcudp_data *)mem_alloc(sizeof(*su)); 130*45094Smckusick if (su == NULL) { 131*45094Smckusick (void)fprintf(stderr, "svcudp_create: out of memory\n"); 132*45094Smckusick return (NULL); 133*45094Smckusick } 134*45094Smckusick su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4; 135*45094Smckusick if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) { 136*45094Smckusick (void)fprintf(stderr, "svcudp_create: out of memory\n"); 137*45094Smckusick return (NULL); 138*45094Smckusick } 139*45094Smckusick xdrmem_create( 140*45094Smckusick &(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE); 141*45094Smckusick su->su_cache = NULL; 142*45094Smckusick xprt->xp_p2 = (caddr_t)su; 143*45094Smckusick xprt->xp_verf.oa_base = su->su_verfbody; 144*45094Smckusick xprt->xp_ops = &svcudp_op; 145*45094Smckusick xprt->xp_port = ntohs(addr.sin_port); 146*45094Smckusick xprt->xp_sock = sock; 147*45094Smckusick xprt_register(xprt); 148*45094Smckusick return (xprt); 149*45094Smckusick } 150*45094Smckusick 151*45094Smckusick SVCXPRT * 152*45094Smckusick svcudp_create(sock) 153*45094Smckusick int sock; 154*45094Smckusick { 155*45094Smckusick 156*45094Smckusick return(svcudp_bufcreate(sock, UDPMSGSIZE, UDPMSGSIZE)); 157*45094Smckusick } 158*45094Smckusick 159*45094Smckusick static enum xprt_stat 160*45094Smckusick svcudp_stat(xprt) 161*45094Smckusick SVCXPRT *xprt; 162*45094Smckusick { 163*45094Smckusick 164*45094Smckusick return (XPRT_IDLE); 165*45094Smckusick } 166*45094Smckusick 167*45094Smckusick static bool_t 168*45094Smckusick svcudp_recv(xprt, msg) 169*45094Smckusick register SVCXPRT *xprt; 170*45094Smckusick struct rpc_msg *msg; 171*45094Smckusick { 172*45094Smckusick register struct svcudp_data *su = su_data(xprt); 173*45094Smckusick register XDR *xdrs = &(su->su_xdrs); 174*45094Smckusick register int rlen; 175*45094Smckusick char *reply; 176*45094Smckusick u_long replylen; 177*45094Smckusick 178*45094Smckusick again: 179*45094Smckusick xprt->xp_addrlen = sizeof(struct sockaddr_in); 180*45094Smckusick rlen = recvfrom(xprt->xp_sock, rpc_buffer(xprt), (int) su->su_iosz, 181*45094Smckusick 0, (struct sockaddr *)&(xprt->xp_raddr), &(xprt->xp_addrlen)); 182*45094Smckusick if (rlen == -1 && errno == EINTR) 183*45094Smckusick goto again; 184*45094Smckusick if (rlen < 4*sizeof(u_long)) 185*45094Smckusick return (FALSE); 186*45094Smckusick xdrs->x_op = XDR_DECODE; 187*45094Smckusick XDR_SETPOS(xdrs, 0); 188*45094Smckusick if (! xdr_callmsg(xdrs, msg)) 189*45094Smckusick return (FALSE); 190*45094Smckusick su->su_xid = msg->rm_xid; 191*45094Smckusick if (su->su_cache != NULL) { 192*45094Smckusick if (cache_get(xprt, msg, &reply, &replylen)) { 193*45094Smckusick (void) sendto(xprt->xp_sock, reply, (int) replylen, 0, 194*45094Smckusick (struct sockaddr *) &xprt->xp_raddr, xprt->xp_addrlen); 195*45094Smckusick return (TRUE); 196*45094Smckusick } 197*45094Smckusick } 198*45094Smckusick return (TRUE); 199*45094Smckusick } 200*45094Smckusick 201*45094Smckusick static bool_t 202*45094Smckusick svcudp_reply(xprt, msg) 203*45094Smckusick register SVCXPRT *xprt; 204*45094Smckusick struct rpc_msg *msg; 205*45094Smckusick { 206*45094Smckusick register struct svcudp_data *su = su_data(xprt); 207*45094Smckusick register XDR *xdrs = &(su->su_xdrs); 208*45094Smckusick register int slen; 209*45094Smckusick register bool_t stat = FALSE; 210*45094Smckusick 211*45094Smckusick xdrs->x_op = XDR_ENCODE; 212*45094Smckusick XDR_SETPOS(xdrs, 0); 213*45094Smckusick msg->rm_xid = su->su_xid; 214*45094Smckusick if (xdr_replymsg(xdrs, msg)) { 215*45094Smckusick slen = (int)XDR_GETPOS(xdrs); 216*45094Smckusick if (sendto(xprt->xp_sock, rpc_buffer(xprt), slen, 0, 217*45094Smckusick (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen) 218*45094Smckusick == slen) { 219*45094Smckusick stat = TRUE; 220*45094Smckusick if (su->su_cache && slen >= 0) { 221*45094Smckusick cache_set(xprt, (u_long) slen); 222*45094Smckusick } 223*45094Smckusick } 224*45094Smckusick } 225*45094Smckusick return (stat); 226*45094Smckusick } 227*45094Smckusick 228*45094Smckusick static bool_t 229*45094Smckusick svcudp_getargs(xprt, xdr_args, args_ptr) 230*45094Smckusick SVCXPRT *xprt; 231*45094Smckusick xdrproc_t xdr_args; 232*45094Smckusick caddr_t args_ptr; 233*45094Smckusick { 234*45094Smckusick 235*45094Smckusick return ((*xdr_args)(&(su_data(xprt)->su_xdrs), args_ptr)); 236*45094Smckusick } 237*45094Smckusick 238*45094Smckusick static bool_t 239*45094Smckusick svcudp_freeargs(xprt, xdr_args, args_ptr) 240*45094Smckusick SVCXPRT *xprt; 241*45094Smckusick xdrproc_t xdr_args; 242*45094Smckusick caddr_t args_ptr; 243*45094Smckusick { 244*45094Smckusick register XDR *xdrs = &(su_data(xprt)->su_xdrs); 245*45094Smckusick 246*45094Smckusick xdrs->x_op = XDR_FREE; 247*45094Smckusick return ((*xdr_args)(xdrs, args_ptr)); 248*45094Smckusick } 249*45094Smckusick 250*45094Smckusick static void 251*45094Smckusick svcudp_destroy(xprt) 252*45094Smckusick register SVCXPRT *xprt; 253*45094Smckusick { 254*45094Smckusick register struct svcudp_data *su = su_data(xprt); 255*45094Smckusick 256*45094Smckusick xprt_unregister(xprt); 257*45094Smckusick (void)close(xprt->xp_sock); 258*45094Smckusick XDR_DESTROY(&(su->su_xdrs)); 259*45094Smckusick mem_free(rpc_buffer(xprt), su->su_iosz); 260*45094Smckusick mem_free((caddr_t)su, sizeof(struct svcudp_data)); 261*45094Smckusick mem_free((caddr_t)xprt, sizeof(SVCXPRT)); 262*45094Smckusick } 263*45094Smckusick 264*45094Smckusick 265*45094Smckusick /***********this could be a separate file*********************/ 266*45094Smckusick 267*45094Smckusick /* 268*45094Smckusick * Fifo cache for udp server 269*45094Smckusick * Copies pointers to reply buffers into fifo cache 270*45094Smckusick * Buffers are sent again if retransmissions are detected. 271*45094Smckusick */ 272*45094Smckusick 273*45094Smckusick #define SPARSENESS 4 /* 75% sparse */ 274*45094Smckusick 275*45094Smckusick #define CACHE_PERROR(msg) \ 276*45094Smckusick (void) fprintf(stderr,"%s\n", msg) 277*45094Smckusick 278*45094Smckusick #define ALLOC(type, size) \ 279*45094Smckusick (type *) mem_alloc((unsigned) (sizeof(type) * (size))) 280*45094Smckusick 281*45094Smckusick #define BZERO(addr, type, size) \ 282*45094Smckusick bzero((char *) addr, sizeof(type) * (int) (size)) 283*45094Smckusick 284*45094Smckusick /* 285*45094Smckusick * An entry in the cache 286*45094Smckusick */ 287*45094Smckusick typedef struct cache_node *cache_ptr; 288*45094Smckusick struct cache_node { 289*45094Smckusick /* 290*45094Smckusick * Index into cache is xid, proc, vers, prog and address 291*45094Smckusick */ 292*45094Smckusick u_long cache_xid; 293*45094Smckusick u_long cache_proc; 294*45094Smckusick u_long cache_vers; 295*45094Smckusick u_long cache_prog; 296*45094Smckusick struct sockaddr_in cache_addr; 297*45094Smckusick /* 298*45094Smckusick * The cached reply and length 299*45094Smckusick */ 300*45094Smckusick char * cache_reply; 301*45094Smckusick u_long cache_replylen; 302*45094Smckusick /* 303*45094Smckusick * Next node on the list, if there is a collision 304*45094Smckusick */ 305*45094Smckusick cache_ptr cache_next; 306*45094Smckusick }; 307*45094Smckusick 308*45094Smckusick 309*45094Smckusick 310*45094Smckusick /* 311*45094Smckusick * The entire cache 312*45094Smckusick */ 313*45094Smckusick struct udp_cache { 314*45094Smckusick u_long uc_size; /* size of cache */ 315*45094Smckusick cache_ptr *uc_entries; /* hash table of entries in cache */ 316*45094Smckusick cache_ptr *uc_fifo; /* fifo list of entries in cache */ 317*45094Smckusick u_long uc_nextvictim; /* points to next victim in fifo list */ 318*45094Smckusick u_long uc_prog; /* saved program number */ 319*45094Smckusick u_long uc_vers; /* saved version number */ 320*45094Smckusick u_long uc_proc; /* saved procedure number */ 321*45094Smckusick struct sockaddr_in uc_addr; /* saved caller's address */ 322*45094Smckusick }; 323*45094Smckusick 324*45094Smckusick 325*45094Smckusick /* 326*45094Smckusick * the hashing function 327*45094Smckusick */ 328*45094Smckusick #define CACHE_LOC(transp, xid) \ 329*45094Smckusick (xid % (SPARSENESS*((struct udp_cache *) su_data(transp)->su_cache)->uc_size)) 330*45094Smckusick 331*45094Smckusick 332*45094Smckusick /* 333*45094Smckusick * Enable use of the cache. 334*45094Smckusick * Note: there is no disable. 335*45094Smckusick */ 336*45094Smckusick svcudp_enablecache(transp, size) 337*45094Smckusick SVCXPRT *transp; 338*45094Smckusick u_long size; 339*45094Smckusick { 340*45094Smckusick struct svcudp_data *su = su_data(transp); 341*45094Smckusick struct udp_cache *uc; 342*45094Smckusick 343*45094Smckusick if (su->su_cache != NULL) { 344*45094Smckusick CACHE_PERROR("enablecache: cache already enabled"); 345*45094Smckusick return(0); 346*45094Smckusick } 347*45094Smckusick uc = ALLOC(struct udp_cache, 1); 348*45094Smckusick if (uc == NULL) { 349*45094Smckusick CACHE_PERROR("enablecache: could not allocate cache"); 350*45094Smckusick return(0); 351*45094Smckusick } 352*45094Smckusick uc->uc_size = size; 353*45094Smckusick uc->uc_nextvictim = 0; 354*45094Smckusick uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS); 355*45094Smckusick if (uc->uc_entries == NULL) { 356*45094Smckusick CACHE_PERROR("enablecache: could not allocate cache data"); 357*45094Smckusick return(0); 358*45094Smckusick } 359*45094Smckusick BZERO(uc->uc_entries, cache_ptr, size * SPARSENESS); 360*45094Smckusick uc->uc_fifo = ALLOC(cache_ptr, size); 361*45094Smckusick if (uc->uc_fifo == NULL) { 362*45094Smckusick CACHE_PERROR("enablecache: could not allocate cache fifo"); 363*45094Smckusick return(0); 364*45094Smckusick } 365*45094Smckusick BZERO(uc->uc_fifo, cache_ptr, size); 366*45094Smckusick su->su_cache = (char *) uc; 367*45094Smckusick return(1); 368*45094Smckusick } 369*45094Smckusick 370*45094Smckusick 371*45094Smckusick /* 372*45094Smckusick * Set an entry in the cache 373*45094Smckusick */ 374*45094Smckusick static 375*45094Smckusick cache_set(xprt, replylen) 376*45094Smckusick SVCXPRT *xprt; 377*45094Smckusick u_long replylen; 378*45094Smckusick { 379*45094Smckusick register cache_ptr victim; 380*45094Smckusick register cache_ptr *vicp; 381*45094Smckusick register struct svcudp_data *su = su_data(xprt); 382*45094Smckusick struct udp_cache *uc = (struct udp_cache *) su->su_cache; 383*45094Smckusick u_int loc; 384*45094Smckusick char *newbuf; 385*45094Smckusick 386*45094Smckusick /* 387*45094Smckusick * Find space for the new entry, either by 388*45094Smckusick * reusing an old entry, or by mallocing a new one 389*45094Smckusick */ 390*45094Smckusick victim = uc->uc_fifo[uc->uc_nextvictim]; 391*45094Smckusick if (victim != NULL) { 392*45094Smckusick loc = CACHE_LOC(xprt, victim->cache_xid); 393*45094Smckusick for (vicp = &uc->uc_entries[loc]; 394*45094Smckusick *vicp != NULL && *vicp != victim; 395*45094Smckusick vicp = &(*vicp)->cache_next) 396*45094Smckusick ; 397*45094Smckusick if (*vicp == NULL) { 398*45094Smckusick CACHE_PERROR("cache_set: victim not found"); 399*45094Smckusick return; 400*45094Smckusick } 401*45094Smckusick *vicp = victim->cache_next; /* remote from cache */ 402*45094Smckusick newbuf = victim->cache_reply; 403*45094Smckusick } else { 404*45094Smckusick victim = ALLOC(struct cache_node, 1); 405*45094Smckusick if (victim == NULL) { 406*45094Smckusick CACHE_PERROR("cache_set: victim alloc failed"); 407*45094Smckusick return; 408*45094Smckusick } 409*45094Smckusick newbuf = mem_alloc(su->su_iosz); 410*45094Smckusick if (newbuf == NULL) { 411*45094Smckusick CACHE_PERROR("cache_set: could not allocate new rpc_buffer"); 412*45094Smckusick return; 413*45094Smckusick } 414*45094Smckusick } 415*45094Smckusick 416*45094Smckusick /* 417*45094Smckusick * Store it away 418*45094Smckusick */ 419*45094Smckusick victim->cache_replylen = replylen; 420*45094Smckusick victim->cache_reply = rpc_buffer(xprt); 421*45094Smckusick rpc_buffer(xprt) = newbuf; 422*45094Smckusick xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_ENCODE); 423*45094Smckusick victim->cache_xid = su->su_xid; 424*45094Smckusick victim->cache_proc = uc->uc_proc; 425*45094Smckusick victim->cache_vers = uc->uc_vers; 426*45094Smckusick victim->cache_prog = uc->uc_prog; 427*45094Smckusick victim->cache_addr = uc->uc_addr; 428*45094Smckusick loc = CACHE_LOC(xprt, victim->cache_xid); 429*45094Smckusick victim->cache_next = uc->uc_entries[loc]; 430*45094Smckusick uc->uc_entries[loc] = victim; 431*45094Smckusick uc->uc_fifo[uc->uc_nextvictim++] = victim; 432*45094Smckusick uc->uc_nextvictim %= uc->uc_size; 433*45094Smckusick } 434*45094Smckusick 435*45094Smckusick /* 436*45094Smckusick * Try to get an entry from the cache 437*45094Smckusick * return 1 if found, 0 if not found 438*45094Smckusick */ 439*45094Smckusick static 440*45094Smckusick cache_get(xprt, msg, replyp, replylenp) 441*45094Smckusick SVCXPRT *xprt; 442*45094Smckusick struct rpc_msg *msg; 443*45094Smckusick char **replyp; 444*45094Smckusick u_long *replylenp; 445*45094Smckusick { 446*45094Smckusick u_int loc; 447*45094Smckusick register cache_ptr ent; 448*45094Smckusick register struct svcudp_data *su = su_data(xprt); 449*45094Smckusick register struct udp_cache *uc = (struct udp_cache *) su->su_cache; 450*45094Smckusick 451*45094Smckusick # define EQADDR(a1, a2) (bcmp((char*)&a1, (char*)&a2, sizeof(a1)) == 0) 452*45094Smckusick 453*45094Smckusick loc = CACHE_LOC(xprt, su->su_xid); 454*45094Smckusick for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) { 455*45094Smckusick if (ent->cache_xid == su->su_xid && 456*45094Smckusick ent->cache_proc == uc->uc_proc && 457*45094Smckusick ent->cache_vers == uc->uc_vers && 458*45094Smckusick ent->cache_prog == uc->uc_prog && 459*45094Smckusick EQADDR(ent->cache_addr, uc->uc_addr)) { 460*45094Smckusick *replyp = ent->cache_reply; 461*45094Smckusick *replylenp = ent->cache_replylen; 462*45094Smckusick return(1); 463*45094Smckusick } 464*45094Smckusick } 465*45094Smckusick /* 466*45094Smckusick * Failed to find entry 467*45094Smckusick * Remember a few things so we can do a set later 468*45094Smckusick */ 469*45094Smckusick uc->uc_proc = msg->rm_call.cb_proc; 470*45094Smckusick uc->uc_vers = msg->rm_call.cb_vers; 471*45094Smckusick uc->uc_prog = msg->rm_call.cb_prog; 472*45094Smckusick uc->uc_addr = xprt->xp_raddr; 473*45094Smckusick return(0); 474*45094Smckusick } 475*45094Smckusick 476