FreeBSD/Linux Kernel Cross Reference
sys/xdr/xdr.c
1 /* $NetBSD: xdr.c,v 1.22 2000/07/06 03:10:35 christos Exp $ */
2
3 /*
4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5 * unrestricted use provided that this legend is included on all tape
6 * media and as a part of the software program in whole or part. Users
7 * may copy or modify Sun RPC without charge, but are not authorized
8 * to license or distribute it to anyone else except as part of a product or
9 * program developed by the user.
10 *
11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14 *
15 * Sun RPC is provided with no support and without any obligation on the
16 * part of Sun Microsystems, Inc. to assist in its use, correction,
17 * modification or enhancement.
18 *
19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21 * OR ANY PART THEREOF.
22 *
23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24 * or profits or other special, indirect and consequential damages, even if
25 * Sun has been advised of the possibility of such damages.
26 *
27 * Sun Microsystems, Inc.
28 * 2550 Garcia Avenue
29 * Mountain View, California 94043
30 */
31
32 #if defined(LIBC_SCCS) && !defined(lint)
33 static char *sccsid2 = "@(#)xdr.c 1.35 87/08/12";
34 static char *sccsid = "@(#)xdr.c 2.1 88/07/29 4.0 RPCSRC";
35 #endif
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 /*
40 * xdr.c, Generic XDR routines implementation.
41 *
42 * Copyright (C) 1986, Sun Microsystems, Inc.
43 *
44 * These are the "generic" xdr routines used to serialize and de-serialize
45 * most common data items. See xdr.h for more info on the interface to
46 * xdr.
47 */
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/kernel.h>
52 #include <sys/malloc.h>
53 #include <sys/module.h>
54
55 #include <rpc/rpc.h>
56 #include <rpc/rpc_com.h>
57 #include <rpc/types.h>
58 #include <rpc/xdr.h>
59
60 typedef quad_t longlong_t; /* ANSI long long type */
61 typedef u_quad_t u_longlong_t; /* ANSI unsigned long long type */
62
63 /*
64 * constants specific to the xdr "protocol"
65 */
66 #define XDR_FALSE ((long) 0)
67 #define XDR_TRUE ((long) 1)
68
69 MALLOC_DEFINE(M_RPC, "rpc", "Remote Procedure Call");
70
71 /*
72 * for unit alignment
73 */
74 static const char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 };
75
76 /*
77 * Free a data structure using XDR
78 * Not a filter, but a convenient utility nonetheless
79 */
80 void
81 xdr_free(xdrproc_t proc, void *objp)
82 {
83 XDR x;
84
85 x.x_op = XDR_FREE;
86 (*proc)(&x, objp);
87 }
88
89 /*
90 * XDR nothing
91 */
92 bool_t
93 xdr_void(void)
94 {
95
96 return (TRUE);
97 }
98
99 /*
100 * XDR integers
101 */
102 bool_t
103 xdr_int(XDR *xdrs, int *ip)
104 {
105 long l;
106
107 switch (xdrs->x_op) {
108 case XDR_ENCODE:
109 l = (long) *ip;
110 return (XDR_PUTLONG(xdrs, &l));
111
112 case XDR_DECODE:
113 if (!XDR_GETLONG(xdrs, &l)) {
114 return (FALSE);
115 }
116 *ip = (int) l;
117 return (TRUE);
118
119 case XDR_FREE:
120 return (TRUE);
121 }
122 /* NOTREACHED */
123 return (FALSE);
124 }
125
126 /*
127 * XDR unsigned integers
128 */
129 bool_t
130 xdr_u_int(XDR *xdrs, u_int *up)
131 {
132 u_long l;
133
134 switch (xdrs->x_op) {
135 case XDR_ENCODE:
136 l = (u_long) *up;
137 return (XDR_PUTLONG(xdrs, (long *)&l));
138
139 case XDR_DECODE:
140 if (!XDR_GETLONG(xdrs, (long *)&l)) {
141 return (FALSE);
142 }
143 *up = (u_int) l;
144 return (TRUE);
145
146 case XDR_FREE:
147 return (TRUE);
148 }
149 /* NOTREACHED */
150 return (FALSE);
151 }
152
153 /*
154 * XDR long integers
155 * same as xdr_u_long - open coded to save a proc call!
156 */
157 bool_t
158 xdr_long(XDR *xdrs, long *lp)
159 {
160 switch (xdrs->x_op) {
161 case XDR_ENCODE:
162 return (XDR_PUTLONG(xdrs, lp));
163 case XDR_DECODE:
164 return (XDR_GETLONG(xdrs, lp));
165 case XDR_FREE:
166 return (TRUE);
167 }
168 /* NOTREACHED */
169 return (FALSE);
170 }
171
172 /*
173 * XDR unsigned long integers
174 * same as xdr_long - open coded to save a proc call!
175 */
176 bool_t
177 xdr_u_long(XDR *xdrs, u_long *ulp)
178 {
179 switch (xdrs->x_op) {
180 case XDR_ENCODE:
181 return (XDR_PUTLONG(xdrs, (long *)ulp));
182 case XDR_DECODE:
183 return (XDR_GETLONG(xdrs, (long *)ulp));
184 case XDR_FREE:
185 return (TRUE);
186 }
187 /* NOTREACHED */
188 return (FALSE);
189 }
190
191 /*
192 * XDR 32-bit integers
193 * same as xdr_uint32_t - open coded to save a proc call!
194 */
195 bool_t
196 xdr_int32_t(XDR *xdrs, int32_t *int32_p)
197 {
198 long l;
199
200 switch (xdrs->x_op) {
201 case XDR_ENCODE:
202 l = (long) *int32_p;
203 return (XDR_PUTLONG(xdrs, &l));
204
205 case XDR_DECODE:
206 if (!XDR_GETLONG(xdrs, &l)) {
207 return (FALSE);
208 }
209 *int32_p = (int32_t) l;
210 return (TRUE);
211
212 case XDR_FREE:
213 return (TRUE);
214 }
215 /* NOTREACHED */
216 return (FALSE);
217 }
218
219 /*
220 * XDR unsigned 32-bit integers
221 * same as xdr_int32_t - open coded to save a proc call!
222 */
223 bool_t
224 xdr_uint32_t(XDR *xdrs, uint32_t *uint32_p)
225 {
226 u_long l;
227
228 switch (xdrs->x_op) {
229 case XDR_ENCODE:
230 l = (u_long) *uint32_p;
231 return (XDR_PUTLONG(xdrs, (long *)&l));
232
233 case XDR_DECODE:
234 if (!XDR_GETLONG(xdrs, (long *)&l)) {
235 return (FALSE);
236 }
237 *uint32_p = (uint32_t) l;
238 return (TRUE);
239
240 case XDR_FREE:
241 return (TRUE);
242 }
243 /* NOTREACHED */
244 return (FALSE);
245 }
246
247 /*
248 * XDR short integers
249 */
250 bool_t
251 xdr_short(XDR *xdrs, short *sp)
252 {
253 long l;
254
255 switch (xdrs->x_op) {
256 case XDR_ENCODE:
257 l = (long) *sp;
258 return (XDR_PUTLONG(xdrs, &l));
259
260 case XDR_DECODE:
261 if (!XDR_GETLONG(xdrs, &l)) {
262 return (FALSE);
263 }
264 *sp = (short) l;
265 return (TRUE);
266
267 case XDR_FREE:
268 return (TRUE);
269 }
270 /* NOTREACHED */
271 return (FALSE);
272 }
273
274 /*
275 * XDR unsigned short integers
276 */
277 bool_t
278 xdr_u_short(XDR *xdrs, u_short *usp)
279 {
280 u_long l;
281
282 switch (xdrs->x_op) {
283 case XDR_ENCODE:
284 l = (u_long) *usp;
285 return (XDR_PUTLONG(xdrs, (long *)&l));
286
287 case XDR_DECODE:
288 if (!XDR_GETLONG(xdrs, (long *)&l)) {
289 return (FALSE);
290 }
291 *usp = (u_short) l;
292 return (TRUE);
293
294 case XDR_FREE:
295 return (TRUE);
296 }
297 /* NOTREACHED */
298 return (FALSE);
299 }
300
301 /*
302 * XDR 16-bit integers
303 */
304 bool_t
305 xdr_int16_t(XDR *xdrs, int16_t *int16_p)
306 {
307 long l;
308
309 switch (xdrs->x_op) {
310 case XDR_ENCODE:
311 l = (long) *int16_p;
312 return (XDR_PUTLONG(xdrs, &l));
313
314 case XDR_DECODE:
315 if (!XDR_GETLONG(xdrs, &l)) {
316 return (FALSE);
317 }
318 *int16_p = (int16_t) l;
319 return (TRUE);
320
321 case XDR_FREE:
322 return (TRUE);
323 }
324 /* NOTREACHED */
325 return (FALSE);
326 }
327
328 /*
329 * XDR unsigned 16-bit integers
330 */
331 bool_t
332 xdr_uint16_t(XDR *xdrs, uint16_t *uint16_p)
333 {
334 u_long l;
335
336 switch (xdrs->x_op) {
337 case XDR_ENCODE:
338 l = (u_long) *uint16_p;
339 return (XDR_PUTLONG(xdrs, (long *)&l));
340
341 case XDR_DECODE:
342 if (!XDR_GETLONG(xdrs, (long *)&l)) {
343 return (FALSE);
344 }
345 *uint16_p = (uint16_t) l;
346 return (TRUE);
347
348 case XDR_FREE:
349 return (TRUE);
350 }
351 /* NOTREACHED */
352 return (FALSE);
353 }
354
355 /*
356 * XDR a char
357 */
358 bool_t
359 xdr_char(XDR *xdrs, char *cp)
360 {
361 int i;
362
363 i = (*cp);
364 if (!xdr_int(xdrs, &i)) {
365 return (FALSE);
366 }
367 *cp = i;
368 return (TRUE);
369 }
370
371 /*
372 * XDR an unsigned char
373 */
374 bool_t
375 xdr_u_char(XDR *xdrs, u_char *cp)
376 {
377 u_int u;
378
379 u = (*cp);
380 if (!xdr_u_int(xdrs, &u)) {
381 return (FALSE);
382 }
383 *cp = u;
384 return (TRUE);
385 }
386
387 /*
388 * XDR booleans
389 */
390 bool_t
391 xdr_bool(XDR *xdrs, bool_t *bp)
392 {
393 long lb;
394
395 switch (xdrs->x_op) {
396 case XDR_ENCODE:
397 lb = *bp ? XDR_TRUE : XDR_FALSE;
398 return (XDR_PUTLONG(xdrs, &lb));
399
400 case XDR_DECODE:
401 if (!XDR_GETLONG(xdrs, &lb)) {
402 return (FALSE);
403 }
404 *bp = (lb == XDR_FALSE) ? FALSE : TRUE;
405 return (TRUE);
406
407 case XDR_FREE:
408 return (TRUE);
409 }
410 /* NOTREACHED */
411 return (FALSE);
412 }
413
414 /*
415 * XDR enumerations
416 */
417 bool_t
418 xdr_enum(XDR *xdrs, enum_t *ep)
419 {
420 enum sizecheck { SIZEVAL }; /* used to find the size of an enum */
421
422 /*
423 * enums are treated as ints
424 */
425 /* LINTED */ if (sizeof (enum sizecheck) == sizeof (long)) {
426 return (xdr_long(xdrs, (long *)(void *)ep));
427 } else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (int)) {
428 return (xdr_int(xdrs, (int *)(void *)ep));
429 } else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (short)) {
430 return (xdr_short(xdrs, (short *)(void *)ep));
431 } else {
432 return (FALSE);
433 }
434 }
435
436 /*
437 * XDR opaque data
438 * Allows the specification of a fixed size sequence of opaque bytes.
439 * cp points to the opaque object and cnt gives the byte length.
440 */
441 bool_t
442 xdr_opaque(XDR *xdrs, caddr_t cp, u_int cnt)
443 {
444 u_int rndup;
445 static int crud[BYTES_PER_XDR_UNIT];
446
447 /*
448 * if no data we are done
449 */
450 if (cnt == 0)
451 return (TRUE);
452
453 /*
454 * round byte count to full xdr units
455 */
456 rndup = cnt % BYTES_PER_XDR_UNIT;
457 if (rndup > 0)
458 rndup = BYTES_PER_XDR_UNIT - rndup;
459
460 if (xdrs->x_op == XDR_DECODE) {
461 if (!XDR_GETBYTES(xdrs, cp, cnt)) {
462 return (FALSE);
463 }
464 if (rndup == 0)
465 return (TRUE);
466 return (XDR_GETBYTES(xdrs, (caddr_t)(void *)crud, rndup));
467 }
468
469 if (xdrs->x_op == XDR_ENCODE) {
470 if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
471 return (FALSE);
472 }
473 if (rndup == 0)
474 return (TRUE);
475 return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
476 }
477
478 if (xdrs->x_op == XDR_FREE) {
479 return (TRUE);
480 }
481
482 return (FALSE);
483 }
484
485 /*
486 * XDR counted bytes
487 * *cpp is a pointer to the bytes, *sizep is the count.
488 * If *cpp is NULL maxsize bytes are allocated
489 */
490 bool_t
491 xdr_bytes(XDR *xdrs, char **cpp, u_int *sizep, u_int maxsize)
492 {
493 char *sp = *cpp; /* sp is the actual string pointer */
494 u_int nodesize;
495 bool_t ret, allocated = FALSE;
496
497 /*
498 * first deal with the length since xdr bytes are counted
499 */
500 if (! xdr_u_int(xdrs, sizep)) {
501 return (FALSE);
502 }
503 nodesize = *sizep;
504 if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
505 return (FALSE);
506 }
507
508 /*
509 * now deal with the actual bytes
510 */
511 switch (xdrs->x_op) {
512 case XDR_DECODE:
513 if (nodesize == 0) {
514 return (TRUE);
515 }
516 if (sp == NULL) {
517 *cpp = sp = mem_alloc(nodesize);
518 allocated = TRUE;
519 }
520 if (sp == NULL) {
521 printf("xdr_bytes: out of memory");
522 return (FALSE);
523 }
524 /* FALLTHROUGH */
525
526 case XDR_ENCODE:
527 ret = xdr_opaque(xdrs, sp, nodesize);
528 if ((xdrs->x_op == XDR_DECODE) && (ret == FALSE)) {
529 if (allocated == TRUE) {
530 mem_free(sp, nodesize);
531 *cpp = NULL;
532 }
533 }
534 return (ret);
535
536 case XDR_FREE:
537 if (sp != NULL) {
538 mem_free(sp, nodesize);
539 *cpp = NULL;
540 }
541 return (TRUE);
542 }
543 /* NOTREACHED */
544 return (FALSE);
545 }
546
547 /*
548 * Implemented here due to commonality of the object.
549 */
550 bool_t
551 xdr_netobj(XDR *xdrs, struct netobj *np)
552 {
553
554 return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
555 }
556
557 /*
558 * XDR a descriminated union
559 * Support routine for discriminated unions.
560 * You create an array of xdrdiscrim structures, terminated with
561 * an entry with a null procedure pointer. The routine gets
562 * the discriminant value and then searches the array of xdrdiscrims
563 * looking for that value. It calls the procedure given in the xdrdiscrim
564 * to handle the discriminant. If there is no specific routine a default
565 * routine may be called.
566 * If there is no specific or default routine an error is returned.
567 */
568 bool_t
569 xdr_union(XDR *xdrs,
570 enum_t *dscmp, /* enum to decide which arm to work on */
571 char *unp, /* the union itself */
572 const struct xdr_discrim *choices, /* [value, xdr proc] for each arm */
573 xdrproc_t dfault) /* default xdr routine */
574 {
575 enum_t dscm;
576
577 /*
578 * we deal with the discriminator; it's an enum
579 */
580 if (! xdr_enum(xdrs, dscmp)) {
581 return (FALSE);
582 }
583 dscm = *dscmp;
584
585 /*
586 * search choices for a value that matches the discriminator.
587 * if we find one, execute the xdr routine for that value.
588 */
589 for (; choices->proc != NULL_xdrproc_t; choices++) {
590 if (choices->value == dscm)
591 return ((*(choices->proc))(xdrs, unp));
592 }
593
594 /*
595 * no match - execute the default xdr routine if there is one
596 */
597 return ((dfault == NULL_xdrproc_t) ? FALSE :
598 (*dfault)(xdrs, unp));
599 }
600
601 /*
602 * Non-portable xdr primitives.
603 * Care should be taken when moving these routines to new architectures.
604 */
605
606 /*
607 * XDR null terminated ASCII strings
608 * xdr_string deals with "C strings" - arrays of bytes that are
609 * terminated by a NULL character. The parameter cpp references a
610 * pointer to storage; If the pointer is null, then the necessary
611 * storage is allocated. The last parameter is the max allowed length
612 * of the string as specified by a protocol.
613 */
614 bool_t
615 xdr_string(XDR *xdrs, char **cpp, u_int maxsize)
616 {
617 char *sp = *cpp; /* sp is the actual string pointer */
618 u_int size;
619 u_int nodesize;
620 bool_t ret, allocated = FALSE;
621
622 /*
623 * first deal with the length since xdr strings are counted-strings
624 */
625 switch (xdrs->x_op) {
626 case XDR_FREE:
627 if (sp == NULL) {
628 return(TRUE); /* already free */
629 }
630 /* FALLTHROUGH */
631 case XDR_ENCODE:
632 size = strlen(sp);
633 break;
634 case XDR_DECODE:
635 break;
636 }
637 if (! xdr_u_int(xdrs, &size)) {
638 return (FALSE);
639 }
640 if (size > maxsize) {
641 return (FALSE);
642 }
643 nodesize = size + 1;
644
645 /*
646 * now deal with the actual bytes
647 */
648 switch (xdrs->x_op) {
649 case XDR_DECODE:
650 if (nodesize == 0) {
651 return (TRUE);
652 }
653 if (sp == NULL) {
654 *cpp = sp = mem_alloc(nodesize);
655 allocated = TRUE;
656 }
657 if (sp == NULL) {
658 printf("xdr_string: out of memory");
659 return (FALSE);
660 }
661 sp[size] = 0;
662 /* FALLTHROUGH */
663
664 case XDR_ENCODE:
665 ret = xdr_opaque(xdrs, sp, size);
666 if ((xdrs->x_op == XDR_DECODE) && (ret == FALSE)) {
667 if (allocated == TRUE) {
668 mem_free(sp, nodesize);
669 *cpp = NULL;
670 }
671 }
672 return (ret);
673
674 case XDR_FREE:
675 mem_free(sp, nodesize);
676 *cpp = NULL;
677 return (TRUE);
678 }
679 /* NOTREACHED */
680 return (FALSE);
681 }
682
683 /*
684 * Wrapper for xdr_string that can be called directly from
685 * routines like clnt_call
686 */
687 bool_t
688 xdr_wrapstring(XDR *xdrs, char **cpp)
689 {
690 return xdr_string(xdrs, cpp, RPC_MAXDATASIZE);
691 }
692
693 /*
694 * NOTE: xdr_hyper(), xdr_u_hyper(), xdr_longlong_t(), and xdr_u_longlong_t()
695 * are in the "non-portable" section because they require that a `long long'
696 * be a 64-bit type.
697 *
698 * --thorpej@netbsd.org, November 30, 1999
699 */
700
701 /*
702 * XDR 64-bit integers
703 */
704 bool_t
705 xdr_int64_t(XDR *xdrs, int64_t *llp)
706 {
707 u_long ul[2];
708
709 switch (xdrs->x_op) {
710 case XDR_ENCODE:
711 ul[0] = (u_long)((uint64_t)*llp >> 32) & 0xffffffff;
712 ul[1] = (u_long)((uint64_t)*llp) & 0xffffffff;
713 if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
714 return (FALSE);
715 return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
716 case XDR_DECODE:
717 if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
718 return (FALSE);
719 if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
720 return (FALSE);
721 *llp = (int64_t)
722 (((uint64_t)ul[0] << 32) | ((uint64_t)ul[1]));
723 return (TRUE);
724 case XDR_FREE:
725 return (TRUE);
726 }
727 /* NOTREACHED */
728 return (FALSE);
729 }
730
731 /*
732 * XDR unsigned 64-bit integers
733 */
734 bool_t
735 xdr_uint64_t(XDR *xdrs, uint64_t *ullp)
736 {
737 u_long ul[2];
738
739 switch (xdrs->x_op) {
740 case XDR_ENCODE:
741 ul[0] = (u_long)(*ullp >> 32) & 0xffffffff;
742 ul[1] = (u_long)(*ullp) & 0xffffffff;
743 if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
744 return (FALSE);
745 return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
746 case XDR_DECODE:
747 if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
748 return (FALSE);
749 if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
750 return (FALSE);
751 *ullp = (uint64_t)
752 (((uint64_t)ul[0] << 32) | ((uint64_t)ul[1]));
753 return (TRUE);
754 case XDR_FREE:
755 return (TRUE);
756 }
757 /* NOTREACHED */
758 return (FALSE);
759 }
760
761 /*
762 * XDR hypers
763 */
764 bool_t
765 xdr_hyper(XDR *xdrs, longlong_t *llp)
766 {
767
768 /*
769 * Don't bother open-coding this; it's a fair amount of code. Just
770 * call xdr_int64_t().
771 */
772 return (xdr_int64_t(xdrs, (int64_t *)llp));
773 }
774
775 /*
776 * XDR unsigned hypers
777 */
778 bool_t
779 xdr_u_hyper(XDR *xdrs, u_longlong_t *ullp)
780 {
781
782 /*
783 * Don't bother open-coding this; it's a fair amount of code. Just
784 * call xdr_uint64_t().
785 */
786 return (xdr_uint64_t(xdrs, (uint64_t *)ullp));
787 }
788
789 /*
790 * XDR longlong_t's
791 */
792 bool_t
793 xdr_longlong_t(XDR *xdrs, longlong_t *llp)
794 {
795
796 /*
797 * Don't bother open-coding this; it's a fair amount of code. Just
798 * call xdr_int64_t().
799 */
800 return (xdr_int64_t(xdrs, (int64_t *)llp));
801 }
802
803 /*
804 * XDR u_longlong_t's
805 */
806 bool_t
807 xdr_u_longlong_t(XDR *xdrs, u_longlong_t *ullp)
808 {
809
810 /*
811 * Don't bother open-coding this; it's a fair amount of code. Just
812 * call xdr_uint64_t().
813 */
814 return (xdr_uint64_t(xdrs, (uint64_t *)ullp));
815 }
816
817 /*
818 * Kernel module glue
819 */
820 static int
821 xdr_modevent(module_t mod, int type, void *data)
822 {
823
824 return (0);
825 }
826 static moduledata_t xdr_mod = {
827 "xdr",
828 xdr_modevent,
829 NULL,
830 };
831 DECLARE_MODULE(xdr, xdr_mod, SI_SUB_VFS, SI_ORDER_ANY);
832 MODULE_VERSION(xdr, 1);
Cache object: c2e7c796273bbafe9a0cb3bc52531599
|