PageRenderTime 44ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

lib/libc/rpc/svc_dg.c

http://www.minix3.org/
C | 652 lines | 478 code | 68 blank | 106 comment | 87 complexity | 3faa6fd66b66c5c294ed30e4a114968d MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
  1. /* $NetBSD: svc_dg.c,v 1.12 2008/04/25 17:44:44 christos Exp $ */
  2. /*
  3. * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  4. * unrestricted use provided that this legend is included on all tape
  5. * media and as a part of the software program in whole or part. Users
  6. * may copy or modify Sun RPC without charge, but are not authorized
  7. * to license or distribute it to anyone else except as part of a product or
  8. * program developed by the user.
  9. *
  10. * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  11. * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  12. * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  13. *
  14. * Sun RPC is provided with no support and without any obligation on the
  15. * part of Sun Microsystems, Inc. to assist in its use, correction,
  16. * modification or enhancement.
  17. *
  18. * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  19. * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
  20. * OR ANY PART THEREOF.
  21. *
  22. * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  23. * or profits or other special, indirect and consequential damages, even if
  24. * Sun has been advised of the possibility of such damages.
  25. *
  26. * Sun Microsystems, Inc.
  27. * 2550 Garcia Avenue
  28. * Mountain View, California 94043
  29. */
  30. /*
  31. * Copyright (c) 1986-1991 by Sun Microsystems Inc.
  32. */
  33. /* #ident "@(#)svc_dg.c 1.17 94/04/24 SMI" */
  34. /*
  35. * svc_dg.c, Server side for connectionless RPC.
  36. *
  37. * Does some caching in the hopes of achieving execute-at-most-once semantics.
  38. */
  39. #include <sys/cdefs.h>
  40. #if defined(LIBC_SCCS) && !defined(lint)
  41. __RCSID("$NetBSD: svc_dg.c,v 1.12 2008/04/25 17:44:44 christos Exp $");
  42. #endif
  43. #include "namespace.h"
  44. #include "reentrant.h"
  45. #include <sys/types.h>
  46. #include <sys/socket.h>
  47. #include <rpc/rpc.h>
  48. #include <assert.h>
  49. #include <errno.h>
  50. #include <unistd.h>
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include <string.h>
  54. #ifdef RPC_CACHE_DEBUG
  55. #include <netconfig.h>
  56. #include <netdir.h>
  57. #endif
  58. #include <err.h>
  59. #include "rpc_internal.h"
  60. #include "svc_dg.h"
  61. #define su_data(xprt) ((struct svc_dg_data *)(xprt->xp_p2))
  62. #define rpc_buffer(xprt) ((xprt)->xp_p1)
  63. #ifdef __weak_alias
  64. __weak_alias(svc_dg_create,_svc_dg_create)
  65. #endif
  66. #ifndef MAX
  67. #define MAX(a, b) (((a) > (b)) ? (a) : (b))
  68. #endif
  69. static void svc_dg_ops __P((SVCXPRT *));
  70. static enum xprt_stat svc_dg_stat __P((SVCXPRT *));
  71. static bool_t svc_dg_recv __P((SVCXPRT *, struct rpc_msg *));
  72. static bool_t svc_dg_reply __P((SVCXPRT *, struct rpc_msg *));
  73. static bool_t svc_dg_getargs __P((SVCXPRT *, xdrproc_t, caddr_t));
  74. static bool_t svc_dg_freeargs __P((SVCXPRT *, xdrproc_t, caddr_t));
  75. static void svc_dg_destroy __P((SVCXPRT *));
  76. static bool_t svc_dg_control __P((SVCXPRT *, const u_int, void *));
  77. static int cache_get __P((SVCXPRT *, struct rpc_msg *, char **, size_t *));
  78. static void cache_set __P((SVCXPRT *, size_t));
  79. /*
  80. * Usage:
  81. * xprt = svc_dg_create(sock, sendsize, recvsize);
  82. * Does other connectionless specific initializations.
  83. * Once *xprt is initialized, it is registered.
  84. * see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable
  85. * system defaults are chosen.
  86. * The routines returns NULL if a problem occurred.
  87. */
  88. static const char svc_dg_str[] = "svc_dg_create: %s";
  89. static const char svc_dg_err1[] = "could not get transport information";
  90. static const char svc_dg_err2[] = " transport does not support data transfer";
  91. static const char __no_mem_str[] = "out of memory";
  92. SVCXPRT *
  93. svc_dg_create(fd, sendsize, recvsize)
  94. int fd;
  95. u_int sendsize;
  96. u_int recvsize;
  97. {
  98. SVCXPRT *xprt;
  99. struct svc_dg_data *su = NULL;
  100. struct __rpc_sockinfo si;
  101. struct sockaddr_storage ss;
  102. socklen_t slen;
  103. if (!__rpc_fd2sockinfo(fd, &si)) {
  104. warnx(svc_dg_str, svc_dg_err1);
  105. return (NULL);
  106. }
  107. /*
  108. * Find the receive and the send size
  109. */
  110. sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
  111. recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
  112. if ((sendsize == 0) || (recvsize == 0)) {
  113. warnx(svc_dg_str, svc_dg_err2);
  114. return (NULL);
  115. }
  116. xprt = mem_alloc(sizeof (SVCXPRT));
  117. if (xprt == NULL)
  118. goto freedata;
  119. memset(xprt, 0, sizeof (SVCXPRT));
  120. su = mem_alloc(sizeof (*su));
  121. if (su == NULL)
  122. goto freedata;
  123. su->su_iosz = ((MAX(sendsize, recvsize) + 3) / 4) * 4;
  124. if ((rpc_buffer(xprt) = malloc(su->su_iosz)) == NULL)
  125. goto freedata;
  126. xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz,
  127. XDR_DECODE);
  128. su->su_cache = NULL;
  129. xprt->xp_fd = fd;
  130. xprt->xp_p2 = (caddr_t)(void *)su;
  131. xprt->xp_verf.oa_base = su->su_verfbody;
  132. svc_dg_ops(xprt);
  133. xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
  134. slen = sizeof ss;
  135. if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
  136. goto freedata;
  137. xprt->xp_ltaddr.buf = mem_alloc(sizeof (struct sockaddr_storage));
  138. xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_storage);
  139. xprt->xp_ltaddr.len = slen;
  140. memcpy(xprt->xp_ltaddr.buf, &ss, slen);
  141. xprt_register(xprt);
  142. return (xprt);
  143. freedata:
  144. (void) warnx(svc_dg_str, __no_mem_str);
  145. if (xprt) {
  146. if (su)
  147. (void) mem_free(su, sizeof (*su));
  148. (void) mem_free(xprt, sizeof (SVCXPRT));
  149. }
  150. return (NULL);
  151. }
  152. /*ARGSUSED*/
  153. static enum xprt_stat
  154. svc_dg_stat(xprt)
  155. SVCXPRT *xprt;
  156. {
  157. return (XPRT_IDLE);
  158. }
  159. static bool_t
  160. svc_dg_recv(xprt, msg)
  161. SVCXPRT *xprt;
  162. struct rpc_msg *msg;
  163. {
  164. struct svc_dg_data *su;
  165. XDR *xdrs;
  166. char *reply;
  167. struct sockaddr_storage ss;
  168. socklen_t alen;
  169. size_t replylen;
  170. ssize_t rlen;
  171. _DIAGASSERT(xprt != NULL);
  172. _DIAGASSERT(msg != NULL);
  173. su = su_data(xprt);
  174. xdrs = &(su->su_xdrs);
  175. again:
  176. alen = sizeof (struct sockaddr_storage);
  177. rlen = recvfrom(xprt->xp_fd, rpc_buffer(xprt), su->su_iosz, 0,
  178. (struct sockaddr *)(void *)&ss, &alen);
  179. if (rlen == -1 && errno == EINTR)
  180. goto again;
  181. if (rlen == -1 || (rlen < (ssize_t)(4 * sizeof (u_int32_t))))
  182. return (FALSE);
  183. if (xprt->xp_rtaddr.len < alen) {
  184. if (xprt->xp_rtaddr.len != 0)
  185. mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.len);
  186. xprt->xp_rtaddr.buf = mem_alloc(alen);
  187. xprt->xp_rtaddr.len = alen;
  188. }
  189. memcpy(xprt->xp_rtaddr.buf, &ss, alen);
  190. #ifdef PORTMAP
  191. if (ss.ss_family == AF_INET) {
  192. xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf;
  193. xprt->xp_addrlen = sizeof (struct sockaddr_in);
  194. }
  195. #endif
  196. xdrs->x_op = XDR_DECODE;
  197. XDR_SETPOS(xdrs, 0);
  198. if (! xdr_callmsg(xdrs, msg)) {
  199. return (FALSE);
  200. }
  201. su->su_xid = msg->rm_xid;
  202. if (su->su_cache != NULL) {
  203. if (cache_get(xprt, msg, &reply, &replylen)) {
  204. (void)sendto(xprt->xp_fd, reply, replylen, 0,
  205. (struct sockaddr *)(void *)&ss, alen);
  206. return (FALSE);
  207. }
  208. }
  209. return (TRUE);
  210. }
  211. static bool_t
  212. svc_dg_reply(xprt, msg)
  213. SVCXPRT *xprt;
  214. struct rpc_msg *msg;
  215. {
  216. struct svc_dg_data *su;
  217. XDR *xdrs;
  218. bool_t stat = FALSE;
  219. size_t slen;
  220. _DIAGASSERT(xprt != NULL);
  221. _DIAGASSERT(msg != NULL);
  222. su = su_data(xprt);
  223. xdrs = &(su->su_xdrs);
  224. xdrs->x_op = XDR_ENCODE;
  225. XDR_SETPOS(xdrs, 0);
  226. msg->rm_xid = su->su_xid;
  227. if (xdr_replymsg(xdrs, msg)) {
  228. slen = XDR_GETPOS(xdrs);
  229. if (sendto(xprt->xp_fd, rpc_buffer(xprt), slen, 0,
  230. (struct sockaddr *)xprt->xp_rtaddr.buf,
  231. (socklen_t)xprt->xp_rtaddr.len) == (ssize_t) slen) {
  232. stat = TRUE;
  233. if (su->su_cache)
  234. cache_set(xprt, slen);
  235. }
  236. }
  237. return (stat);
  238. }
  239. static bool_t
  240. svc_dg_getargs(xprt, xdr_args, args_ptr)
  241. SVCXPRT *xprt;
  242. xdrproc_t xdr_args;
  243. caddr_t args_ptr;
  244. {
  245. return (*xdr_args)(&(su_data(xprt)->su_xdrs), args_ptr);
  246. }
  247. static bool_t
  248. svc_dg_freeargs(xprt, xdr_args, args_ptr)
  249. SVCXPRT *xprt;
  250. xdrproc_t xdr_args;
  251. caddr_t args_ptr;
  252. {
  253. XDR *xdrs;
  254. _DIAGASSERT(xprt != NULL);
  255. xdrs = &(su_data(xprt)->su_xdrs);
  256. xdrs->x_op = XDR_FREE;
  257. return (*xdr_args)(xdrs, args_ptr);
  258. }
  259. static void
  260. svc_dg_destroy(xprt)
  261. SVCXPRT *xprt;
  262. {
  263. struct svc_dg_data *su;
  264. _DIAGASSERT(xprt != NULL);
  265. su = su_data(xprt);
  266. xprt_unregister(xprt);
  267. if (xprt->xp_fd != -1)
  268. (void)close(xprt->xp_fd);
  269. XDR_DESTROY(&(su->su_xdrs));
  270. (void) mem_free(rpc_buffer(xprt), su->su_iosz);
  271. (void) mem_free(su, sizeof (*su));
  272. if (xprt->xp_rtaddr.buf)
  273. (void) mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
  274. if (xprt->xp_ltaddr.buf)
  275. (void) mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
  276. if (xprt->xp_tp)
  277. (void) free(xprt->xp_tp);
  278. (void) mem_free(xprt, sizeof (SVCXPRT));
  279. }
  280. static bool_t
  281. /*ARGSUSED*/
  282. svc_dg_control(xprt, rq, in)
  283. SVCXPRT *xprt;
  284. const u_int rq;
  285. void *in;
  286. {
  287. return (FALSE);
  288. }
  289. static void
  290. svc_dg_ops(xprt)
  291. SVCXPRT *xprt;
  292. {
  293. static struct xp_ops ops;
  294. static struct xp_ops2 ops2;
  295. #ifdef _REENTRANT
  296. extern mutex_t ops_lock;
  297. #endif
  298. _DIAGASSERT(xprt != NULL);
  299. /* VARIABLES PROTECTED BY ops_lock: ops */
  300. mutex_lock(&ops_lock);
  301. if (ops.xp_recv == NULL) {
  302. ops.xp_recv = svc_dg_recv;
  303. ops.xp_stat = svc_dg_stat;
  304. ops.xp_getargs = svc_dg_getargs;
  305. ops.xp_reply = svc_dg_reply;
  306. ops.xp_freeargs = svc_dg_freeargs;
  307. ops.xp_destroy = svc_dg_destroy;
  308. ops2.xp_control = svc_dg_control;
  309. }
  310. xprt->xp_ops = &ops;
  311. xprt->xp_ops2 = &ops2;
  312. mutex_unlock(&ops_lock);
  313. }
  314. /* The CACHING COMPONENT */
  315. /*
  316. * Could have been a separate file, but some part of it depends upon the
  317. * private structure of the client handle.
  318. *
  319. * Fifo cache for cl server
  320. * Copies pointers to reply buffers into fifo cache
  321. * Buffers are sent again if retransmissions are detected.
  322. */
  323. #define SPARSENESS 4 /* 75% sparse */
  324. #define ALLOC(type, size) \
  325. mem_alloc((sizeof (type) * (size)))
  326. #define MEMZERO(addr, type, size) \
  327. (void) memset((void *) (addr), 0, sizeof (type) * (int) (size))
  328. #define FREE(addr, type, size) \
  329. mem_free((addr), (sizeof (type) * (size)))
  330. /*
  331. * An entry in the cache
  332. */
  333. typedef struct cache_node *cache_ptr;
  334. struct cache_node {
  335. /*
  336. * Index into cache is xid, proc, vers, prog and address
  337. */
  338. u_int32_t cache_xid;
  339. rpcproc_t cache_proc;
  340. rpcvers_t cache_vers;
  341. rpcprog_t cache_prog;
  342. struct netbuf cache_addr;
  343. /*
  344. * The cached reply and length
  345. */
  346. char *cache_reply;
  347. size_t cache_replylen;
  348. /*
  349. * Next node on the list, if there is a collision
  350. */
  351. cache_ptr cache_next;
  352. };
  353. /*
  354. * The entire cache
  355. */
  356. struct cl_cache {
  357. u_int uc_size; /* size of cache */
  358. cache_ptr *uc_entries; /* hash table of entries in cache */
  359. cache_ptr *uc_fifo; /* fifo list of entries in cache */
  360. u_int uc_nextvictim; /* points to next victim in fifo list */
  361. rpcprog_t uc_prog; /* saved program number */
  362. rpcvers_t uc_vers; /* saved version number */
  363. rpcproc_t uc_proc; /* saved procedure number */
  364. };
  365. /*
  366. * the hashing function
  367. */
  368. #define CACHE_LOC(transp, xid) \
  369. (xid % (SPARSENESS * ((struct cl_cache *) \
  370. su_data(transp)->su_cache)->uc_size))
  371. #ifdef _REENTRANT
  372. extern mutex_t dupreq_lock;
  373. #endif
  374. /*
  375. * Enable use of the cache. Returns 1 on success, 0 on failure.
  376. * Note: there is no disable.
  377. */
  378. static const char cache_enable_str[] = "svc_enablecache: %s %s";
  379. static const char alloc_err[] = "could not allocate cache ";
  380. static const char enable_err[] = "cache already enabled";
  381. int
  382. svc_dg_enablecache(transp, size)
  383. SVCXPRT *transp;
  384. u_int size;
  385. {
  386. struct svc_dg_data *su;
  387. struct cl_cache *uc;
  388. _DIAGASSERT(transp != NULL);
  389. su = su_data(transp);
  390. mutex_lock(&dupreq_lock);
  391. if (su->su_cache != NULL) {
  392. (void) warnx(cache_enable_str, enable_err, " ");
  393. mutex_unlock(&dupreq_lock);
  394. return (0);
  395. }
  396. uc = ALLOC(struct cl_cache, 1);
  397. if (uc == NULL) {
  398. warnx(cache_enable_str, alloc_err, " ");
  399. mutex_unlock(&dupreq_lock);
  400. return (0);
  401. }
  402. uc->uc_size = size;
  403. uc->uc_nextvictim = 0;
  404. uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS);
  405. if (uc->uc_entries == NULL) {
  406. warnx(cache_enable_str, alloc_err, "data");
  407. FREE(uc, struct cl_cache, 1);
  408. mutex_unlock(&dupreq_lock);
  409. return (0);
  410. }
  411. MEMZERO(uc->uc_entries, cache_ptr, size * SPARSENESS);
  412. uc->uc_fifo = ALLOC(cache_ptr, size);
  413. if (uc->uc_fifo == NULL) {
  414. warnx(cache_enable_str, alloc_err, "fifo");
  415. FREE(uc->uc_entries, cache_ptr, size * SPARSENESS);
  416. FREE(uc, struct cl_cache, 1);
  417. mutex_unlock(&dupreq_lock);
  418. return (0);
  419. }
  420. MEMZERO(uc->uc_fifo, cache_ptr, size);
  421. su->su_cache = (char *)(void *)uc;
  422. mutex_unlock(&dupreq_lock);
  423. return (1);
  424. }
  425. /*
  426. * Set an entry in the cache. It assumes that the uc entry is set from
  427. * the earlier call to cache_get() for the same procedure. This will always
  428. * happen because cache_get() is calle by svc_dg_recv and cache_set() is called
  429. * by svc_dg_reply(). All this hoopla because the right RPC parameters are
  430. * not available at svc_dg_reply time.
  431. */
  432. static const char cache_set_str[] = "cache_set: %s";
  433. static const char cache_set_err1[] = "victim not found";
  434. static const char cache_set_err2[] = "victim alloc failed";
  435. static const char cache_set_err3[] = "could not allocate new rpc buffer";
  436. static void
  437. cache_set(xprt, replylen)
  438. SVCXPRT *xprt;
  439. size_t replylen;
  440. {
  441. cache_ptr victim;
  442. cache_ptr *vicp;
  443. struct svc_dg_data *su;
  444. struct cl_cache *uc;
  445. u_int loc;
  446. char *newbuf;
  447. #ifdef RPC_CACHE_DEBUG
  448. struct netconfig *nconf;
  449. char *uaddr;
  450. #endif
  451. _DIAGASSERT(xprt != NULL);
  452. su = su_data(xprt);
  453. uc = (struct cl_cache *) su->su_cache;
  454. mutex_lock(&dupreq_lock);
  455. /*
  456. * Find space for the new entry, either by
  457. * reusing an old entry, or by mallocing a new one
  458. */
  459. victim = uc->uc_fifo[uc->uc_nextvictim];
  460. if (victim != NULL) {
  461. loc = CACHE_LOC(xprt, victim->cache_xid);
  462. for (vicp = &uc->uc_entries[loc];
  463. *vicp != NULL && *vicp != victim;
  464. vicp = &(*vicp)->cache_next)
  465. ;
  466. if (*vicp == NULL) {
  467. warnx(cache_set_str, cache_set_err1);
  468. mutex_unlock(&dupreq_lock);
  469. return;
  470. }
  471. *vicp = victim->cache_next; /* remove from cache */
  472. newbuf = victim->cache_reply;
  473. } else {
  474. victim = ALLOC(struct cache_node, 1);
  475. if (victim == NULL) {
  476. warnx(cache_set_str, cache_set_err2);
  477. mutex_unlock(&dupreq_lock);
  478. return;
  479. }
  480. newbuf = mem_alloc(su->su_iosz);
  481. if (newbuf == NULL) {
  482. warnx(cache_set_str, cache_set_err3);
  483. FREE(victim, struct cache_node, 1);
  484. mutex_unlock(&dupreq_lock);
  485. return;
  486. }
  487. }
  488. /*
  489. * Store it away
  490. */
  491. #ifdef RPC_CACHE_DEBUG
  492. if (nconf = getnetconfigent(xprt->xp_netid)) {
  493. uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr);
  494. freenetconfigent(nconf);
  495. printf(
  496. "cache set for xid= %x prog=%d vers=%d proc=%d for rmtaddr=%s\n",
  497. su->su_xid, uc->uc_prog, uc->uc_vers,
  498. uc->uc_proc, uaddr);
  499. free(uaddr);
  500. }
  501. #endif
  502. victim->cache_replylen = replylen;
  503. victim->cache_reply = rpc_buffer(xprt);
  504. rpc_buffer(xprt) = newbuf;
  505. xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt),
  506. su->su_iosz, XDR_ENCODE);
  507. victim->cache_xid = su->su_xid;
  508. victim->cache_proc = uc->uc_proc;
  509. victim->cache_vers = uc->uc_vers;
  510. victim->cache_prog = uc->uc_prog;
  511. victim->cache_addr = xprt->xp_rtaddr;
  512. victim->cache_addr.buf = ALLOC(char, xprt->xp_rtaddr.len);
  513. (void) memcpy(victim->cache_addr.buf, xprt->xp_rtaddr.buf,
  514. (size_t)xprt->xp_rtaddr.len);
  515. loc = CACHE_LOC(xprt, victim->cache_xid);
  516. victim->cache_next = uc->uc_entries[loc];
  517. uc->uc_entries[loc] = victim;
  518. uc->uc_fifo[uc->uc_nextvictim++] = victim;
  519. uc->uc_nextvictim %= uc->uc_size;
  520. mutex_unlock(&dupreq_lock);
  521. }
  522. /*
  523. * Try to get an entry from the cache
  524. * return 1 if found, 0 if not found and set the stage for cache_set()
  525. */
  526. static int
  527. cache_get(xprt, msg, replyp, replylenp)
  528. SVCXPRT *xprt;
  529. struct rpc_msg *msg;
  530. char **replyp;
  531. size_t *replylenp;
  532. {
  533. u_int loc;
  534. cache_ptr ent;
  535. struct svc_dg_data *su;
  536. struct cl_cache *uc;
  537. #ifdef RPC_CACHE_DEBUG
  538. struct netconfig *nconf;
  539. char *uaddr;
  540. #endif
  541. _DIAGASSERT(xprt != NULL);
  542. _DIAGASSERT(msg != NULL);
  543. _DIAGASSERT(replyp != NULL);
  544. _DIAGASSERT(replylenp != NULL);
  545. su = su_data(xprt);
  546. uc = (struct cl_cache *) su->su_cache;
  547. mutex_lock(&dupreq_lock);
  548. loc = CACHE_LOC(xprt, su->su_xid);
  549. for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) {
  550. if (ent->cache_xid == su->su_xid &&
  551. ent->cache_proc == msg->rm_call.cb_proc &&
  552. ent->cache_vers == msg->rm_call.cb_vers &&
  553. ent->cache_prog == msg->rm_call.cb_prog &&
  554. ent->cache_addr.len == xprt->xp_rtaddr.len &&
  555. (memcmp(ent->cache_addr.buf, xprt->xp_rtaddr.buf,
  556. xprt->xp_rtaddr.len) == 0)) {
  557. #ifdef RPC_CACHE_DEBUG
  558. if (nconf = getnetconfigent(xprt->xp_netid)) {
  559. uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr);
  560. freenetconfigent(nconf);
  561. printf(
  562. "cache entry found for xid=%x prog=%d vers=%d proc=%d for rmtaddr=%s\n",
  563. su->su_xid, msg->rm_call.cb_prog,
  564. msg->rm_call.cb_vers,
  565. msg->rm_call.cb_proc, uaddr);
  566. free(uaddr);
  567. }
  568. #endif
  569. *replyp = ent->cache_reply;
  570. *replylenp = ent->cache_replylen;
  571. mutex_unlock(&dupreq_lock);
  572. return (1);
  573. }
  574. }
  575. /*
  576. * Failed to find entry
  577. * Remember a few things so we can do a set later
  578. */
  579. uc->uc_proc = msg->rm_call.cb_proc;
  580. uc->uc_vers = msg->rm_call.cb_vers;
  581. uc->uc_prog = msg->rm_call.cb_prog;
  582. mutex_unlock(&dupreq_lock);
  583. return (0);
  584. }