1 | #include <machine/rtems-bsd-user-space.h> |
---|
2 | |
---|
3 | /* $NetBSD: svc_dg.c,v 1.4 2000/07/06 03:10:35 christos Exp $ */ |
---|
4 | |
---|
5 | /*- |
---|
6 | * Copyright (c) 2009, Sun Microsystems, Inc. |
---|
7 | * All rights reserved. |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions are met: |
---|
11 | * - Redistributions of source code must retain the above copyright notice, |
---|
12 | * this list of conditions and the following disclaimer. |
---|
13 | * - Redistributions in binary form must reproduce the above copyright notice, |
---|
14 | * this list of conditions and the following disclaimer in the documentation |
---|
15 | * and/or other materials provided with the distribution. |
---|
16 | * - Neither the name of Sun Microsystems, Inc. nor the names of its |
---|
17 | * contributors may be used to endorse or promote products derived |
---|
18 | * from this software without specific prior written permission. |
---|
19 | * |
---|
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
---|
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
---|
24 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
---|
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
---|
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
---|
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
---|
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
---|
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
---|
30 | * POSSIBILITY OF SUCH DAMAGE. |
---|
31 | */ |
---|
32 | |
---|
33 | /* |
---|
34 | * Copyright (c) 1986-1991 by Sun Microsystems Inc. |
---|
35 | */ |
---|
36 | |
---|
37 | #if defined(LIBC_SCCS) && !defined(lint) |
---|
38 | #ident "@(#)svc_dg.c 1.17 94/04/24 SMI" |
---|
39 | #endif |
---|
40 | #include <sys/cdefs.h> |
---|
41 | __FBSDID("$FreeBSD$"); |
---|
42 | |
---|
43 | /* |
---|
44 | * svc_dg.c, Server side for connectionless RPC. |
---|
45 | * |
---|
46 | * Does some caching in the hopes of achieving execute-at-most-once semantics. |
---|
47 | */ |
---|
48 | |
---|
49 | #include "namespace.h" |
---|
50 | #include "reentrant.h" |
---|
51 | #include <sys/types.h> |
---|
52 | #include <sys/socket.h> |
---|
53 | #include <rpc/rpc.h> |
---|
54 | #include <rpc/svc_dg.h> |
---|
55 | #include <assert.h> |
---|
56 | #include <errno.h> |
---|
57 | #include <unistd.h> |
---|
58 | #include <stdio.h> |
---|
59 | #include <stdlib.h> |
---|
60 | #include <string.h> |
---|
61 | #ifdef RPC_CACHE_DEBUG |
---|
62 | #include <netconfig.h> |
---|
63 | #include <netdir.h> |
---|
64 | #endif |
---|
65 | #include <err.h> |
---|
66 | #include "un-namespace.h" |
---|
67 | |
---|
68 | #include "rpc_com.h" |
---|
69 | #include "mt_misc.h" |
---|
70 | |
---|
71 | #define su_data(xprt) ((struct svc_dg_data *)(xprt->xp_p2)) |
---|
72 | #define rpc_buffer(xprt) ((xprt)->xp_p1) |
---|
73 | |
---|
74 | #ifndef MAX |
---|
75 | #define MAX(a, b) (((a) > (b)) ? (a) : (b)) |
---|
76 | #endif |
---|
77 | |
---|
78 | static void svc_dg_ops(SVCXPRT *); |
---|
79 | static enum xprt_stat svc_dg_stat(SVCXPRT *); |
---|
80 | static bool_t svc_dg_recv(SVCXPRT *, struct rpc_msg *); |
---|
81 | static bool_t svc_dg_reply(SVCXPRT *, struct rpc_msg *); |
---|
82 | static bool_t svc_dg_getargs(SVCXPRT *, xdrproc_t, void *); |
---|
83 | static bool_t svc_dg_freeargs(SVCXPRT *, xdrproc_t, void *); |
---|
84 | static void svc_dg_destroy(SVCXPRT *); |
---|
85 | static bool_t svc_dg_control(SVCXPRT *, const u_int, void *); |
---|
86 | static int cache_get(SVCXPRT *, struct rpc_msg *, char **, size_t *); |
---|
87 | static void cache_set(SVCXPRT *, size_t); |
---|
88 | int svc_dg_enablecache(SVCXPRT *, u_int); |
---|
89 | |
---|
90 | /* |
---|
91 | * Usage: |
---|
92 | * xprt = svc_dg_create(sock, sendsize, recvsize); |
---|
93 | * Does other connectionless specific initializations. |
---|
94 | * Once *xprt is initialized, it is registered. |
---|
95 | * see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable |
---|
96 | * system defaults are chosen. |
---|
97 | * The routines returns NULL if a problem occurred. |
---|
98 | */ |
---|
99 | static const char svc_dg_str[] = "svc_dg_create: %s"; |
---|
100 | static const char svc_dg_err1[] = "could not get transport information"; |
---|
101 | static const char svc_dg_err2[] = "transport does not support data transfer"; |
---|
102 | static const char svc_dg_err3[] = "getsockname failed"; |
---|
103 | static const char svc_dg_err4[] = "cannot set IP_RECVDSTADDR"; |
---|
104 | static const char __no_mem_str[] = "out of memory"; |
---|
105 | |
---|
106 | SVCXPRT * |
---|
107 | svc_dg_create(fd, sendsize, recvsize) |
---|
108 | int fd; |
---|
109 | u_int sendsize; |
---|
110 | u_int recvsize; |
---|
111 | { |
---|
112 | SVCXPRT *xprt; |
---|
113 | struct svc_dg_data *su = NULL; |
---|
114 | struct __rpc_sockinfo si; |
---|
115 | struct sockaddr_storage ss; |
---|
116 | socklen_t slen; |
---|
117 | |
---|
118 | if (!__rpc_fd2sockinfo(fd, &si)) { |
---|
119 | warnx(svc_dg_str, svc_dg_err1); |
---|
120 | return (NULL); |
---|
121 | } |
---|
122 | /* |
---|
123 | * Find the receive and the send size |
---|
124 | */ |
---|
125 | sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); |
---|
126 | recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); |
---|
127 | if ((sendsize == 0) || (recvsize == 0)) { |
---|
128 | warnx(svc_dg_str, svc_dg_err2); |
---|
129 | return (NULL); |
---|
130 | } |
---|
131 | |
---|
132 | xprt = svc_xprt_alloc(); |
---|
133 | if (xprt == NULL) |
---|
134 | goto freedata; |
---|
135 | |
---|
136 | su = mem_alloc(sizeof (*su)); |
---|
137 | if (su == NULL) |
---|
138 | goto freedata; |
---|
139 | su->su_iosz = ((MAX(sendsize, recvsize) + 3) / 4) * 4; |
---|
140 | if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) |
---|
141 | goto freedata; |
---|
142 | xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, |
---|
143 | XDR_DECODE); |
---|
144 | su->su_cache = NULL; |
---|
145 | xprt->xp_fd = fd; |
---|
146 | xprt->xp_p2 = su; |
---|
147 | xprt->xp_verf.oa_base = su->su_verfbody; |
---|
148 | svc_dg_ops(xprt); |
---|
149 | xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); |
---|
150 | |
---|
151 | slen = sizeof ss; |
---|
152 | if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { |
---|
153 | warnx(svc_dg_str, svc_dg_err3); |
---|
154 | goto freedata_nowarn; |
---|
155 | } |
---|
156 | xprt->xp_ltaddr.buf = mem_alloc(sizeof (struct sockaddr_storage)); |
---|
157 | xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_storage); |
---|
158 | xprt->xp_ltaddr.len = slen; |
---|
159 | memcpy(xprt->xp_ltaddr.buf, &ss, slen); |
---|
160 | |
---|
161 | if (ss.ss_family == AF_INET) { |
---|
162 | struct sockaddr_in *sin; |
---|
163 | static const int true_value = 1; |
---|
164 | |
---|
165 | sin = (struct sockaddr_in *)(void *)&ss; |
---|
166 | if (sin->sin_addr.s_addr == INADDR_ANY) { |
---|
167 | su->su_srcaddr.buf = mem_alloc(sizeof (ss)); |
---|
168 | su->su_srcaddr.maxlen = sizeof (ss); |
---|
169 | |
---|
170 | if (_setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, |
---|
171 | &true_value, sizeof(true_value))) { |
---|
172 | warnx(svc_dg_str, svc_dg_err4); |
---|
173 | goto freedata_nowarn; |
---|
174 | } |
---|
175 | } |
---|
176 | } |
---|
177 | |
---|
178 | xprt_register(xprt); |
---|
179 | return (xprt); |
---|
180 | freedata: |
---|
181 | (void) warnx(svc_dg_str, __no_mem_str); |
---|
182 | freedata_nowarn: |
---|
183 | if (xprt) { |
---|
184 | if (su) |
---|
185 | (void) mem_free(su, sizeof (*su)); |
---|
186 | svc_xprt_free(xprt); |
---|
187 | } |
---|
188 | return (NULL); |
---|
189 | } |
---|
190 | |
---|
191 | /*ARGSUSED*/ |
---|
192 | static enum xprt_stat |
---|
193 | svc_dg_stat(xprt) |
---|
194 | SVCXPRT *xprt; |
---|
195 | { |
---|
196 | return (XPRT_IDLE); |
---|
197 | } |
---|
198 | |
---|
199 | static int |
---|
200 | svc_dg_recvfrom(int fd, char *buf, int buflen, |
---|
201 | struct sockaddr *raddr, socklen_t *raddrlen, |
---|
202 | struct sockaddr *laddr, socklen_t *laddrlen) |
---|
203 | { |
---|
204 | struct msghdr msg; |
---|
205 | struct iovec msg_iov[1]; |
---|
206 | struct sockaddr_in *lin = (struct sockaddr_in *)laddr; |
---|
207 | int rlen; |
---|
208 | bool_t have_lin = FALSE; |
---|
209 | char tmp[CMSG_LEN(sizeof(*lin))]; |
---|
210 | struct cmsghdr *cmsg; |
---|
211 | |
---|
212 | memset((char *)&msg, 0, sizeof(msg)); |
---|
213 | msg_iov[0].iov_base = buf; |
---|
214 | msg_iov[0].iov_len = buflen; |
---|
215 | msg.msg_iov = msg_iov; |
---|
216 | msg.msg_iovlen = 1; |
---|
217 | msg.msg_namelen = *raddrlen; |
---|
218 | msg.msg_name = (char *)raddr; |
---|
219 | if (laddr != NULL) { |
---|
220 | msg.msg_control = (caddr_t)tmp; |
---|
221 | msg.msg_controllen = CMSG_LEN(sizeof(*lin)); |
---|
222 | } |
---|
223 | rlen = _recvmsg(fd, &msg, 0); |
---|
224 | if (rlen >= 0) |
---|
225 | *raddrlen = msg.msg_namelen; |
---|
226 | |
---|
227 | if (rlen == -1 || laddr == NULL || |
---|
228 | msg.msg_controllen < sizeof(struct cmsghdr) || |
---|
229 | msg.msg_flags & MSG_CTRUNC) |
---|
230 | return rlen; |
---|
231 | |
---|
232 | for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; |
---|
233 | cmsg = CMSG_NXTHDR(&msg, cmsg)) { |
---|
234 | if (cmsg->cmsg_level == IPPROTO_IP && |
---|
235 | cmsg->cmsg_type == IP_RECVDSTADDR) { |
---|
236 | have_lin = TRUE; |
---|
237 | memcpy(&lin->sin_addr, |
---|
238 | (struct in_addr *)CMSG_DATA(cmsg), |
---|
239 | sizeof(struct in_addr)); |
---|
240 | break; |
---|
241 | } |
---|
242 | } |
---|
243 | |
---|
244 | lin->sin_family = AF_INET; |
---|
245 | lin->sin_port = 0; |
---|
246 | *laddrlen = sizeof(struct sockaddr_in); |
---|
247 | |
---|
248 | if (!have_lin) |
---|
249 | lin->sin_addr.s_addr = INADDR_ANY; |
---|
250 | |
---|
251 | return rlen; |
---|
252 | } |
---|
253 | |
---|
254 | static bool_t |
---|
255 | svc_dg_recv(xprt, msg) |
---|
256 | SVCXPRT *xprt; |
---|
257 | struct rpc_msg *msg; |
---|
258 | { |
---|
259 | struct svc_dg_data *su = su_data(xprt); |
---|
260 | XDR *xdrs = &(su->su_xdrs); |
---|
261 | char *reply; |
---|
262 | struct sockaddr_storage ss; |
---|
263 | socklen_t alen; |
---|
264 | size_t replylen; |
---|
265 | ssize_t rlen; |
---|
266 | |
---|
267 | again: |
---|
268 | alen = sizeof (struct sockaddr_storage); |
---|
269 | rlen = svc_dg_recvfrom(xprt->xp_fd, rpc_buffer(xprt), su->su_iosz, |
---|
270 | (struct sockaddr *)(void *)&ss, &alen, |
---|
271 | (struct sockaddr *)su->su_srcaddr.buf, &su->su_srcaddr.len); |
---|
272 | if (rlen == -1 && errno == EINTR) |
---|
273 | goto again; |
---|
274 | if (rlen == -1 || (rlen < (ssize_t)(4 * sizeof (u_int32_t)))) |
---|
275 | return (FALSE); |
---|
276 | if (xprt->xp_rtaddr.len < alen) { |
---|
277 | if (xprt->xp_rtaddr.len != 0) |
---|
278 | mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.len); |
---|
279 | xprt->xp_rtaddr.buf = mem_alloc(alen); |
---|
280 | xprt->xp_rtaddr.len = alen; |
---|
281 | } |
---|
282 | memcpy(xprt->xp_rtaddr.buf, &ss, alen); |
---|
283 | #ifdef PORTMAP |
---|
284 | if (ss.ss_family == AF_INET) { |
---|
285 | xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf; |
---|
286 | xprt->xp_addrlen = sizeof (struct sockaddr_in); |
---|
287 | } |
---|
288 | #endif /* PORTMAP */ |
---|
289 | xdrs->x_op = XDR_DECODE; |
---|
290 | XDR_SETPOS(xdrs, 0); |
---|
291 | if (! xdr_callmsg(xdrs, msg)) { |
---|
292 | return (FALSE); |
---|
293 | } |
---|
294 | su->su_xid = msg->rm_xid; |
---|
295 | if (su->su_cache != NULL) { |
---|
296 | if (cache_get(xprt, msg, &reply, &replylen)) { |
---|
297 | (void)_sendto(xprt->xp_fd, reply, replylen, 0, |
---|
298 | (struct sockaddr *)(void *)&ss, alen); |
---|
299 | return (FALSE); |
---|
300 | } |
---|
301 | } |
---|
302 | return (TRUE); |
---|
303 | } |
---|
304 | |
---|
305 | static int |
---|
306 | svc_dg_sendto(int fd, char *buf, int buflen, |
---|
307 | const struct sockaddr *raddr, socklen_t raddrlen, |
---|
308 | const struct sockaddr *laddr, socklen_t laddrlen) |
---|
309 | { |
---|
310 | struct msghdr msg; |
---|
311 | struct iovec msg_iov[1]; |
---|
312 | struct sockaddr_in *laddr_in = (struct sockaddr_in *)laddr; |
---|
313 | struct in_addr *lin = &laddr_in->sin_addr; |
---|
314 | char tmp[CMSG_SPACE(sizeof(*lin))]; |
---|
315 | struct cmsghdr *cmsg; |
---|
316 | |
---|
317 | memset((char *)&msg, 0, sizeof(msg)); |
---|
318 | msg_iov[0].iov_base = buf; |
---|
319 | msg_iov[0].iov_len = buflen; |
---|
320 | msg.msg_iov = msg_iov; |
---|
321 | msg.msg_iovlen = 1; |
---|
322 | msg.msg_namelen = raddrlen; |
---|
323 | msg.msg_name = (char *)raddr; |
---|
324 | |
---|
325 | if (laddr != NULL && laddr->sa_family == AF_INET && |
---|
326 | lin->s_addr != INADDR_ANY) { |
---|
327 | msg.msg_control = (caddr_t)tmp; |
---|
328 | msg.msg_controllen = CMSG_LEN(sizeof(*lin)); |
---|
329 | cmsg = CMSG_FIRSTHDR(&msg); |
---|
330 | cmsg->cmsg_len = CMSG_LEN(sizeof(*lin)); |
---|
331 | cmsg->cmsg_level = IPPROTO_IP; |
---|
332 | cmsg->cmsg_type = IP_SENDSRCADDR; |
---|
333 | memcpy(CMSG_DATA(cmsg), lin, sizeof(*lin)); |
---|
334 | } |
---|
335 | |
---|
336 | return _sendmsg(fd, &msg, 0); |
---|
337 | } |
---|
338 | |
---|
339 | static bool_t |
---|
340 | svc_dg_reply(xprt, msg) |
---|
341 | SVCXPRT *xprt; |
---|
342 | struct rpc_msg *msg; |
---|
343 | { |
---|
344 | struct svc_dg_data *su = su_data(xprt); |
---|
345 | XDR *xdrs = &(su->su_xdrs); |
---|
346 | bool_t stat = TRUE; |
---|
347 | size_t slen; |
---|
348 | xdrproc_t xdr_proc; |
---|
349 | caddr_t xdr_where; |
---|
350 | |
---|
351 | xdrs->x_op = XDR_ENCODE; |
---|
352 | XDR_SETPOS(xdrs, 0); |
---|
353 | msg->rm_xid = su->su_xid; |
---|
354 | if (msg->rm_reply.rp_stat == MSG_ACCEPTED && |
---|
355 | msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { |
---|
356 | xdr_proc = msg->acpted_rply.ar_results.proc; |
---|
357 | xdr_where = msg->acpted_rply.ar_results.where; |
---|
358 | msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; |
---|
359 | msg->acpted_rply.ar_results.where = NULL; |
---|
360 | |
---|
361 | if (!xdr_replymsg(xdrs, msg) || |
---|
362 | !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) |
---|
363 | stat = FALSE; |
---|
364 | } else { |
---|
365 | stat = xdr_replymsg(xdrs, msg); |
---|
366 | } |
---|
367 | if (stat) { |
---|
368 | slen = XDR_GETPOS(xdrs); |
---|
369 | if (svc_dg_sendto(xprt->xp_fd, rpc_buffer(xprt), slen, |
---|
370 | (struct sockaddr *)xprt->xp_rtaddr.buf, |
---|
371 | (socklen_t)xprt->xp_rtaddr.len, |
---|
372 | (struct sockaddr *)su->su_srcaddr.buf, |
---|
373 | (socklen_t)su->su_srcaddr.len) == (ssize_t) slen) { |
---|
374 | stat = TRUE; |
---|
375 | if (su->su_cache) |
---|
376 | cache_set(xprt, slen); |
---|
377 | } |
---|
378 | } |
---|
379 | return (stat); |
---|
380 | } |
---|
381 | |
---|
382 | static bool_t |
---|
383 | svc_dg_getargs(xprt, xdr_args, args_ptr) |
---|
384 | SVCXPRT *xprt; |
---|
385 | xdrproc_t xdr_args; |
---|
386 | void *args_ptr; |
---|
387 | { |
---|
388 | struct svc_dg_data *su; |
---|
389 | |
---|
390 | assert(xprt != NULL); |
---|
391 | su = su_data(xprt); |
---|
392 | return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), |
---|
393 | &su->su_xdrs, xdr_args, args_ptr)); |
---|
394 | } |
---|
395 | |
---|
396 | static bool_t |
---|
397 | svc_dg_freeargs(xprt, xdr_args, args_ptr) |
---|
398 | SVCXPRT *xprt; |
---|
399 | xdrproc_t xdr_args; |
---|
400 | void *args_ptr; |
---|
401 | { |
---|
402 | XDR *xdrs = &(su_data(xprt)->su_xdrs); |
---|
403 | |
---|
404 | xdrs->x_op = XDR_FREE; |
---|
405 | return (*xdr_args)(xdrs, args_ptr); |
---|
406 | } |
---|
407 | |
---|
408 | static void |
---|
409 | svc_dg_destroy(xprt) |
---|
410 | SVCXPRT *xprt; |
---|
411 | { |
---|
412 | struct svc_dg_data *su = su_data(xprt); |
---|
413 | |
---|
414 | xprt_unregister(xprt); |
---|
415 | if (xprt->xp_fd != -1) |
---|
416 | (void)_close(xprt->xp_fd); |
---|
417 | XDR_DESTROY(&(su->su_xdrs)); |
---|
418 | (void) mem_free(rpc_buffer(xprt), su->su_iosz); |
---|
419 | if (su->su_srcaddr.buf) |
---|
420 | (void) mem_free(su->su_srcaddr.buf, su->su_srcaddr.maxlen); |
---|
421 | (void) mem_free(su, sizeof (*su)); |
---|
422 | if (xprt->xp_rtaddr.buf) |
---|
423 | (void) mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); |
---|
424 | if (xprt->xp_ltaddr.buf) |
---|
425 | (void) mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); |
---|
426 | if (xprt->xp_tp) |
---|
427 | (void) free(xprt->xp_tp); |
---|
428 | svc_xprt_free(xprt); |
---|
429 | } |
---|
430 | |
---|
431 | static bool_t |
---|
432 | /*ARGSUSED*/ |
---|
433 | svc_dg_control(xprt, rq, in) |
---|
434 | SVCXPRT *xprt; |
---|
435 | const u_int rq; |
---|
436 | void *in; |
---|
437 | { |
---|
438 | return (FALSE); |
---|
439 | } |
---|
440 | |
---|
441 | static void |
---|
442 | svc_dg_ops(xprt) |
---|
443 | SVCXPRT *xprt; |
---|
444 | { |
---|
445 | static struct xp_ops ops; |
---|
446 | static struct xp_ops2 ops2; |
---|
447 | |
---|
448 | /* VARIABLES PROTECTED BY ops_lock: ops */ |
---|
449 | |
---|
450 | mutex_lock(&ops_lock); |
---|
451 | if (ops.xp_recv == NULL) { |
---|
452 | ops.xp_recv = svc_dg_recv; |
---|
453 | ops.xp_stat = svc_dg_stat; |
---|
454 | ops.xp_getargs = svc_dg_getargs; |
---|
455 | ops.xp_reply = svc_dg_reply; |
---|
456 | ops.xp_freeargs = svc_dg_freeargs; |
---|
457 | ops.xp_destroy = svc_dg_destroy; |
---|
458 | ops2.xp_control = svc_dg_control; |
---|
459 | } |
---|
460 | xprt->xp_ops = &ops; |
---|
461 | xprt->xp_ops2 = &ops2; |
---|
462 | mutex_unlock(&ops_lock); |
---|
463 | } |
---|
464 | |
---|
465 | /* The CACHING COMPONENT */ |
---|
466 | |
---|
467 | /* |
---|
468 | * Could have been a separate file, but some part of it depends upon the |
---|
469 | * private structure of the client handle. |
---|
470 | * |
---|
471 | * Fifo cache for cl server |
---|
472 | * Copies pointers to reply buffers into fifo cache |
---|
473 | * Buffers are sent again if retransmissions are detected. |
---|
474 | */ |
---|
475 | |
---|
476 | #define SPARSENESS 4 /* 75% sparse */ |
---|
477 | |
---|
478 | #define ALLOC(type, size) \ |
---|
479 | (type *) mem_alloc((sizeof (type) * (size))) |
---|
480 | |
---|
481 | #define MEMZERO(addr, type, size) \ |
---|
482 | (void) memset((void *) (addr), 0, sizeof (type) * (int) (size)) |
---|
483 | |
---|
484 | #define FREE(addr, type, size) \ |
---|
485 | mem_free((addr), (sizeof (type) * (size))) |
---|
486 | |
---|
487 | /* |
---|
488 | * An entry in the cache |
---|
489 | */ |
---|
490 | typedef struct cache_node *cache_ptr; |
---|
491 | struct cache_node { |
---|
492 | /* |
---|
493 | * Index into cache is xid, proc, vers, prog and address |
---|
494 | */ |
---|
495 | u_int32_t cache_xid; |
---|
496 | rpcproc_t cache_proc; |
---|
497 | rpcvers_t cache_vers; |
---|
498 | rpcprog_t cache_prog; |
---|
499 | struct netbuf cache_addr; |
---|
500 | /* |
---|
501 | * The cached reply and length |
---|
502 | */ |
---|
503 | char *cache_reply; |
---|
504 | size_t cache_replylen; |
---|
505 | /* |
---|
506 | * Next node on the list, if there is a collision |
---|
507 | */ |
---|
508 | cache_ptr cache_next; |
---|
509 | }; |
---|
510 | |
---|
511 | /* |
---|
512 | * The entire cache |
---|
513 | */ |
---|
514 | struct cl_cache { |
---|
515 | u_int uc_size; /* size of cache */ |
---|
516 | cache_ptr *uc_entries; /* hash table of entries in cache */ |
---|
517 | cache_ptr *uc_fifo; /* fifo list of entries in cache */ |
---|
518 | u_int uc_nextvictim; /* points to next victim in fifo list */ |
---|
519 | rpcprog_t uc_prog; /* saved program number */ |
---|
520 | rpcvers_t uc_vers; /* saved version number */ |
---|
521 | rpcproc_t uc_proc; /* saved procedure number */ |
---|
522 | }; |
---|
523 | |
---|
524 | |
---|
525 | /* |
---|
526 | * the hashing function |
---|
527 | */ |
---|
528 | #define CACHE_LOC(transp, xid) \ |
---|
529 | (xid % (SPARSENESS * ((struct cl_cache *) \ |
---|
530 | su_data(transp)->su_cache)->uc_size)) |
---|
531 | |
---|
532 | /* |
---|
533 | * Enable use of the cache. Returns 1 on success, 0 on failure. |
---|
534 | * Note: there is no disable. |
---|
535 | */ |
---|
536 | static const char cache_enable_str[] = "svc_enablecache: %s %s"; |
---|
537 | static const char alloc_err[] = "could not allocate cache "; |
---|
538 | static const char enable_err[] = "cache already enabled"; |
---|
539 | |
---|
540 | int |
---|
541 | svc_dg_enablecache(transp, size) |
---|
542 | SVCXPRT *transp; |
---|
543 | u_int size; |
---|
544 | { |
---|
545 | struct svc_dg_data *su = su_data(transp); |
---|
546 | struct cl_cache *uc; |
---|
547 | |
---|
548 | mutex_lock(&dupreq_lock); |
---|
549 | if (su->su_cache != NULL) { |
---|
550 | (void) warnx(cache_enable_str, enable_err, " "); |
---|
551 | mutex_unlock(&dupreq_lock); |
---|
552 | return (0); |
---|
553 | } |
---|
554 | uc = ALLOC(struct cl_cache, 1); |
---|
555 | if (uc == NULL) { |
---|
556 | warnx(cache_enable_str, alloc_err, " "); |
---|
557 | mutex_unlock(&dupreq_lock); |
---|
558 | return (0); |
---|
559 | } |
---|
560 | uc->uc_size = size; |
---|
561 | uc->uc_nextvictim = 0; |
---|
562 | uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS); |
---|
563 | if (uc->uc_entries == NULL) { |
---|
564 | warnx(cache_enable_str, alloc_err, "data"); |
---|
565 | FREE(uc, struct cl_cache, 1); |
---|
566 | mutex_unlock(&dupreq_lock); |
---|
567 | return (0); |
---|
568 | } |
---|
569 | MEMZERO(uc->uc_entries, cache_ptr, size * SPARSENESS); |
---|
570 | uc->uc_fifo = ALLOC(cache_ptr, size); |
---|
571 | if (uc->uc_fifo == NULL) { |
---|
572 | warnx(cache_enable_str, alloc_err, "fifo"); |
---|
573 | FREE(uc->uc_entries, cache_ptr, size * SPARSENESS); |
---|
574 | FREE(uc, struct cl_cache, 1); |
---|
575 | mutex_unlock(&dupreq_lock); |
---|
576 | return (0); |
---|
577 | } |
---|
578 | MEMZERO(uc->uc_fifo, cache_ptr, size); |
---|
579 | su->su_cache = (char *)(void *)uc; |
---|
580 | mutex_unlock(&dupreq_lock); |
---|
581 | return (1); |
---|
582 | } |
---|
583 | |
---|
584 | /* |
---|
585 | * Set an entry in the cache. It assumes that the uc entry is set from |
---|
586 | * the earlier call to cache_get() for the same procedure. This will always |
---|
587 | * happen because cache_get() is calle by svc_dg_recv and cache_set() is called |
---|
588 | * by svc_dg_reply(). All this hoopla because the right RPC parameters are |
---|
589 | * not available at svc_dg_reply time. |
---|
590 | */ |
---|
591 | |
---|
592 | static const char cache_set_str[] = "cache_set: %s"; |
---|
593 | static const char cache_set_err1[] = "victim not found"; |
---|
594 | static const char cache_set_err2[] = "victim alloc failed"; |
---|
595 | static const char cache_set_err3[] = "could not allocate new rpc buffer"; |
---|
596 | |
---|
597 | static void |
---|
598 | cache_set(xprt, replylen) |
---|
599 | SVCXPRT *xprt; |
---|
600 | size_t replylen; |
---|
601 | { |
---|
602 | cache_ptr victim; |
---|
603 | cache_ptr *vicp; |
---|
604 | struct svc_dg_data *su = su_data(xprt); |
---|
605 | struct cl_cache *uc = (struct cl_cache *) su->su_cache; |
---|
606 | u_int loc; |
---|
607 | char *newbuf; |
---|
608 | #ifdef RPC_CACHE_DEBUG |
---|
609 | struct netconfig *nconf; |
---|
610 | char *uaddr; |
---|
611 | #endif |
---|
612 | |
---|
613 | mutex_lock(&dupreq_lock); |
---|
614 | /* |
---|
615 | * Find space for the new entry, either by |
---|
616 | * reusing an old entry, or by mallocing a new one |
---|
617 | */ |
---|
618 | victim = uc->uc_fifo[uc->uc_nextvictim]; |
---|
619 | if (victim != NULL) { |
---|
620 | loc = CACHE_LOC(xprt, victim->cache_xid); |
---|
621 | for (vicp = &uc->uc_entries[loc]; |
---|
622 | *vicp != NULL && *vicp != victim; |
---|
623 | vicp = &(*vicp)->cache_next) |
---|
624 | ; |
---|
625 | if (*vicp == NULL) { |
---|
626 | warnx(cache_set_str, cache_set_err1); |
---|
627 | mutex_unlock(&dupreq_lock); |
---|
628 | return; |
---|
629 | } |
---|
630 | *vicp = victim->cache_next; /* remove from cache */ |
---|
631 | newbuf = victim->cache_reply; |
---|
632 | } else { |
---|
633 | victim = ALLOC(struct cache_node, 1); |
---|
634 | if (victim == NULL) { |
---|
635 | warnx(cache_set_str, cache_set_err2); |
---|
636 | mutex_unlock(&dupreq_lock); |
---|
637 | return; |
---|
638 | } |
---|
639 | newbuf = mem_alloc(su->su_iosz); |
---|
640 | if (newbuf == NULL) { |
---|
641 | warnx(cache_set_str, cache_set_err3); |
---|
642 | FREE(victim, struct cache_node, 1); |
---|
643 | mutex_unlock(&dupreq_lock); |
---|
644 | return; |
---|
645 | } |
---|
646 | } |
---|
647 | |
---|
648 | /* |
---|
649 | * Store it away |
---|
650 | */ |
---|
651 | #ifdef RPC_CACHE_DEBUG |
---|
652 | if (nconf = getnetconfigent(xprt->xp_netid)) { |
---|
653 | uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr); |
---|
654 | freenetconfigent(nconf); |
---|
655 | printf( |
---|
656 | "cache set for xid= %x prog=%d vers=%d proc=%d for rmtaddr=%s\n", |
---|
657 | su->su_xid, uc->uc_prog, uc->uc_vers, |
---|
658 | uc->uc_proc, uaddr); |
---|
659 | free(uaddr); |
---|
660 | } |
---|
661 | #endif |
---|
662 | victim->cache_replylen = replylen; |
---|
663 | victim->cache_reply = rpc_buffer(xprt); |
---|
664 | rpc_buffer(xprt) = newbuf; |
---|
665 | xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), |
---|
666 | su->su_iosz, XDR_ENCODE); |
---|
667 | victim->cache_xid = su->su_xid; |
---|
668 | victim->cache_proc = uc->uc_proc; |
---|
669 | victim->cache_vers = uc->uc_vers; |
---|
670 | victim->cache_prog = uc->uc_prog; |
---|
671 | victim->cache_addr = xprt->xp_rtaddr; |
---|
672 | victim->cache_addr.buf = ALLOC(char, xprt->xp_rtaddr.len); |
---|
673 | (void) memcpy(victim->cache_addr.buf, xprt->xp_rtaddr.buf, |
---|
674 | (size_t)xprt->xp_rtaddr.len); |
---|
675 | loc = CACHE_LOC(xprt, victim->cache_xid); |
---|
676 | victim->cache_next = uc->uc_entries[loc]; |
---|
677 | uc->uc_entries[loc] = victim; |
---|
678 | uc->uc_fifo[uc->uc_nextvictim++] = victim; |
---|
679 | uc->uc_nextvictim %= uc->uc_size; |
---|
680 | mutex_unlock(&dupreq_lock); |
---|
681 | } |
---|
682 | |
---|
683 | /* |
---|
684 | * Try to get an entry from the cache |
---|
685 | * return 1 if found, 0 if not found and set the stage for cache_set() |
---|
686 | */ |
---|
687 | static int |
---|
688 | cache_get(xprt, msg, replyp, replylenp) |
---|
689 | SVCXPRT *xprt; |
---|
690 | struct rpc_msg *msg; |
---|
691 | char **replyp; |
---|
692 | size_t *replylenp; |
---|
693 | { |
---|
694 | u_int loc; |
---|
695 | cache_ptr ent; |
---|
696 | struct svc_dg_data *su = su_data(xprt); |
---|
697 | struct cl_cache *uc = (struct cl_cache *) su->su_cache; |
---|
698 | #ifdef RPC_CACHE_DEBUG |
---|
699 | struct netconfig *nconf; |
---|
700 | char *uaddr; |
---|
701 | #endif |
---|
702 | |
---|
703 | mutex_lock(&dupreq_lock); |
---|
704 | loc = CACHE_LOC(xprt, su->su_xid); |
---|
705 | for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) { |
---|
706 | if (ent->cache_xid == su->su_xid && |
---|
707 | ent->cache_proc == msg->rm_call.cb_proc && |
---|
708 | ent->cache_vers == msg->rm_call.cb_vers && |
---|
709 | ent->cache_prog == msg->rm_call.cb_prog && |
---|
710 | ent->cache_addr.len == xprt->xp_rtaddr.len && |
---|
711 | (memcmp(ent->cache_addr.buf, xprt->xp_rtaddr.buf, |
---|
712 | xprt->xp_rtaddr.len) == 0)) { |
---|
713 | #ifdef RPC_CACHE_DEBUG |
---|
714 | if (nconf = getnetconfigent(xprt->xp_netid)) { |
---|
715 | uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr); |
---|
716 | freenetconfigent(nconf); |
---|
717 | printf( |
---|
718 | "cache entry found for xid=%x prog=%d vers=%d proc=%d for rmtaddr=%s\n", |
---|
719 | su->su_xid, msg->rm_call.cb_prog, |
---|
720 | msg->rm_call.cb_vers, |
---|
721 | msg->rm_call.cb_proc, uaddr); |
---|
722 | free(uaddr); |
---|
723 | } |
---|
724 | #endif |
---|
725 | *replyp = ent->cache_reply; |
---|
726 | *replylenp = ent->cache_replylen; |
---|
727 | mutex_unlock(&dupreq_lock); |
---|
728 | return (1); |
---|
729 | } |
---|
730 | } |
---|
731 | /* |
---|
732 | * Failed to find entry |
---|
733 | * Remember a few things so we can do a set later |
---|
734 | */ |
---|
735 | uc->uc_proc = msg->rm_call.cb_proc; |
---|
736 | uc->uc_vers = msg->rm_call.cb_vers; |
---|
737 | uc->uc_prog = msg->rm_call.cb_prog; |
---|
738 | mutex_unlock(&dupreq_lock); |
---|
739 | return (0); |
---|
740 | } |
---|