4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2014 Gary Mills
24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 * Portions of this source code were derived from Berkeley
31 * 4.3 BSD under license from the Regents of the University of
36 * svc_dg.c, Server side for connectionless RPC.
38 * Does some caching in the hopes of achieving execute-at-most-once semantics.
44 #include <sys/types.h>
45 #include <sys/sysmacros.h>
47 #include <rpcsvc/svc_dg_priv.h>
54 #include <sys/socket.h>
55 #include <netinet/in.h>
56 #include <arpa/inet.h>
57 #ifdef RPC_CACHE_DEBUG
58 #include <netconfig.h>
63 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
66 static struct xp_ops
*svc_dg_ops();
67 static void cache_set();
68 static int cache_get();
70 #define rpc_buffer(xprt) ((xprt)->xp_p1)
74 * xprt = svc_dg_create(sock, sendsize, recvsize);
75 * Does other connectionless specific initializations.
76 * Once *xprt is initialized, it is registered.
77 * see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable
78 * system defaults are chosen.
79 * The routines returns NULL if a problem occurred.
81 static const char svc_dg_str
[] = "svc_dg_create: %s";
82 static const char svc_dg_err1
[] = "could not get transport information";
83 static const char svc_dg_err2
[] = " transport does not support data transfer";
84 static const char svc_dg_err3
[] =
85 "fd > FD_SETSIZE; Use rpc_control(RPC_SVC_USE_POLLFD,...);";
86 static const char __no_mem_str
[] = "out of memory";
88 /* Structure used to initialize SVC_XP_AUTH(xprt).svc_ah_ops. */
89 extern struct svc_auth_ops svc_auth_any_ops
;
90 extern int __rpc_get_ltaddr(struct netbuf
*, struct netbuf
*);
93 svc_dg_xprtfree(SVCXPRT
*xprt
)
95 /* LINTED pointer alignment */
96 SVCXPRT_EXT
*xt
= xprt
? SVCEXT(xprt
) : NULL
;
97 /* LINTED pointer alignment */
98 struct svc_dg_data
*su
= xprt
? get_svc_dg_data(xprt
) : NULL
;
102 free(xprt
->xp_netid
);
104 if (xt
->parent
== NULL
)
105 free(xprt
->xp_ltaddr
.buf
);
106 free(xprt
->xp_rtaddr
.buf
);
108 XDR_DESTROY(&(su
->su_xdrs
));
111 free(rpc_buffer(xprt
));
116 svc_dg_create_private(int fd
, uint_t sendsize
, uint_t recvsize
)
119 struct svc_dg_data
*su
= NULL
;
121 size_t ucred_sz
= ucred_size();
123 if (RPC_FD_NOTIN_FDSET(fd
)) {
126 syslog(LOG_ERR
, svc_dg_str
, svc_dg_err3
);
130 if (t_getinfo(fd
, &tinfo
) == -1) {
131 syslog(LOG_ERR
, svc_dg_str
, svc_dg_err1
);
135 * Find the receive and the send size
137 sendsize
= __rpc_get_t_size((int)sendsize
, tinfo
.tsdu
);
138 recvsize
= __rpc_get_t_size((int)recvsize
, tinfo
.tsdu
);
139 if ((sendsize
== 0) || (recvsize
== 0)) {
140 syslog(LOG_ERR
, svc_dg_str
, svc_dg_err2
);
144 if ((xprt
= svc_xprt_alloc()) == NULL
)
146 /* LINTED pointer alignment */
147 svc_flags(xprt
) |= SVC_DGRAM
;
149 su
= malloc(sizeof (*su
) + ucred_sz
);
152 su
->su_iosz
= ((MAX(sendsize
, recvsize
) + 3) / 4) * 4;
153 if ((rpc_buffer(xprt
) = malloc(su
->su_iosz
)) == NULL
)
155 xdrmem_create(&(su
->su_xdrs
), rpc_buffer(xprt
), su
->su_iosz
,
159 xprt
->xp_p2
= (caddr_t
)su
;
160 xprt
->xp_verf
.oa_base
= su
->su_verfbody
;
161 xprt
->xp_ops
= svc_dg_ops();
163 su
->su_tudata
.addr
.maxlen
= 0; /* Fill in later */
165 su
->su_tudata
.udata
.buf
= (char *)rpc_buffer(xprt
);
166 su
->su_tudata
.opt
.buf
= (char *)su
->opts
;
167 su
->su_tudata
.udata
.maxlen
= su
->su_iosz
;
168 su
->su_tudata
.opt
.maxlen
= MAX_OPT_WORDS
* sizeof (int) + ucred_sz
;
169 /* LINTED pointer alignment */
170 SVC_XP_AUTH(xprt
).svc_ah_ops
= svc_auth_any_ops
;
171 /* LINTED pointer alignment */
172 SVC_XP_AUTH(xprt
).svc_ah_private
= NULL
;
175 (void) syslog(LOG_ERR
, svc_dg_str
, __no_mem_str
);
177 svc_dg_xprtfree(xprt
);
182 svc_dg_create(const int fd
, const uint_t sendsize
, const uint_t recvsize
)
186 if ((xprt
= svc_dg_create_private(fd
, sendsize
, recvsize
)) != NULL
)
192 svc_dg_xprtcopy(SVCXPRT
*parent
)
195 struct svc_dg_data
*su
;
196 size_t ucred_sz
= ucred_size();
198 if ((xprt
= svc_xprt_alloc()) == NULL
)
201 /* LINTED pointer alignment */
202 SVCEXT(xprt
)->parent
= parent
;
203 /* LINTED pointer alignment */
204 SVCEXT(xprt
)->flags
= SVCEXT(parent
)->flags
;
206 xprt
->xp_fd
= parent
->xp_fd
;
207 xprt
->xp_port
= parent
->xp_port
;
208 xprt
->xp_ops
= svc_dg_ops();
210 xprt
->xp_tp
= (char *)strdup(parent
->xp_tp
);
211 if (xprt
->xp_tp
== NULL
) {
212 syslog(LOG_ERR
, "svc_dg_xprtcopy: strdup failed");
213 svc_dg_xprtfree(xprt
);
217 if (parent
->xp_netid
) {
218 xprt
->xp_netid
= (char *)strdup(parent
->xp_netid
);
219 if (xprt
->xp_netid
== NULL
) {
220 syslog(LOG_ERR
, "svc_dg_xprtcopy: strdup failed");
222 svc_dg_xprtfree(xprt
);
226 xprt
->xp_ltaddr
= parent
->xp_ltaddr
; /* shared with parent */
228 xprt
->xp_rtaddr
= parent
->xp_rtaddr
;
229 xprt
->xp_rtaddr
.buf
= malloc(xprt
->xp_rtaddr
.maxlen
);
230 if (xprt
->xp_rtaddr
.buf
== NULL
) {
231 svc_dg_xprtfree(xprt
);
234 (void) memcpy(xprt
->xp_rtaddr
.buf
, parent
->xp_rtaddr
.buf
,
235 xprt
->xp_rtaddr
.maxlen
);
236 xprt
->xp_type
= parent
->xp_type
;
238 if ((su
= malloc(sizeof (struct svc_dg_data
) + ucred_sz
)) == NULL
) {
239 svc_dg_xprtfree(xprt
);
242 /* LINTED pointer alignment */
243 su
->su_iosz
= get_svc_dg_data(parent
)->su_iosz
;
244 if ((rpc_buffer(xprt
) = malloc(su
->su_iosz
)) == NULL
) {
245 svc_dg_xprtfree(xprt
);
249 xdrmem_create(&(su
->su_xdrs
), rpc_buffer(xprt
), su
->su_iosz
,
252 su
->su_tudata
.addr
.maxlen
= 0; /* Fill in later */
253 su
->su_tudata
.udata
.buf
= (char *)rpc_buffer(xprt
);
254 su
->su_tudata
.opt
.buf
= (char *)su
->opts
;
255 su
->su_tudata
.udata
.maxlen
= su
->su_iosz
;
256 su
->su_tudata
.opt
.maxlen
= MAX_OPT_WORDS
* sizeof (int) + ucred_sz
;
257 xprt
->xp_p2
= (caddr_t
)su
; /* get_svc_dg_data(xprt) = su */
258 xprt
->xp_verf
.oa_base
= su
->su_verfbody
;
264 static enum xprt_stat
265 svc_dg_stat(SVCXPRT
*xprt
)
271 * Find the SCM_UCRED in src and place a pointer to that option alone in dest.
272 * Note that these two 'netbuf' structures might be the same one, so the code
273 * has to be careful about referring to src after changing dest.
276 extract_cred(const struct netbuf
*src
, struct netbuf
*dest
)
279 unsigned int len
= src
->len
;
280 const struct T_opthdr
*opt
;
283 while (len
>= sizeof (*opt
)) {
284 /* LINTED: pointer alignment */
285 opt
= (const struct T_opthdr
*)cp
;
287 if (olen
> len
|| olen
< sizeof (*opt
) ||
288 !IS_P2ALIGNED(olen
, sizeof (t_uscalar_t
)))
290 if (opt
->level
== SOL_SOCKET
&& opt
->name
== SCM_UCRED
) {
302 * This routine extracts the destination IP address of the inbound RPC packet
303 * and sets that as source IP address for the outbound response.
306 set_src_addr(SVCXPRT
*xprt
, struct netbuf
*opt
)
308 struct netbuf
*nbufp
, *ltaddr
;
309 struct T_opthdr
*opthdr
;
310 in_pktinfo_t
*pktinfo
;
311 struct sockaddr_in
*sock
= NULL
;
313 /* extract dest IP of inbound packet */
314 /* LINTED pointer alignment */
315 nbufp
= (struct netbuf
*)xprt
->xp_p2
;
316 ltaddr
= &xprt
->xp_ltaddr
;
317 if (__rpc_get_ltaddr(nbufp
, ltaddr
) != 0)
320 /* do nothing for non-IPv4 packet */
321 /* LINTED pointer alignment */
322 sock
= (struct sockaddr_in
*)ltaddr
->buf
;
323 if (sock
->sin_family
!= AF_INET
)
326 /* set desired option header */
327 opthdr
= (struct T_opthdr
*)memalign(sizeof (int),
328 sizeof (struct T_opthdr
) + sizeof (in_pktinfo_t
));
331 opthdr
->len
= sizeof (struct T_opthdr
) + sizeof (in_pktinfo_t
);
332 opthdr
->level
= IPPROTO_IP
;
333 opthdr
->name
= IP_PKTINFO
;
336 * 1. set source IP of outbound packet
337 * 2. value '0' for index means IP layer uses this as source address
339 pktinfo
= (in_pktinfo_t
*)(opthdr
+ 1);
340 (void) memset(pktinfo
, 0, sizeof (in_pktinfo_t
));
341 pktinfo
->ipi_spec_dst
.s_addr
= sock
->sin_addr
.s_addr
;
342 pktinfo
->ipi_ifindex
= 0;
344 /* copy data into ancillary buffer */
345 if (opthdr
->len
+ opt
->len
<= opt
->maxlen
) {
346 (void) memcpy((void *)(opt
->buf
+opt
->len
), (const void *)opthdr
,
348 opt
->len
+= opthdr
->len
;
354 svc_dg_recv(SVCXPRT
*xprt
, struct rpc_msg
*msg
)
356 /* LINTED pointer alignment */
357 struct svc_dg_data
*su
= get_svc_dg_data(xprt
);
358 XDR
*xdrs
= &(su
->su_xdrs
);
359 struct t_unitdata
*tu_data
= &(su
->su_tudata
);
361 struct netbuf
*nbufp
;
362 struct netconfig
*nconf
;
364 /* XXX: tudata should have been made a part of the server handle */
365 if (tu_data
->addr
.maxlen
== 0)
366 tu_data
->addr
= xprt
->xp_rtaddr
;
368 tu_data
->addr
.len
= 0;
369 tu_data
->opt
.len
= 0;
370 tu_data
->udata
.len
= 0;
373 if (t_rcvudata(xprt
->xp_fd
, tu_data
, &moreflag
) == -1) {
375 syslog(LOG_ERR
, "svc_dg_recv: t_rcvudata t_errno=%d errno=%d\n",
378 if (t_errno
== TLOOK
) {
381 lookres
= t_look(xprt
->xp_fd
);
382 if ((lookres
== T_UDERR
) &&
383 (t_rcvuderr(xprt
->xp_fd
, NULL
) < 0)) {
387 "svc_dg_recv: t_rcvuderr t_errno = %d\n",
391 if (lookres
== T_DATA
)
393 } else if ((errno
== EINTR
) && (t_errno
== TSYSERR
))
401 (tu_data
->udata
.len
< 4 * (uint_t
)sizeof (uint32_t))) {
403 * If moreflag is set, drop that data packet. Something wrong
407 su
->optbuf
= tu_data
->opt
;
408 xprt
->xp_rtaddr
.len
= tu_data
->addr
.len
;
409 xdrs
->x_op
= XDR_DECODE
;
411 if (!xdr_callmsg(xdrs
, msg
))
413 su
->su_xid
= msg
->rm_xid
;
414 if (su
->su_cache
!= NULL
) {
418 if (cache_get(xprt
, msg
, &reply
, &replylen
)) {
419 /* tu_data.addr is already set */
420 tu_data
->udata
.buf
= reply
;
421 tu_data
->udata
.len
= (uint_t
)replylen
;
422 extract_cred(&tu_data
->opt
, &tu_data
->opt
);
423 set_src_addr(xprt
, &tu_data
->opt
);
424 (void) t_sndudata(xprt
->xp_fd
, tu_data
);
425 tu_data
->udata
.buf
= (char *)rpc_buffer(xprt
);
426 tu_data
->opt
.buf
= (char *)su
->opts
;
432 * get local ip address
435 if ((nconf
= getnetconfigent(xprt
->xp_netid
)) != NULL
) {
436 if (strcmp(nconf
->nc_protofmly
, NC_INET
) == 0 ||
437 strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0) {
438 if (nconf
->nc_semantics
== NC_TPI_CLTS
) {
439 /* LINTED pointer cast */
440 nbufp
= (struct netbuf
*)(xprt
->xp_p2
);
441 if (__rpc_get_ltaddr(nbufp
,
442 &xprt
->xp_ltaddr
) < 0) {
443 if (strcmp(nconf
->nc_protofmly
,
446 "svc_dg_recv: ip(udp), "
447 "t_errno=%d, errno=%d",
450 if (strcmp(nconf
->nc_protofmly
,
453 "svc_dg_recv: ip (udp6), "
454 "t_errno=%d, errno=%d",
457 freenetconfigent(nconf
);
462 freenetconfigent(nconf
);
468 svc_dg_reply(SVCXPRT
*xprt
, struct rpc_msg
*msg
)
470 /* LINTED pointer alignment */
471 struct svc_dg_data
*su
= get_svc_dg_data(xprt
);
472 XDR
*xdrs
= &(su
->su_xdrs
);
474 xdrproc_t xdr_results
;
475 caddr_t xdr_location
;
478 if (msg
->rm_reply
.rp_stat
== MSG_ACCEPTED
&&
479 msg
->rm_reply
.rp_acpt
.ar_stat
== SUCCESS
) {
481 xdr_results
= msg
->acpted_rply
.ar_results
.proc
;
482 xdr_location
= msg
->acpted_rply
.ar_results
.where
;
483 msg
->acpted_rply
.ar_results
.proc
= xdr_void
;
484 msg
->acpted_rply
.ar_results
.where
= NULL
;
488 xdrs
->x_op
= XDR_ENCODE
;
490 msg
->rm_xid
= su
->su_xid
;
491 if (xdr_replymsg(xdrs
, msg
) && (!has_args
||
492 /* LINTED pointer alignment */
493 SVCAUTH_WRAP(&SVC_XP_AUTH(xprt
), xdrs
, xdr_results
,
496 struct t_unitdata
*tu_data
= &(su
->su_tudata
);
498 slen
= (int)XDR_GETPOS(xdrs
);
499 tu_data
->udata
.len
= slen
;
500 extract_cred(&su
->optbuf
, &tu_data
->opt
);
501 set_src_addr(xprt
, &tu_data
->opt
);
503 if (t_sndudata(xprt
->xp_fd
, tu_data
) == 0) {
505 if (su
->su_cache
&& slen
>= 0) {
506 cache_set(xprt
, (uint32_t)slen
);
513 "svc_dg_reply: t_sndudata error t_errno=%d ",
514 "errno=%d\n", t_errno
, errno
);
516 tu_data
->opt
.buf
= (char *)su
->opts
;
522 svc_dg_getargs(SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
524 if (svc_mt_mode
!= RPC_SVC_MT_NONE
)
526 /* LINTED pointer alignment */
527 return (SVCAUTH_UNWRAP(&SVC_XP_AUTH(xprt
),
528 &(get_svc_dg_data(xprt
)->su_xdrs
), xdr_args
, args_ptr
));
532 svc_dg_freeargs(SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
534 /* LINTED pointer alignment */
535 XDR
*xdrs
= &(get_svc_dg_data(xprt
)->su_xdrs
);
537 xdrs
->x_op
= XDR_FREE
;
538 return ((*xdr_args
)(xdrs
, args_ptr
));
542 svc_dg_destroy(SVCXPRT
*xprt
)
544 (void) mutex_lock(&svc_mutex
);
545 _svc_dg_destroy_private(xprt
);
546 (void) mutex_unlock(&svc_mutex
);
550 _svc_dg_destroy_private(SVCXPRT
*xprt
)
552 if (svc_mt_mode
!= RPC_SVC_MT_NONE
) {
553 /* LINTED pointer alignment */
554 if (SVCEXT(xprt
)->parent
)
555 /* LINTED pointer alignment */
556 xprt
= SVCEXT(xprt
)->parent
;
557 /* LINTED pointer alignment */
558 svc_flags(xprt
) |= SVC_DEFUNCT
;
559 /* LINTED pointer alignment */
560 if (SVCEXT(xprt
)->refcnt
> 0)
564 xprt_unregister(xprt
);
565 (void) t_close(xprt
->xp_fd
);
567 if (svc_mt_mode
!= RPC_SVC_MT_NONE
)
568 svc_xprt_destroy(xprt
);
570 svc_dg_xprtfree(xprt
);
575 svc_dg_control(SVCXPRT
*xprt
, const uint_t rq
, void *in
)
579 if (xprt
->xp_p2
== NULL
)
581 /* LINTED pointer alignment */
582 *(uint32_t *)in
= ((struct svc_dg_data
*)(xprt
->xp_p2
))->su_xid
;
589 static struct xp_ops
*
592 static struct xp_ops ops
;
593 extern mutex_t ops_lock
;
595 /* VARIABLES PROTECTED BY ops_lock: ops */
597 (void) mutex_lock(&ops_lock
);
598 if (ops
.xp_recv
== NULL
) {
599 ops
.xp_recv
= svc_dg_recv
;
600 ops
.xp_stat
= svc_dg_stat
;
601 ops
.xp_getargs
= svc_dg_getargs
;
602 ops
.xp_reply
= svc_dg_reply
;
603 ops
.xp_freeargs
= svc_dg_freeargs
;
604 ops
.xp_destroy
= svc_dg_destroy
;
605 ops
.xp_control
= svc_dg_control
;
607 (void) mutex_unlock(&ops_lock
);
611 /* The CACHING COMPONENT */
614 * Could have been a separate file, but some part of it depends upon the
615 * private structure of the client handle.
617 * Fifo cache for cl server
618 * Copies pointers to reply buffers into fifo cache
619 * Buffers are sent again if retransmissions are detected.
622 #define SPARSENESS 4 /* 75% sparse */
625 * An entry in the cache
627 typedef struct cache_node
*cache_ptr
;
630 * Index into cache is xid, proc, vers, prog and address
633 rpcproc_t cache_proc
;
634 rpcvers_t cache_vers
;
635 rpcprog_t cache_prog
;
636 struct netbuf cache_addr
;
638 * The cached reply and length
641 uint32_t cache_replylen
;
643 * Next node on the list, if there is a collision
645 cache_ptr cache_next
;
652 uint32_t uc_size
; /* size of cache */
653 cache_ptr
*uc_entries
; /* hash table of entries in cache */
654 cache_ptr
*uc_fifo
; /* fifo list of entries in cache */
655 uint32_t uc_nextvictim
; /* points to next victim in fifo list */
656 rpcprog_t uc_prog
; /* saved program number */
657 rpcvers_t uc_vers
; /* saved version number */
658 rpcproc_t uc_proc
; /* saved procedure number */
663 * the hashing function
665 #define CACHE_LOC(transp, xid) \
666 (xid % (SPARSENESS * ((struct cl_cache *) \
667 get_svc_dg_data(transp)->su_cache)->uc_size))
669 extern mutex_t dupreq_lock
;
672 * Enable use of the cache. Returns 1 on success, 0 on failure.
673 * Note: there is no disable.
675 static const char cache_enable_str
[] = "svc_enablecache: %s %s";
676 static const char alloc_err
[] = "could not allocate cache ";
677 static const char enable_err
[] = "cache already enabled";
680 svc_dg_enablecache(SVCXPRT
*xprt
, const uint_t size
)
683 struct svc_dg_data
*su
;
686 /* LINTED pointer alignment */
687 if (svc_mt_mode
!= RPC_SVC_MT_NONE
&& SVCEXT(xprt
)->parent
!= NULL
)
688 /* LINTED pointer alignment */
689 transp
= SVCEXT(xprt
)->parent
;
692 /* LINTED pointer alignment */
693 su
= get_svc_dg_data(transp
);
695 (void) mutex_lock(&dupreq_lock
);
696 if (su
->su_cache
!= NULL
) {
697 (void) syslog(LOG_ERR
, cache_enable_str
,
699 (void) mutex_unlock(&dupreq_lock
);
702 uc
= malloc(sizeof (struct cl_cache
));
704 (void) syslog(LOG_ERR
, cache_enable_str
,
706 (void) mutex_unlock(&dupreq_lock
);
710 uc
->uc_nextvictim
= 0;
711 uc
->uc_entries
= calloc(size
* SPARSENESS
, sizeof (cache_ptr
));
712 if (uc
->uc_entries
== NULL
) {
713 (void) syslog(LOG_ERR
, cache_enable_str
, alloc_err
, "data");
715 (void) mutex_unlock(&dupreq_lock
);
718 uc
->uc_fifo
= calloc(size
, sizeof (cache_ptr
));
719 if (uc
->uc_fifo
== NULL
) {
720 (void) syslog(LOG_ERR
, cache_enable_str
, alloc_err
, "fifo");
721 free(uc
->uc_entries
);
723 (void) mutex_unlock(&dupreq_lock
);
726 su
->su_cache
= (char *)uc
;
727 (void) mutex_unlock(&dupreq_lock
);
732 * Set an entry in the cache. It assumes that the uc entry is set from
733 * the earlier call to cache_get() for the same procedure. This will always
734 * happen because cache_get() is calle by svc_dg_recv and cache_set() is called
735 * by svc_dg_reply(). All this hoopla because the right RPC parameters are
736 * not available at svc_dg_reply time.
739 static const char cache_set_str
[] = "cache_set: %s";
740 static const char cache_set_err1
[] = "victim not found";
741 static const char cache_set_err2
[] = "victim alloc failed";
742 static const char cache_set_err3
[] = "could not allocate new rpc buffer";
745 cache_set(SVCXPRT
*xprt
, uint32_t replylen
)
750 struct svc_dg_data
*su
;
753 char *newbuf
, *newbuf2
;
755 #ifdef RPC_CACHE_DEBUG
756 struct netconfig
*nconf
;
760 /* LINTED pointer alignment */
761 if (svc_mt_mode
!= RPC_SVC_MT_NONE
&& SVCEXT(xprt
)->parent
!= NULL
)
762 /* LINTED pointer alignment */
763 parent
= SVCEXT(xprt
)->parent
;
766 /* LINTED pointer alignment */
767 su
= get_svc_dg_data(xprt
);
768 /* LINTED pointer alignment */
769 uc
= (struct cl_cache
*)get_svc_dg_data(parent
)->su_cache
;
771 (void) mutex_lock(&dupreq_lock
);
773 * Find space for the new entry, either by
774 * reusing an old entry, or by mallocing a new one
776 victim
= uc
->uc_fifo
[uc
->uc_nextvictim
];
777 if (victim
!= NULL
) {
778 /* LINTED pointer alignment */
779 loc
= CACHE_LOC(parent
, victim
->cache_xid
);
780 for (vicp
= &uc
->uc_entries
[loc
];
781 *vicp
!= NULL
&& *vicp
!= victim
;
782 vicp
= &(*vicp
)->cache_next
)
785 (void) syslog(LOG_ERR
, cache_set_str
, cache_set_err1
);
786 (void) mutex_unlock(&dupreq_lock
);
789 *vicp
= victim
->cache_next
; /* remove from cache */
790 newbuf
= victim
->cache_reply
;
792 victim
= malloc(sizeof (struct cache_node
));
793 if (victim
== NULL
) {
794 (void) syslog(LOG_ERR
, cache_set_str
, cache_set_err2
);
795 (void) mutex_unlock(&dupreq_lock
);
798 newbuf
= malloc(su
->su_iosz
);
799 if (newbuf
== NULL
) {
800 (void) syslog(LOG_ERR
, cache_set_str
, cache_set_err3
);
802 (void) mutex_unlock(&dupreq_lock
);
811 #ifdef RPC_CACHE_DEBUG
812 if (nconf
= getnetconfigent(xprt
->xp_netid
)) {
813 uaddr
= taddr2uaddr(nconf
, &xprt
->xp_rtaddr
);
814 freenetconfigent(nconf
);
816 "cache set for xid= %x prog=%d vers=%d proc=%d for rmtaddr=%s\n",
817 su
->su_xid
, uc
->uc_prog
, uc
->uc_vers
, uc
->uc_proc
, uaddr
);
821 newbuf2
= malloc(sizeof (char) * xprt
->xp_rtaddr
.len
);
822 if (newbuf2
== NULL
) {
823 syslog(LOG_ERR
, "cache_set : out of memory");
828 (void) mutex_unlock(&dupreq_lock
);
831 victim
->cache_replylen
= replylen
;
832 victim
->cache_reply
= rpc_buffer(xprt
);
833 rpc_buffer(xprt
) = newbuf
;
834 xdrmem_create(&(su
->su_xdrs
), rpc_buffer(xprt
), su
->su_iosz
,
836 su
->su_tudata
.udata
.buf
= (char *)rpc_buffer(xprt
);
837 victim
->cache_xid
= su
->su_xid
;
838 victim
->cache_proc
= uc
->uc_proc
;
839 victim
->cache_vers
= uc
->uc_vers
;
840 victim
->cache_prog
= uc
->uc_prog
;
841 victim
->cache_addr
= xprt
->xp_rtaddr
;
842 victim
->cache_addr
.buf
= newbuf2
;
843 (void) memcpy(victim
->cache_addr
.buf
, xprt
->xp_rtaddr
.buf
,
844 (int)xprt
->xp_rtaddr
.len
);
845 /* LINTED pointer alignment */
846 loc
= CACHE_LOC(parent
, victim
->cache_xid
);
847 victim
->cache_next
= uc
->uc_entries
[loc
];
848 uc
->uc_entries
[loc
] = victim
;
849 uc
->uc_fifo
[uc
->uc_nextvictim
++] = victim
;
850 uc
->uc_nextvictim
%= uc
->uc_size
;
851 (void) mutex_unlock(&dupreq_lock
);
855 * Try to get an entry from the cache
856 * return 1 if found, 0 if not found and set the stage for cache_set()
859 cache_get(SVCXPRT
*xprt
, struct rpc_msg
*msg
, char **replyp
,
865 struct svc_dg_data
*su
;
867 #ifdef RPC_CACHE_DEBUG
868 struct netconfig
*nconf
;
872 /* LINTED pointer alignment */
873 if (svc_mt_mode
!= RPC_SVC_MT_NONE
&& SVCEXT(xprt
)->parent
!= NULL
)
874 /* LINTED pointer alignment */
875 parent
= SVCEXT(xprt
)->parent
;
878 /* LINTED pointer alignment */
879 su
= get_svc_dg_data(xprt
);
880 /* LINTED pointer alignment */
881 uc
= (struct cl_cache
*)get_svc_dg_data(parent
)->su_cache
;
883 (void) mutex_lock(&dupreq_lock
);
884 /* LINTED pointer alignment */
885 loc
= CACHE_LOC(parent
, su
->su_xid
);
886 for (ent
= uc
->uc_entries
[loc
]; ent
!= NULL
; ent
= ent
->cache_next
) {
887 if (ent
->cache_xid
== su
->su_xid
&&
888 ent
->cache_proc
== msg
->rm_call
.cb_proc
&&
889 ent
->cache_vers
== msg
->rm_call
.cb_vers
&&
890 ent
->cache_prog
== msg
->rm_call
.cb_prog
&&
891 ent
->cache_addr
.len
== xprt
->xp_rtaddr
.len
&&
892 (memcmp(ent
->cache_addr
.buf
, xprt
->xp_rtaddr
.buf
,
893 xprt
->xp_rtaddr
.len
) == 0)) {
894 #ifdef RPC_CACHE_DEBUG
895 if (nconf
= getnetconfigent(xprt
->xp_netid
)) {
896 uaddr
= taddr2uaddr(nconf
, &xprt
->xp_rtaddr
);
897 freenetconfigent(nconf
);
899 "cache entry found for xid=%x prog=%d vers=%d proc=%d for rmtaddr=%s\n",
900 su
->su_xid
, msg
->rm_call
.cb_prog
,
901 msg
->rm_call
.cb_vers
,
902 msg
->rm_call
.cb_proc
, uaddr
);
906 *replyp
= ent
->cache_reply
;
907 *replylenp
= ent
->cache_replylen
;
908 (void) mutex_unlock(&dupreq_lock
);
913 * Failed to find entry
914 * Remember a few things so we can do a set later
916 uc
->uc_proc
= msg
->rm_call
.cb_proc
;
917 uc
->uc_vers
= msg
->rm_call
.cb_vers
;
918 uc
->uc_prog
= msg
->rm_call
.cb_prog
;
919 (void) mutex_unlock(&dupreq_lock
);