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