svc_udp.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  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. *
  6. * Copyright (C) 2012-2019 Free Software Foundation, Inc.
  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. *
  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.
  51. */
  52. #include <stdio.h>
  53. #include <unistd.h>
  54. #include <string.h>
  55. #include <rpc/rpc.h>
  56. #include <sys/socket.h>
  57. #include <errno.h>
  58. #include <libintl.h>
  59. #ifdef IP_PKTINFO
  60. #include <sys/uio.h>
  61. #endif
  62. #include <wchar.h>
  63. #include <libio/iolibio.h>
  64. #include <shlib-compat.h>
  65. #define rpc_buffer(xprt) ((xprt)->xp_p1)
  66. #ifndef MAX
  67. #define MAX(a, b) ((a > b) ? a : b)
  68. #endif
  69. static bool_t svcudp_recv (SVCXPRT *, struct rpc_msg *);
  70. static bool_t svcudp_reply (SVCXPRT *, struct rpc_msg *);
  71. static enum xprt_stat svcudp_stat (SVCXPRT *);
  72. static bool_t svcudp_getargs (SVCXPRT *, xdrproc_t, caddr_t);
  73. static bool_t svcudp_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
  74. static void svcudp_destroy (SVCXPRT *);
  75. static const struct xp_ops svcudp_op =
  76. {
  77. svcudp_recv,
  78. svcudp_stat,
  79. svcudp_getargs,
  80. svcudp_reply,
  81. svcudp_freeargs,
  82. svcudp_destroy
  83. };
  84. static int cache_get (SVCXPRT *, struct rpc_msg *, char **replyp,
  85. u_long *replylenp);
  86. static void cache_set (SVCXPRT *xprt, u_long replylen);
  87. /*
  88. * kept in xprt->xp_p2
  89. */
  90. struct svcudp_data
  91. {
  92. u_int su_iosz; /* byte size of send.recv buffer */
  93. u_long su_xid; /* transaction id */
  94. XDR su_xdrs; /* XDR handle */
  95. char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */
  96. char *su_cache; /* cached data, NULL if no cache */
  97. };
  98. #define su_data(xprt) ((struct svcudp_data *)(xprt->xp_p2))
  99. /*
  100. * Usage:
  101. * xprt = svcudp_create(sock);
  102. *
  103. * If sock<0 then a socket is created, else sock is used.
  104. * If the socket, sock is not bound to a port then svcudp_create
  105. * binds it to an arbitrary port. In any (successful) case,
  106. * xprt->xp_sock is the registered socket number and xprt->xp_port is the
  107. * associated port number.
  108. * Once *xprt is initialized, it is registered as a transporter;
  109. * see (svc.h, xprt_register).
  110. * The routines returns NULL if a problem occurred.
  111. */
  112. SVCXPRT *
  113. svcudp_bufcreate (int sock, u_int sendsz, u_int recvsz)
  114. {
  115. bool_t madesock = FALSE;
  116. SVCXPRT *xprt;
  117. struct svcudp_data *su;
  118. struct sockaddr_in addr;
  119. socklen_t len = sizeof (struct sockaddr_in);
  120. int pad;
  121. void *buf;
  122. if (sock == RPC_ANYSOCK)
  123. {
  124. if ((sock = __socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
  125. {
  126. perror (_("svcudp_create: socket creation problem"));
  127. return (SVCXPRT *) NULL;
  128. }
  129. madesock = TRUE;
  130. }
  131. memset ((char *) &addr, 0, sizeof (addr));
  132. addr.sin_family = AF_INET;
  133. if (bindresvport (sock, &addr))
  134. {
  135. addr.sin_port = 0;
  136. (void) __bind (sock, (struct sockaddr *) &addr, len);
  137. }
  138. if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0)
  139. {
  140. perror (_("svcudp_create - cannot getsockname"));
  141. if (madesock)
  142. (void) __close (sock);
  143. return (SVCXPRT *) NULL;
  144. }
  145. xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
  146. su = (struct svcudp_data *) mem_alloc (sizeof (*su));
  147. buf = mem_alloc (((MAX (sendsz, recvsz) + 3) / 4) * 4);
  148. if (xprt == NULL || su == NULL || buf == NULL)
  149. {
  150. (void) __fxprintf (NULL, "%s: %s",
  151. "svcudp_create", _("out of memory\n"));
  152. mem_free (xprt, sizeof (SVCXPRT));
  153. mem_free (su, sizeof (*su));
  154. mem_free (buf, ((MAX (sendsz, recvsz) + 3) / 4) * 4);
  155. return NULL;
  156. }
  157. su->su_iosz = ((MAX (sendsz, recvsz) + 3) / 4) * 4;
  158. rpc_buffer (xprt) = buf;
  159. xdrmem_create (&(su->su_xdrs), rpc_buffer (xprt), su->su_iosz, XDR_DECODE);
  160. su->su_cache = NULL;
  161. xprt->xp_p2 = (caddr_t) su;
  162. xprt->xp_verf.oa_base = su->su_verfbody;
  163. xprt->xp_ops = &svcudp_op;
  164. xprt->xp_port = ntohs (addr.sin_port);
  165. xprt->xp_sock = sock;
  166. #ifdef IP_PKTINFO
  167. if ((sizeof (struct iovec) + sizeof (struct msghdr)
  168. + sizeof(struct cmsghdr) + sizeof (struct in_pktinfo))
  169. > sizeof (xprt->xp_pad))
  170. {
  171. (void) __fxprintf (NULL,"%s", _("\
  172. svcudp_create: xp_pad is too small for IP_PKTINFO\n"));
  173. return NULL;
  174. }
  175. pad = 1;
  176. if (__setsockopt (sock, SOL_IP, IP_PKTINFO, (void *) &pad,
  177. sizeof (pad)) == 0)
  178. /* Set the padding to all 1s. */
  179. pad = 0xff;
  180. else
  181. #endif
  182. /* Clear the padding. */
  183. pad = 0;
  184. memset (&xprt->xp_pad [0], pad, sizeof (xprt->xp_pad));
  185. xprt_register (xprt);
  186. return xprt;
  187. }
  188. #ifdef EXPORT_RPC_SYMBOLS
  189. libc_hidden_def (svcudp_bufcreate)
  190. #else
  191. libc_hidden_nolink_sunrpc (svcudp_bufcreate, GLIBC_2_0)
  192. #endif
  193. SVCXPRT *
  194. svcudp_create (int sock)
  195. {
  196. return svcudp_bufcreate (sock, UDPMSGSIZE, UDPMSGSIZE);
  197. }
  198. #ifdef EXPORT_RPC_SYMBOLS
  199. libc_hidden_def (svcudp_create)
  200. #else
  201. libc_hidden_nolink_sunrpc (svcudp_create, GLIBC_2_0)
  202. #endif
  203. static enum xprt_stat
  204. svcudp_stat (SVCXPRT *xprt)
  205. {
  206. return XPRT_IDLE;
  207. }
  208. static bool_t
  209. svcudp_recv (SVCXPRT *xprt, struct rpc_msg *msg)
  210. {
  211. struct svcudp_data *su = su_data (xprt);
  212. XDR *xdrs = &(su->su_xdrs);
  213. int rlen;
  214. char *reply;
  215. u_long replylen;
  216. socklen_t len;
  217. /* It is very tricky when you have IP aliases. We want to make sure
  218. that we are sending the packet from the IP address where the
  219. incoming packet is addressed to. H.J. */
  220. #ifdef IP_PKTINFO
  221. struct iovec *iovp;
  222. struct msghdr *mesgp;
  223. #endif
  224. again:
  225. /* FIXME -- should xp_addrlen be a size_t? */
  226. len = (socklen_t) sizeof(struct sockaddr_in);
  227. #ifdef IP_PKTINFO
  228. iovp = (struct iovec *) &xprt->xp_pad [0];
  229. mesgp = (struct msghdr *) &xprt->xp_pad [sizeof (struct iovec)];
  230. if (mesgp->msg_iovlen)
  231. {
  232. iovp->iov_base = rpc_buffer (xprt);
  233. iovp->iov_len = su->su_iosz;
  234. mesgp->msg_iov = iovp;
  235. mesgp->msg_iovlen = 1;
  236. mesgp->msg_name = &(xprt->xp_raddr);
  237. mesgp->msg_namelen = len;
  238. mesgp->msg_control = &xprt->xp_pad [sizeof (struct iovec)
  239. + sizeof (struct msghdr)];
  240. mesgp->msg_controllen = sizeof(xprt->xp_pad)
  241. - sizeof (struct iovec) - sizeof (struct msghdr);
  242. rlen = __recvmsg (xprt->xp_sock, mesgp, 0);
  243. if (rlen >= 0)
  244. {
  245. struct cmsghdr *cmsg;
  246. len = mesgp->msg_namelen;
  247. cmsg = CMSG_FIRSTHDR (mesgp);
  248. if (cmsg == NULL
  249. || CMSG_NXTHDR (mesgp, cmsg) != NULL
  250. || cmsg->cmsg_level != SOL_IP
  251. || cmsg->cmsg_type != IP_PKTINFO
  252. || cmsg->cmsg_len < (sizeof (struct cmsghdr)
  253. + sizeof (struct in_pktinfo)))
  254. {
  255. /* Not a simple IP_PKTINFO, ignore it. */
  256. mesgp->msg_control = NULL;
  257. mesgp->msg_controllen = 0;
  258. }
  259. else
  260. {
  261. /* It was a simple IP_PKTIFO as we expected, discard the
  262. interface field. */
  263. struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
  264. pkti->ipi_ifindex = 0;
  265. }
  266. }
  267. }
  268. else
  269. #endif
  270. rlen = __recvfrom (xprt->xp_sock, rpc_buffer (xprt),
  271. (int) su->su_iosz, 0,
  272. (struct sockaddr *) &(xprt->xp_raddr), &len);
  273. xprt->xp_addrlen = len;
  274. if (rlen == -1)
  275. {
  276. if (errno == EINTR)
  277. goto again;
  278. __svc_accept_failed ();
  279. }
  280. if (rlen < 16) /* < 4 32-bit ints? */
  281. return FALSE;
  282. xdrs->x_op = XDR_DECODE;
  283. XDR_SETPOS (xdrs, 0);
  284. if (!xdr_callmsg (xdrs, msg))
  285. return FALSE;
  286. su->su_xid = msg->rm_xid;
  287. if (su->su_cache != NULL)
  288. {
  289. if (cache_get (xprt, msg, &reply, &replylen))
  290. {
  291. #ifdef IP_PKTINFO
  292. if (mesgp->msg_iovlen)
  293. {
  294. iovp->iov_base = reply;
  295. iovp->iov_len = replylen;
  296. (void) __sendmsg (xprt->xp_sock, mesgp, 0);
  297. }
  298. else
  299. #endif
  300. (void) __sendto (xprt->xp_sock, reply, (int) replylen, 0,
  301. (struct sockaddr *) &xprt->xp_raddr, len);
  302. return TRUE;
  303. }
  304. }
  305. return TRUE;
  306. }
  307. static bool_t
  308. svcudp_reply (SVCXPRT *xprt, struct rpc_msg *msg)
  309. {
  310. struct svcudp_data *su = su_data (xprt);
  311. XDR *xdrs = &(su->su_xdrs);
  312. int slen, sent;
  313. bool_t stat = FALSE;
  314. #ifdef IP_PKTINFO
  315. struct iovec *iovp;
  316. struct msghdr *mesgp;
  317. #endif
  318. xdrs->x_op = XDR_ENCODE;
  319. XDR_SETPOS (xdrs, 0);
  320. msg->rm_xid = su->su_xid;
  321. if (xdr_replymsg (xdrs, msg))
  322. {
  323. slen = (int) XDR_GETPOS (xdrs);
  324. #ifdef IP_PKTINFO
  325. mesgp = (struct msghdr *) &xprt->xp_pad [sizeof (struct iovec)];
  326. if (mesgp->msg_iovlen)
  327. {
  328. iovp = (struct iovec *) &xprt->xp_pad [0];
  329. iovp->iov_base = rpc_buffer (xprt);
  330. iovp->iov_len = slen;
  331. sent = __sendmsg (xprt->xp_sock, mesgp, 0);
  332. }
  333. else
  334. #endif
  335. sent = __sendto (xprt->xp_sock, rpc_buffer (xprt), slen, 0,
  336. (struct sockaddr *) &(xprt->xp_raddr),
  337. xprt->xp_addrlen);
  338. if (sent == slen)
  339. {
  340. stat = TRUE;
  341. if (su->su_cache && slen >= 0)
  342. {
  343. cache_set (xprt, (u_long) slen);
  344. }
  345. }
  346. }
  347. return stat;
  348. }
  349. static bool_t
  350. svcudp_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
  351. {
  352. return (*xdr_args) (&(su_data (xprt)->su_xdrs), args_ptr);
  353. }
  354. static bool_t
  355. svcudp_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
  356. {
  357. XDR *xdrs = &(su_data (xprt)->su_xdrs);
  358. xdrs->x_op = XDR_FREE;
  359. return (*xdr_args) (xdrs, args_ptr);
  360. }
  361. static void
  362. svcudp_destroy (SVCXPRT *xprt)
  363. {
  364. struct svcudp_data *su = su_data (xprt);
  365. xprt_unregister (xprt);
  366. (void) __close (xprt->xp_sock);
  367. XDR_DESTROY (&(su->su_xdrs));
  368. mem_free (rpc_buffer (xprt), su->su_iosz);
  369. mem_free ((caddr_t) su, sizeof (struct svcudp_data));
  370. mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
  371. }
  372. /***********this could be a separate file*********************/
  373. /*
  374. * Fifo cache for udp server
  375. * Copies pointers to reply buffers into fifo cache
  376. * Buffers are sent again if retransmissions are detected.
  377. */
  378. #define SPARSENESS 4 /* 75% sparse */
  379. #define CACHE_PERROR(msg) \
  380. (void) __fxprintf(NULL, "%s\n", msg)
  381. #define ALLOC(type, size) \
  382. (type *) mem_alloc((unsigned) (sizeof(type) * (size)))
  383. #define CALLOC(type, size) \
  384. (type *) calloc (sizeof (type), size)
  385. /*
  386. * An entry in the cache
  387. */
  388. typedef struct cache_node *cache_ptr;
  389. struct cache_node
  390. {
  391. /*
  392. * Index into cache is xid, proc, vers, prog and address
  393. */
  394. u_long cache_xid;
  395. u_long cache_proc;
  396. u_long cache_vers;
  397. u_long cache_prog;
  398. struct sockaddr_in cache_addr;
  399. /*
  400. * The cached reply and length
  401. */
  402. char *cache_reply;
  403. u_long cache_replylen;
  404. /*
  405. * Next node on the list, if there is a collision
  406. */
  407. cache_ptr cache_next;
  408. };
  409. /*
  410. * The entire cache
  411. */
  412. struct udp_cache
  413. {
  414. u_long uc_size; /* size of cache */
  415. cache_ptr *uc_entries; /* hash table of entries in cache */
  416. cache_ptr *uc_fifo; /* fifo list of entries in cache */
  417. u_long uc_nextvictim; /* points to next victim in fifo list */
  418. u_long uc_prog; /* saved program number */
  419. u_long uc_vers; /* saved version number */
  420. u_long uc_proc; /* saved procedure number */
  421. struct sockaddr_in uc_addr; /* saved caller's address */
  422. };
  423. /*
  424. * the hashing function
  425. */
  426. #define CACHE_LOC(transp, xid) \
  427. (xid % (SPARSENESS*((struct udp_cache *) su_data(transp)->su_cache)->uc_size))
  428. /*
  429. * Enable use of the cache.
  430. * Note: there is no disable.
  431. */
  432. int
  433. svcudp_enablecache (SVCXPRT *transp, u_long size)
  434. {
  435. struct svcudp_data *su = su_data (transp);
  436. struct udp_cache *uc;
  437. if (su->su_cache != NULL)
  438. {
  439. CACHE_PERROR (_("enablecache: cache already enabled"));
  440. return 0;
  441. }
  442. uc = ALLOC (struct udp_cache, 1);
  443. if (uc == NULL)
  444. {
  445. CACHE_PERROR (_("enablecache: could not allocate cache"));
  446. return 0;
  447. }
  448. uc->uc_size = size;
  449. uc->uc_nextvictim = 0;
  450. uc->uc_entries = CALLOC (cache_ptr, size * SPARSENESS);
  451. if (uc->uc_entries == NULL)
  452. {
  453. mem_free (uc, sizeof (struct udp_cache));
  454. CACHE_PERROR (_("enablecache: could not allocate cache data"));
  455. return 0;
  456. }
  457. uc->uc_fifo = CALLOC (cache_ptr, size);
  458. if (uc->uc_fifo == NULL)
  459. {
  460. mem_free (uc->uc_entries, size * SPARSENESS);
  461. mem_free (uc, sizeof (struct udp_cache));
  462. CACHE_PERROR (_("enablecache: could not allocate cache fifo"));
  463. return 0;
  464. }
  465. su->su_cache = (char *) uc;
  466. return 1;
  467. }
  468. libc_hidden_nolink_sunrpc (svcudp_enablecache, GLIBC_2_0)
  469. /*
  470. * Set an entry in the cache
  471. */
  472. static void
  473. cache_set (SVCXPRT *xprt, u_long replylen)
  474. {
  475. cache_ptr victim;
  476. cache_ptr *vicp;
  477. struct svcudp_data *su = su_data (xprt);
  478. struct udp_cache *uc = (struct udp_cache *) su->su_cache;
  479. u_int loc;
  480. char *newbuf;
  481. /*
  482. * Find space for the new entry, either by
  483. * reusing an old entry, or by mallocing a new one
  484. */
  485. victim = uc->uc_fifo[uc->uc_nextvictim];
  486. if (victim != NULL)
  487. {
  488. loc = CACHE_LOC (xprt, victim->cache_xid);
  489. for (vicp = &uc->uc_entries[loc];
  490. *vicp != NULL && *vicp != victim;
  491. vicp = &(*vicp)->cache_next)
  492. ;
  493. if (*vicp == NULL)
  494. {
  495. CACHE_PERROR (_("cache_set: victim not found"));
  496. return;
  497. }
  498. *vicp = victim->cache_next; /* remote from cache */
  499. newbuf = victim->cache_reply;
  500. }
  501. else
  502. {
  503. victim = ALLOC (struct cache_node, 1);
  504. if (victim == NULL)
  505. {
  506. CACHE_PERROR (_("cache_set: victim alloc failed"));
  507. return;
  508. }
  509. newbuf = mem_alloc (su->su_iosz);
  510. if (newbuf == NULL)
  511. {
  512. mem_free (victim, sizeof (struct cache_node));
  513. CACHE_PERROR (_("cache_set: could not allocate new rpc_buffer"));
  514. return;
  515. }
  516. }
  517. /*
  518. * Store it away
  519. */
  520. victim->cache_replylen = replylen;
  521. victim->cache_reply = rpc_buffer (xprt);
  522. rpc_buffer (xprt) = newbuf;
  523. xdrmem_create (&(su->su_xdrs), rpc_buffer (xprt), su->su_iosz, XDR_ENCODE);
  524. victim->cache_xid = su->su_xid;
  525. victim->cache_proc = uc->uc_proc;
  526. victim->cache_vers = uc->uc_vers;
  527. victim->cache_prog = uc->uc_prog;
  528. victim->cache_addr = uc->uc_addr;
  529. loc = CACHE_LOC (xprt, victim->cache_xid);
  530. victim->cache_next = uc->uc_entries[loc];
  531. uc->uc_entries[loc] = victim;
  532. uc->uc_fifo[uc->uc_nextvictim++] = victim;
  533. uc->uc_nextvictim %= uc->uc_size;
  534. }
  535. /*
  536. * Try to get an entry from the cache
  537. * return 1 if found, 0 if not found
  538. */
  539. static int
  540. cache_get (SVCXPRT *xprt, struct rpc_msg *msg, char **replyp,
  541. u_long *replylenp)
  542. {
  543. u_int loc;
  544. cache_ptr ent;
  545. struct svcudp_data *su = su_data (xprt);
  546. struct udp_cache *uc = (struct udp_cache *) su->su_cache;
  547. #define EQADDR(a1, a2) (memcmp((char*)&a1, (char*)&a2, sizeof(a1)) == 0)
  548. loc = CACHE_LOC (xprt, su->su_xid);
  549. for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next)
  550. {
  551. if (ent->cache_xid == su->su_xid &&
  552. ent->cache_proc == uc->uc_proc &&
  553. ent->cache_vers == uc->uc_vers &&
  554. ent->cache_prog == uc->uc_prog &&
  555. EQADDR (ent->cache_addr, uc->uc_addr))
  556. {
  557. *replyp = ent->cache_reply;
  558. *replylenp = ent->cache_replylen;
  559. return 1;
  560. }
  561. }
  562. /*
  563. * Failed to find entry
  564. * Remember a few things so we can do a set later
  565. */
  566. uc->uc_proc = msg->rm_call.cb_proc;
  567. uc->uc_vers = msg->rm_call.cb_vers;
  568. uc->uc_prog = msg->rm_call.cb_prog;
  569. memcpy (&uc->uc_addr, &xprt->xp_raddr, sizeof (uc->uc_addr));
  570. return 0;
  571. }