]> git.ipfire.org Git - thirdparty/glibc.git/blame - sunrpc/svc_udp.c
Fix typos.
[thirdparty/glibc.git] / sunrpc / svc_udp.c
CommitLineData
28f540f4
RM
1/*
2 * svc_udp.c,
3 * Server side for UDP/IP based RPC. (Does some caching in the hopes of
4 * achieving execute-at-most-once semantics.)
5 *
568035b7 6 * Copyright (C) 2012-2013 Free Software Foundation, Inc.
14bc93a9
JL
7 * This file is part of the GNU C Library.
8 *
9 * The GNU C Library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * The GNU C Library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with the GNU C Library; if not, see
21 * <http://www.gnu.org/licenses/>.
22 *
a7ab6ec8
UD
23 * Copyright (c) 2010, Oracle America, Inc.
24 *
25 * Redistribution and use in source and binary forms, with or without
26 * modification, are permitted provided that the following conditions are
27 * met:
28 *
29 * * Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * * Redistributions in binary form must reproduce the above
32 * copyright notice, this list of conditions and the following
33 * disclaimer in the documentation and/or other materials
34 * provided with the distribution.
35 * * Neither the name of the "Oracle America, Inc." nor the names of its
36 * contributors may be used to endorse or promote products derived
37 * from this software without specific prior written permission.
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
40 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
41 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
42 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
43 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
44 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
46 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
47 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
48 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
49 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28f540f4
RM
51 */
52
53#include <stdio.h>
e7fd8a39
UD
54#include <unistd.h>
55#include <string.h>
28f540f4
RM
56#include <rpc/rpc.h>
57#include <sys/socket.h>
58#include <errno.h>
4360eafd 59#include <libintl.h>
28f540f4 60
3fd759d1
UD
61#ifdef IP_PKTINFO
62#include <sys/uio.h>
63#endif
64
3ce1f295
UD
65#include <wchar.h>
66#include <libio/iolibio.h>
28f540f4
RM
67
68#define rpc_buffer(xprt) ((xprt)->xp_p1)
1f64ac13 69#ifndef MAX
e7fd8a39 70#define MAX(a, b) ((a > b) ? a : b)
1f64ac13 71#endif
28f540f4 72
e7fd8a39
UD
73static bool_t svcudp_recv (SVCXPRT *, struct rpc_msg *);
74static bool_t svcudp_reply (SVCXPRT *, struct rpc_msg *);
75static enum xprt_stat svcudp_stat (SVCXPRT *);
76static bool_t svcudp_getargs (SVCXPRT *, xdrproc_t, caddr_t);
77static bool_t svcudp_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
78static void svcudp_destroy (SVCXPRT *);
79
80static const struct xp_ops svcudp_op =
81{
82 svcudp_recv,
83 svcudp_stat,
84 svcudp_getargs,
85 svcudp_reply,
86 svcudp_freeargs,
87 svcudp_destroy
28f540f4
RM
88};
89
e7fd8a39
UD
90static int cache_get (SVCXPRT *, struct rpc_msg *, char **replyp,
91 u_long *replylenp);
92static void cache_set (SVCXPRT *xprt, u_long replylen);
28f540f4
RM
93
94/*
95 * kept in xprt->xp_p2
96 */
e7fd8a39
UD
97struct svcudp_data
98 {
99 u_int su_iosz; /* byte size of send.recv buffer */
100 u_long su_xid; /* transaction id */
101 XDR su_xdrs; /* XDR handle */
102 char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */
103 char *su_cache; /* cached data, NULL if no cache */
104 };
28f540f4
RM
105#define su_data(xprt) ((struct svcudp_data *)(xprt->xp_p2))
106
107/*
108 * Usage:
e7fd8a39 109 * xprt = svcudp_create(sock);
28f540f4
RM
110 *
111 * If sock<0 then a socket is created, else sock is used.
112 * If the socket, sock is not bound to a port then svcudp_create
113 * binds it to an arbitrary port. In any (successful) case,
114 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
115 * associated port number.
116 * Once *xprt is initialized, it is registered as a transporter;
117 * see (svc.h, xprt_register).
118 * The routines returns NULL if a problem occurred.
119 */
120SVCXPRT *
e7fd8a39
UD
121svcudp_bufcreate (sock, sendsz, recvsz)
122 int sock;
123 u_int sendsz, recvsz;
28f540f4 124{
e7fd8a39
UD
125 bool_t madesock = FALSE;
126 SVCXPRT *xprt;
127 struct svcudp_data *su;
128 struct sockaddr_in addr;
70b0abba 129 socklen_t len = sizeof (struct sockaddr_in);
51028f34
UD
130 int pad;
131 void *buf;
e7fd8a39
UD
132
133 if (sock == RPC_ANYSOCK)
134 {
50304ef0 135 if ((sock = __socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
e7fd8a39
UD
136 {
137 perror (_("svcudp_create: socket creation problem"));
138 return (SVCXPRT *) NULL;
28f540f4 139 }
e7fd8a39
UD
140 madesock = TRUE;
141 }
50304ef0 142 __bzero ((char *) &addr, sizeof (addr));
e7fd8a39 143 addr.sin_family = AF_INET;
a585ba22 144 if (bindresvport (sock, &addr))
e7fd8a39
UD
145 {
146 addr.sin_port = 0;
b2bffca2 147 (void) __bind (sock, (struct sockaddr *) &addr, len);
e7fd8a39 148 }
b2bffca2 149 if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0)
e7fd8a39
UD
150 {
151 perror (_("svcudp_create - cannot getsockname"));
152 if (madesock)
50304ef0 153 (void) __close (sock);
e7fd8a39
UD
154 return (SVCXPRT *) NULL;
155 }
156 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
e7fd8a39 157 su = (struct svcudp_data *) mem_alloc (sizeof (*su));
51028f34
UD
158 buf = mem_alloc (((MAX (sendsz, recvsz) + 3) / 4) * 4);
159 if (xprt == NULL || su == NULL || buf == NULL)
e7fd8a39 160 {
1d20f7f8
UD
161 (void) __fxprintf (NULL, "%s: %s",
162 "svcudp_create", _("out of memory\n"));
2e3e5db6
UD
163 mem_free (xprt, sizeof (SVCXPRT));
164 mem_free (su, sizeof (*su));
165 mem_free (buf, ((MAX (sendsz, recvsz) + 3) / 4) * 4);
e7fd8a39
UD
166 return NULL;
167 }
168 su->su_iosz = ((MAX (sendsz, recvsz) + 3) / 4) * 4;
51028f34 169 rpc_buffer (xprt) = buf;
7b57bfe5 170 xdrmem_create (&(su->su_xdrs), rpc_buffer (xprt), su->su_iosz, XDR_DECODE);
e7fd8a39
UD
171 su->su_cache = NULL;
172 xprt->xp_p2 = (caddr_t) su;
173 xprt->xp_verf.oa_base = su->su_verfbody;
174 xprt->xp_ops = &svcudp_op;
175 xprt->xp_port = ntohs (addr.sin_port);
176 xprt->xp_sock = sock;
3fd759d1
UD
177
178#ifdef IP_PKTINFO
179 if ((sizeof (struct iovec) + sizeof (struct msghdr)
180 + sizeof(struct cmsghdr) + sizeof (struct in_pktinfo))
181 > sizeof (xprt->xp_pad))
182 {
8a259a23 183 (void) __fxprintf (NULL,"%s", _("\
df6f8969 184svcudp_create: xp_pad is too small for IP_PKTINFO\n"));
3fd759d1
UD
185 return NULL;
186 }
187 pad = 1;
b2bffca2
UD
188 if (__setsockopt (sock, SOL_IP, IP_PKTINFO, (void *) &pad,
189 sizeof (pad)) == 0)
3fd759d1
UD
190 /* Set the padding to all 1s. */
191 pad = 0xff;
192 else
193#endif
194 /* Clear the padding. */
195 pad = 0;
196 memset (&xprt->xp_pad [0], pad, sizeof (xprt->xp_pad));
197
e7fd8a39
UD
198 xprt_register (xprt);
199 return xprt;
28f540f4 200}
7b57bfe5
UD
201#ifdef EXPORT_RPC_SYMBOLS
202libc_hidden_def (svcudp_bufcreate)
203#else
021db4be 204libc_hidden_nolink_sunrpc (svcudp_bufcreate, GLIBC_2_0)
7b57bfe5 205#endif
28f540f4
RM
206
207SVCXPRT *
e7fd8a39
UD
208svcudp_create (sock)
209 int sock;
28f540f4 210{
7b57bfe5 211 return svcudp_bufcreate (sock, UDPMSGSIZE, UDPMSGSIZE);
28f540f4 212}
4df46dbd
L
213#ifdef EXPORT_RPC_SYMBOLS
214libc_hidden_def (svcudp_create)
215#else
021db4be 216libc_hidden_nolink_sunrpc (svcudp_create, GLIBC_2_0)
4df46dbd 217#endif
28f540f4
RM
218
219static enum xprt_stat
e7fd8a39
UD
220svcudp_stat (xprt)
221 SVCXPRT *xprt;
28f540f4
RM
222{
223
e7fd8a39 224 return XPRT_IDLE;
28f540f4
RM
225}
226
227static bool_t
e7fd8a39
UD
228svcudp_recv (xprt, msg)
229 SVCXPRT *xprt;
230 struct rpc_msg *msg;
28f540f4 231{
e7fd8a39
UD
232 struct svcudp_data *su = su_data (xprt);
233 XDR *xdrs = &(su->su_xdrs);
234 int rlen;
235 char *reply;
236 u_long replylen;
70b0abba 237 socklen_t len;
e7fd8a39 238
3fd759d1
UD
239 /* It is very tricky when you have IP aliases. We want to make sure
240 that we are sending the packet from the IP address where the
241 incoming packet is addressed to. H.J. */
242#ifdef IP_PKTINFO
243 struct iovec *iovp;
244 struct msghdr *mesgp;
245#endif
246
e7fd8a39 247again:
f671aeab 248 /* FIXME -- should xp_addrlen be a size_t? */
70b0abba 249 len = (socklen_t) sizeof(struct sockaddr_in);
3fd759d1
UD
250#ifdef IP_PKTINFO
251 iovp = (struct iovec *) &xprt->xp_pad [0];
252 mesgp = (struct msghdr *) &xprt->xp_pad [sizeof (struct iovec)];
253 if (mesgp->msg_iovlen)
254 {
255 iovp->iov_base = rpc_buffer (xprt);
256 iovp->iov_len = su->su_iosz;
257 mesgp->msg_iov = iovp;
258 mesgp->msg_iovlen = 1;
259 mesgp->msg_name = &(xprt->xp_raddr);
260 mesgp->msg_namelen = len;
261 mesgp->msg_control = &xprt->xp_pad [sizeof (struct iovec)
262 + sizeof (struct msghdr)];
172b90bb
UD
263 mesgp->msg_controllen = sizeof(xprt->xp_pad)
264 - sizeof (struct iovec) - sizeof (struct msghdr);
b2bffca2 265 rlen = __recvmsg (xprt->xp_sock, mesgp, 0);
3fd759d1 266 if (rlen >= 0)
d148ed25
UD
267 {
268 struct cmsghdr *cmsg;
269 len = mesgp->msg_namelen;
270 cmsg = CMSG_FIRSTHDR (mesgp);
271 if (cmsg == NULL
272 || CMSG_NXTHDR (mesgp, cmsg) != NULL
273 || cmsg->cmsg_level != SOL_IP
274 || cmsg->cmsg_type != IP_PKTINFO
275 || cmsg->cmsg_len < (sizeof (struct cmsghdr)
276 + sizeof (struct in_pktinfo)))
277 {
278 /* Not a simple IP_PKTINFO, ignore it. */
279 mesgp->msg_control = NULL;
280 mesgp->msg_controllen = 0;
281 }
282 else
283 {
284 /* It was a simple IP_PKTIFO as we expected, discard the
285 interface field. */
63c9fb5c 286 struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
d148ed25
UD
287 pkti->ipi_ifindex = 0;
288 }
289 }
3fd759d1
UD
290 }
291 else
292#endif
b2bffca2
UD
293 rlen = __recvfrom (xprt->xp_sock, rpc_buffer (xprt),
294 (int) su->su_iosz, 0,
295 (struct sockaddr *) &(xprt->xp_raddr), &len);
f671aeab 296 xprt->xp_addrlen = len;
14bc93a9
JL
297 if (rlen == -1)
298 {
299 if (errno == EINTR)
300 goto again;
301 __svc_accept_failed ();
302 }
e7fd8a39
UD
303 if (rlen < 16) /* < 4 32-bit ints? */
304 return FALSE;
305 xdrs->x_op = XDR_DECODE;
306 XDR_SETPOS (xdrs, 0);
7b57bfe5 307 if (!xdr_callmsg (xdrs, msg))
e7fd8a39
UD
308 return FALSE;
309 su->su_xid = msg->rm_xid;
310 if (su->su_cache != NULL)
311 {
312 if (cache_get (xprt, msg, &reply, &replylen))
313 {
3fd759d1
UD
314#ifdef IP_PKTINFO
315 if (mesgp->msg_iovlen)
316 {
317 iovp->iov_base = reply;
318 iovp->iov_len = replylen;
b2bffca2 319 (void) __sendmsg (xprt->xp_sock, mesgp, 0);
3fd759d1
UD
320 }
321 else
322#endif
b2bffca2
UD
323 (void) __sendto (xprt->xp_sock, reply, (int) replylen, 0,
324 (struct sockaddr *) &xprt->xp_raddr, len);
e7fd8a39 325 return TRUE;
28f540f4 326 }
e7fd8a39
UD
327 }
328 return TRUE;
28f540f4
RM
329}
330
331static bool_t
e7fd8a39
UD
332svcudp_reply (xprt, msg)
333 SVCXPRT *xprt;
334 struct rpc_msg *msg;
28f540f4 335{
e7fd8a39
UD
336 struct svcudp_data *su = su_data (xprt);
337 XDR *xdrs = &(su->su_xdrs);
3fd759d1 338 int slen, sent;
e7fd8a39 339 bool_t stat = FALSE;
3fd759d1
UD
340#ifdef IP_PKTINFO
341 struct iovec *iovp;
342 struct msghdr *mesgp;
343#endif
e7fd8a39
UD
344
345 xdrs->x_op = XDR_ENCODE;
346 XDR_SETPOS (xdrs, 0);
347 msg->rm_xid = su->su_xid;
7b57bfe5 348 if (xdr_replymsg (xdrs, msg))
e7fd8a39
UD
349 {
350 slen = (int) XDR_GETPOS (xdrs);
3fd759d1
UD
351#ifdef IP_PKTINFO
352 mesgp = (struct msghdr *) &xprt->xp_pad [sizeof (struct iovec)];
353 if (mesgp->msg_iovlen)
354 {
355 iovp = (struct iovec *) &xprt->xp_pad [0];
356 iovp->iov_base = rpc_buffer (xprt);
357 iovp->iov_len = slen;
b2bffca2 358 sent = __sendmsg (xprt->xp_sock, mesgp, 0);
3fd759d1
UD
359 }
360 else
361#endif
b2bffca2
UD
362 sent = __sendto (xprt->xp_sock, rpc_buffer (xprt), slen, 0,
363 (struct sockaddr *) &(xprt->xp_raddr),
364 xprt->xp_addrlen);
3fd759d1 365 if (sent == slen)
e7fd8a39
UD
366 {
367 stat = TRUE;
368 if (su->su_cache && slen >= 0)
369 {
370 cache_set (xprt, (u_long) slen);
371 }
28f540f4 372 }
e7fd8a39
UD
373 }
374 return stat;
28f540f4
RM
375}
376
377static bool_t
e7fd8a39
UD
378svcudp_getargs (xprt, xdr_args, args_ptr)
379 SVCXPRT *xprt;
380 xdrproc_t xdr_args;
381 caddr_t args_ptr;
28f540f4
RM
382{
383
e7fd8a39 384 return (*xdr_args) (&(su_data (xprt)->su_xdrs), args_ptr);
28f540f4
RM
385}
386
387static bool_t
e7fd8a39
UD
388svcudp_freeargs (xprt, xdr_args, args_ptr)
389 SVCXPRT *xprt;
390 xdrproc_t xdr_args;
391 caddr_t args_ptr;
28f540f4 392{
e7fd8a39 393 XDR *xdrs = &(su_data (xprt)->su_xdrs);
28f540f4 394
e7fd8a39
UD
395 xdrs->x_op = XDR_FREE;
396 return (*xdr_args) (xdrs, args_ptr);
28f540f4
RM
397}
398
399static void
e7fd8a39
UD
400svcudp_destroy (xprt)
401 SVCXPRT *xprt;
28f540f4 402{
e7fd8a39
UD
403 struct svcudp_data *su = su_data (xprt);
404
405 xprt_unregister (xprt);
50304ef0 406 (void) __close (xprt->xp_sock);
e7fd8a39
UD
407 XDR_DESTROY (&(su->su_xdrs));
408 mem_free (rpc_buffer (xprt), su->su_iosz);
409 mem_free ((caddr_t) su, sizeof (struct svcudp_data));
410 mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
28f540f4
RM
411}
412
413
414/***********this could be a separate file*********************/
415
416/*
417 * Fifo cache for udp server
418 * Copies pointers to reply buffers into fifo cache
419 * Buffers are sent again if retransmissions are detected.
420 */
421
e7fd8a39 422#define SPARSENESS 4 /* 75% sparse */
28f540f4 423
df6f8969 424#define CACHE_PERROR(msg) \
8a259a23 425 (void) __fxprintf(NULL, "%s\n", msg)
28f540f4
RM
426
427#define ALLOC(type, size) \
428 (type *) mem_alloc((unsigned) (sizeof(type) * (size)))
429
cdb9c321
UD
430#define CALLOC(type, size) \
431 (type *) calloc (sizeof (type), size)
28f540f4
RM
432
433/*
434 * An entry in the cache
435 */
436typedef struct cache_node *cache_ptr;
e7fd8a39
UD
437struct cache_node
438 {
439 /*
440 * Index into cache is xid, proc, vers, prog and address
441 */
442 u_long cache_xid;
443 u_long cache_proc;
444 u_long cache_vers;
445 u_long cache_prog;
446 struct sockaddr_in cache_addr;
447 /*
448 * The cached reply and length
449 */
450 char *cache_reply;
451 u_long cache_replylen;
452 /*
453 * Next node on the list, if there is a collision
454 */
455 cache_ptr cache_next;
456 };
28f540f4
RM
457
458
459
460/*
461 * The entire cache
462 */
e7fd8a39
UD
463struct udp_cache
464 {
465 u_long uc_size; /* size of cache */
466 cache_ptr *uc_entries; /* hash table of entries in cache */
467 cache_ptr *uc_fifo; /* fifo list of entries in cache */
468 u_long uc_nextvictim; /* points to next victim in fifo list */
469 u_long uc_prog; /* saved program number */
470 u_long uc_vers; /* saved version number */
471 u_long uc_proc; /* saved procedure number */
472 struct sockaddr_in uc_addr; /* saved caller's address */
473 };
28f540f4
RM
474
475
476/*
477 * the hashing function
478 */
479#define CACHE_LOC(transp, xid) \
cbd3dceb 480 (xid % (SPARSENESS*((struct udp_cache *) su_data(transp)->su_cache)->uc_size))
28f540f4
RM
481
482
483/*
cbd3dceb 484 * Enable use of the cache.
28f540f4
RM
485 * Note: there is no disable.
486 */
e7fd8a39
UD
487int
488svcudp_enablecache (SVCXPRT *transp, u_long size)
28f540f4 489{
e7fd8a39
UD
490 struct svcudp_data *su = su_data (transp);
491 struct udp_cache *uc;
492
493 if (su->su_cache != NULL)
494 {
495 CACHE_PERROR (_("enablecache: cache already enabled"));
496 return 0;
497 }
498 uc = ALLOC (struct udp_cache, 1);
499 if (uc == NULL)
500 {
501 CACHE_PERROR (_("enablecache: could not allocate cache"));
502 return 0;
503 }
504 uc->uc_size = size;
505 uc->uc_nextvictim = 0;
cdb9c321 506 uc->uc_entries = CALLOC (cache_ptr, size * SPARSENESS);
e7fd8a39
UD
507 if (uc->uc_entries == NULL)
508 {
0292b0dd 509 mem_free (uc, sizeof (struct udp_cache));
e7fd8a39
UD
510 CACHE_PERROR (_("enablecache: could not allocate cache data"));
511 return 0;
512 }
cdb9c321 513 uc->uc_fifo = CALLOC (cache_ptr, size);
e7fd8a39
UD
514 if (uc->uc_fifo == NULL)
515 {
0292b0dd
UD
516 mem_free (uc->uc_entries, size * SPARSENESS);
517 mem_free (uc, sizeof (struct udp_cache));
e7fd8a39
UD
518 CACHE_PERROR (_("enablecache: could not allocate cache fifo"));
519 return 0;
520 }
e7fd8a39
UD
521 su->su_cache = (char *) uc;
522 return 1;
28f540f4 523}
021db4be 524libc_hidden_nolink_sunrpc (svcudp_enablecache, GLIBC_2_0)
28f540f4
RM
525
526
527/*
528 * Set an entry in the cache
529 */
e7fd8a39
UD
530static void
531cache_set (SVCXPRT *xprt, u_long replylen)
28f540f4 532{
e7fd8a39
UD
533 cache_ptr victim;
534 cache_ptr *vicp;
535 struct svcudp_data *su = su_data (xprt);
536 struct udp_cache *uc = (struct udp_cache *) su->su_cache;
537 u_int loc;
538 char *newbuf;
539
540 /*
541 * Find space for the new entry, either by
542 * reusing an old entry, or by mallocing a new one
543 */
544 victim = uc->uc_fifo[uc->uc_nextvictim];
545 if (victim != NULL)
546 {
547 loc = CACHE_LOC (xprt, victim->cache_xid);
548 for (vicp = &uc->uc_entries[loc];
549 *vicp != NULL && *vicp != victim;
550 vicp = &(*vicp)->cache_next)
551 ;
552 if (*vicp == NULL)
553 {
554 CACHE_PERROR (_("cache_set: victim not found"));
555 return;
28f540f4 556 }
e7fd8a39
UD
557 *vicp = victim->cache_next; /* remote from cache */
558 newbuf = victim->cache_reply;
559 }
560 else
561 {
562 victim = ALLOC (struct cache_node, 1);
563 if (victim == NULL)
564 {
565 CACHE_PERROR (_("cache_set: victim alloc failed"));
566 return;
567 }
568 newbuf = mem_alloc (su->su_iosz);
569 if (newbuf == NULL)
570 {
0292b0dd 571 mem_free (victim, sizeof (struct cache_node));
e7fd8a39
UD
572 CACHE_PERROR (_("cache_set: could not allocate new rpc_buffer"));
573 return;
574 }
575 }
576
577 /*
578 * Store it away
579 */
580 victim->cache_replylen = replylen;
581 victim->cache_reply = rpc_buffer (xprt);
582 rpc_buffer (xprt) = newbuf;
7b57bfe5 583 xdrmem_create (&(su->su_xdrs), rpc_buffer (xprt), su->su_iosz, XDR_ENCODE);
e7fd8a39
UD
584 victim->cache_xid = su->su_xid;
585 victim->cache_proc = uc->uc_proc;
586 victim->cache_vers = uc->uc_vers;
587 victim->cache_prog = uc->uc_prog;
588 victim->cache_addr = uc->uc_addr;
589 loc = CACHE_LOC (xprt, victim->cache_xid);
590 victim->cache_next = uc->uc_entries[loc];
591 uc->uc_entries[loc] = victim;
592 uc->uc_fifo[uc->uc_nextvictim++] = victim;
593 uc->uc_nextvictim %= uc->uc_size;
28f540f4
RM
594}
595
596/*
597 * Try to get an entry from the cache
598 * return 1 if found, 0 if not found
599 */
e7fd8a39
UD
600static int
601cache_get (xprt, msg, replyp, replylenp)
602 SVCXPRT *xprt;
603 struct rpc_msg *msg;
604 char **replyp;
605 u_long *replylenp;
28f540f4 606{
e7fd8a39
UD
607 u_int loc;
608 cache_ptr ent;
609 struct svcudp_data *su = su_data (xprt);
610 struct udp_cache *uc = (struct udp_cache *) su->su_cache;
611
50304ef0 612#define EQADDR(a1, a2) (memcmp((char*)&a1, (char*)&a2, sizeof(a1)) == 0)
e7fd8a39
UD
613
614 loc = CACHE_LOC (xprt, su->su_xid);
615 for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next)
616 {
617 if (ent->cache_xid == su->su_xid &&
618 ent->cache_proc == uc->uc_proc &&
619 ent->cache_vers == uc->uc_vers &&
620 ent->cache_prog == uc->uc_prog &&
621 EQADDR (ent->cache_addr, uc->uc_addr))
622 {
623 *replyp = ent->cache_reply;
624 *replylenp = ent->cache_replylen;
625 return 1;
28f540f4 626 }
e7fd8a39
UD
627 }
628 /*
629 * Failed to find entry
630 * Remember a few things so we can do a set later
631 */
632 uc->uc_proc = msg->rm_call.cb_proc;
633 uc->uc_vers = msg->rm_call.cb_vers;
634 uc->uc_prog = msg->rm_call.cb_prog;
c1301d9a 635 memcpy (&uc->uc_addr, &xprt->xp_raddr, sizeof (uc->uc_addr));
e7fd8a39 636 return 0;
28f540f4 637}