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