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