xref: /freebsd/lib/libc/xdr/xdr.c (revision 380a989b3223d455375b4fae70fd0b9bdd43bafb)
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 = "$Id: xdr.c,v 1.7 1997/05/28 04:57:30 wpaul Exp $";
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 	int64_t x;
263 
264 	switch (xdrs->x_op) {
265 
266 	case XDR_ENCODE:
267 		return (xdr_opaque(xdrs, (caddr_t)int64_p, sizeof(int64_t)));
268 
269 	case XDR_DECODE:
270 		if (!xdr_opaque(xdrs, (caddr_t)&x, sizeof x)) {
271 			return (FALSE);
272 		}
273 		*int64_p = x;
274 		return (TRUE);
275 
276 	case XDR_FREE:
277 		return (TRUE);
278 	}
279 	return (FALSE);
280 }
281 
282 /*
283  * XDR unsigned 64-bit integers
284  */
285 bool_t
286 xdr_u_int64_t(xdrs, uint64_p)
287 	register XDR *xdrs;
288 	u_int64_t *uint64_p;
289 {
290 	u_int64_t x;
291 
292 	switch (xdrs->x_op) {
293 
294 	case XDR_ENCODE:
295 		return (xdr_opaque(xdrs, (caddr_t)uint64_p, sizeof(u_int64_t)));
296 
297 	case XDR_DECODE:
298 		if (!xdr_opaque(xdrs, (caddr_t)&x, sizeof x)) {
299 			return (FALSE);
300 		}
301 		*uint64_p = x;
302 		return (TRUE);
303 
304 	case XDR_FREE:
305 		return (TRUE);
306 	}
307 	return (FALSE);
308 }
309 
310 
311 /*
312  * XDR short integers
313  */
314 bool_t
315 xdr_short(xdrs, sp)
316 	register XDR *xdrs;
317 	short *sp;
318 {
319 	long l;
320 
321 	switch (xdrs->x_op) {
322 
323 	case XDR_ENCODE:
324 		l = (long) *sp;
325 		return (XDR_PUTLONG(xdrs, &l));
326 
327 	case XDR_DECODE:
328 		if (!XDR_GETLONG(xdrs, &l)) {
329 			return (FALSE);
330 		}
331 		*sp = (short) l;
332 		return (TRUE);
333 
334 	case XDR_FREE:
335 		return (TRUE);
336 	}
337 	return (FALSE);
338 }
339 
340 /*
341  * XDR unsigned short integers
342  */
343 bool_t
344 xdr_u_short(xdrs, usp)
345 	register XDR *xdrs;
346 	u_short *usp;
347 {
348 	u_long l;
349 
350 	switch (xdrs->x_op) {
351 
352 	case XDR_ENCODE:
353 		l = (u_long) *usp;
354 		return (XDR_PUTLONG(xdrs, (long *)&l));
355 
356 	case XDR_DECODE:
357 		if (!XDR_GETLONG(xdrs, (long *)&l)) {
358 			return (FALSE);
359 		}
360 		*usp = (u_short) l;
361 		return (TRUE);
362 
363 	case XDR_FREE:
364 		return (TRUE);
365 	}
366 	return (FALSE);
367 }
368 
369 
370 /*
371  * XDR 16-bit integers
372  */
373 bool_t
374 xdr_int16_t(xdrs, int16_p)
375 	register XDR *xdrs;
376 	int16_t *int16_p;
377 {
378 	long l;
379 
380 	switch (xdrs->x_op) {
381 
382 	case XDR_ENCODE:
383 		l = (long) *int16_p;
384 		return (XDR_PUTLONG(xdrs, &l));
385 
386 	case XDR_DECODE:
387 		if (!XDR_GETLONG(xdrs, &l)) {
388 			return (FALSE);
389 		}
390 		*int16_p = (int16_t) l;
391 		return (TRUE);
392 
393 	case XDR_FREE:
394 		return (TRUE);
395 	}
396 	return (FALSE);
397 }
398 
399 /*
400  * XDR unsigned 16-bit integers
401  */
402 bool_t
403 xdr_u_int16_t(xdrs, u_int16_p)
404 	register XDR *xdrs;
405 	u_int16_t *u_int16_p;
406 {
407 	u_long l;
408 
409 	switch (xdrs->x_op) {
410 
411 	case XDR_ENCODE:
412 		l = (u_long) *u_int16_p;
413 		return (XDR_PUTLONG(xdrs, (long *)&l));
414 
415 	case XDR_DECODE:
416 		if (!XDR_GETLONG(xdrs, (long *)&l)) {
417 			return (FALSE);
418 		}
419 		*u_int16_p = (u_int16_t) l;
420 		return (TRUE);
421 
422 	case XDR_FREE:
423 		return (TRUE);
424 	}
425 	return (FALSE);
426 }
427 
428 
429 /*
430  * XDR a char
431  */
432 bool_t
433 xdr_char(xdrs, cp)
434 	XDR *xdrs;
435 	char *cp;
436 {
437 	int i;
438 
439 	i = (*cp);
440 	if (!xdr_int(xdrs, &i)) {
441 		return (FALSE);
442 	}
443 	*cp = i;
444 	return (TRUE);
445 }
446 
447 /*
448  * XDR an unsigned char
449  */
450 bool_t
451 xdr_u_char(xdrs, cp)
452 	XDR *xdrs;
453 	u_char *cp;
454 {
455 	u_int u;
456 
457 	u = (*cp);
458 	if (!xdr_u_int(xdrs, &u)) {
459 		return (FALSE);
460 	}
461 	*cp = u;
462 	return (TRUE);
463 }
464 
465 /*
466  * XDR booleans
467  */
468 bool_t
469 xdr_bool(xdrs, bp)
470 	register XDR *xdrs;
471 	bool_t *bp;
472 {
473 	long lb;
474 
475 	switch (xdrs->x_op) {
476 
477 	case XDR_ENCODE:
478 		lb = *bp ? XDR_TRUE : XDR_FALSE;
479 		return (XDR_PUTLONG(xdrs, &lb));
480 
481 	case XDR_DECODE:
482 		if (!XDR_GETLONG(xdrs, &lb)) {
483 			return (FALSE);
484 		}
485 		*bp = (lb == XDR_FALSE) ? FALSE : TRUE;
486 		return (TRUE);
487 
488 	case XDR_FREE:
489 		return (TRUE);
490 	}
491 	return (FALSE);
492 }
493 
494 /*
495  * XDR enumerations
496  */
497 bool_t
498 xdr_enum(xdrs, ep)
499 	XDR *xdrs;
500 	enum_t *ep;
501 {
502 #ifndef lint
503 	enum sizecheck { SIZEVAL };	/* used to find the size of an enum */
504 
505 	/*
506 	 * enums are treated as ints
507 	 */
508 	if (sizeof (enum sizecheck) == sizeof (long)) {
509 		return (xdr_long(xdrs, (long *)ep));
510 	} else if (sizeof (enum sizecheck) == sizeof (int)) {
511 		return (xdr_int(xdrs, (int *)ep));
512 	} else if (sizeof (enum sizecheck) == sizeof (short)) {
513 		return (xdr_short(xdrs, (short *)ep));
514 	} else {
515 		return (FALSE);
516 	}
517 #else
518 	(void) (xdr_short(xdrs, (short *)ep));
519 	(void) (xdr_int(xdrs, (int *)ep));
520 	return (xdr_long(xdrs, (long *)ep));
521 #endif
522 }
523 
524 /*
525  * XDR opaque data
526  * Allows the specification of a fixed size sequence of opaque bytes.
527  * cp points to the opaque object and cnt gives the byte length.
528  */
529 bool_t
530 xdr_opaque(xdrs, cp, cnt)
531 	register XDR *xdrs;
532 	caddr_t cp;
533 	register u_int cnt;
534 {
535 	register u_int rndup;
536 	static crud[BYTES_PER_XDR_UNIT];
537 
538 	/*
539 	 * if no data we are done
540 	 */
541 	if (cnt == 0)
542 		return (TRUE);
543 
544 	/*
545 	 * round byte count to full xdr units
546 	 */
547 	rndup = cnt % BYTES_PER_XDR_UNIT;
548 	if (rndup > 0)
549 		rndup = BYTES_PER_XDR_UNIT - rndup;
550 
551 	if (xdrs->x_op == XDR_DECODE) {
552 		if (!XDR_GETBYTES(xdrs, cp, cnt)) {
553 			return (FALSE);
554 		}
555 		if (rndup == 0)
556 			return (TRUE);
557 		return (XDR_GETBYTES(xdrs, (caddr_t)crud, rndup));
558 	}
559 
560 	if (xdrs->x_op == XDR_ENCODE) {
561 		if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
562 			return (FALSE);
563 		}
564 		if (rndup == 0)
565 			return (TRUE);
566 		return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
567 	}
568 
569 	if (xdrs->x_op == XDR_FREE) {
570 		return (TRUE);
571 	}
572 
573 	return (FALSE);
574 }
575 
576 /*
577  * XDR counted bytes
578  * *cpp is a pointer to the bytes, *sizep is the count.
579  * If *cpp is NULL maxsize bytes are allocated
580  */
581 bool_t
582 xdr_bytes(xdrs, cpp, sizep, maxsize)
583 	register XDR *xdrs;
584 	char **cpp;
585 	register u_int *sizep;
586 	u_int maxsize;
587 {
588 	register char *sp = *cpp;  /* sp is the actual string pointer */
589 	register u_int nodesize;
590 
591 	/*
592 	 * first deal with the length since xdr bytes are counted
593 	 */
594 	if (! xdr_u_int(xdrs, sizep)) {
595 		return (FALSE);
596 	}
597 	nodesize = *sizep;
598 	if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
599 		return (FALSE);
600 	}
601 
602 	/*
603 	 * now deal with the actual bytes
604 	 */
605 	switch (xdrs->x_op) {
606 
607 	case XDR_DECODE:
608 		if (nodesize == 0) {
609 			return (TRUE);
610 		}
611 		if (sp == NULL) {
612 			*cpp = sp = (char *)mem_alloc(nodesize);
613 		}
614 		if (sp == NULL) {
615 			(void) fprintf(stderr, "xdr_bytes: out of memory\n");
616 			return (FALSE);
617 		}
618 		/* fall into ... */
619 
620 	case XDR_ENCODE:
621 		return (xdr_opaque(xdrs, sp, nodesize));
622 
623 	case XDR_FREE:
624 		if (sp != NULL) {
625 			mem_free(sp, nodesize);
626 			*cpp = NULL;
627 		}
628 		return (TRUE);
629 	}
630 	return (FALSE);
631 }
632 
633 /*
634  * Implemented here due to commonality of the object.
635  */
636 bool_t
637 xdr_netobj(xdrs, np)
638 	XDR *xdrs;
639 	struct netobj *np;
640 {
641 
642 	return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
643 }
644 
645 /*
646  * XDR a descriminated union
647  * Support routine for discriminated unions.
648  * You create an array of xdrdiscrim structures, terminated with
649  * an entry with a null procedure pointer.  The routine gets
650  * the discriminant value and then searches the array of xdrdiscrims
651  * looking for that value.  It calls the procedure given in the xdrdiscrim
652  * to handle the discriminant.  If there is no specific routine a default
653  * routine may be called.
654  * If there is no specific or default routine an error is returned.
655  */
656 bool_t
657 xdr_union(xdrs, dscmp, unp, choices, dfault)
658 	register XDR *xdrs;
659 	enum_t *dscmp;		/* enum to decide which arm to work on */
660 	char *unp;		/* the union itself */
661 	struct xdr_discrim *choices;	/* [value, xdr proc] for each arm */
662 	xdrproc_t dfault;	/* default xdr routine */
663 {
664 	register enum_t dscm;
665 
666 	/*
667 	 * we deal with the discriminator;  it's an enum
668 	 */
669 	if (! xdr_enum(xdrs, dscmp)) {
670 		return (FALSE);
671 	}
672 	dscm = *dscmp;
673 
674 	/*
675 	 * search choices for a value that matches the discriminator.
676 	 * if we find one, execute the xdr routine for that value.
677 	 */
678 	for (; choices->proc != NULL_xdrproc_t; choices++) {
679 		if (choices->value == dscm)
680 			return ((*(choices->proc))(xdrs, unp, LASTUNSIGNED));
681 	}
682 
683 	/*
684 	 * no match - execute the default xdr routine if there is one
685 	 */
686 	return ((dfault == NULL_xdrproc_t) ? FALSE :
687 	    (*dfault)(xdrs, unp, LASTUNSIGNED));
688 }
689 
690 
691 /*
692  * Non-portable xdr primitives.
693  * Care should be taken when moving these routines to new architectures.
694  */
695 
696 
697 /*
698  * XDR null terminated ASCII strings
699  * xdr_string deals with "C strings" - arrays of bytes that are
700  * terminated by a NULL character.  The parameter cpp references a
701  * pointer to storage; If the pointer is null, then the necessary
702  * storage is allocated.  The last parameter is the max allowed length
703  * of the string as specified by a protocol.
704  */
705 bool_t
706 xdr_string(xdrs, cpp, maxsize)
707 	register XDR *xdrs;
708 	char **cpp;
709 	u_int maxsize;
710 {
711 	register char *sp = *cpp;  /* sp is the actual string pointer */
712 	u_int size;
713 	u_int nodesize;
714 
715 	/*
716 	 * first deal with the length since xdr strings are counted-strings
717 	 */
718 	switch (xdrs->x_op) {
719 	case XDR_FREE:
720 		if (sp == NULL) {
721 			return(TRUE);	/* already free */
722 		}
723 		/* fall through... */
724 	case XDR_ENCODE:
725 		size = strlen(sp);
726 		break;
727 	}
728 	if (! xdr_u_int(xdrs, &size)) {
729 		return (FALSE);
730 	}
731 	if (size > maxsize) {
732 		return (FALSE);
733 	}
734 	nodesize = size + 1;
735 
736 	/*
737 	 * now deal with the actual bytes
738 	 */
739 	switch (xdrs->x_op) {
740 
741 	case XDR_DECODE:
742 		if (nodesize == 0) {
743 			return (TRUE);
744 		}
745 		if (sp == NULL)
746 			*cpp = sp = (char *)mem_alloc(nodesize);
747 		if (sp == NULL) {
748 			(void) fprintf(stderr, "xdr_string: out of memory\n");
749 			return (FALSE);
750 		}
751 		sp[size] = 0;
752 		/* fall into ... */
753 
754 	case XDR_ENCODE:
755 		return (xdr_opaque(xdrs, sp, size));
756 
757 	case XDR_FREE:
758 		mem_free(sp, nodesize);
759 		*cpp = NULL;
760 		return (TRUE);
761 	}
762 	return (FALSE);
763 }
764 
765 /*
766  * Wrapper for xdr_string that can be called directly from
767  * routines like clnt_call
768  */
769 bool_t
770 xdr_wrapstring(xdrs, cpp)
771 	XDR *xdrs;
772 	char **cpp;
773 {
774 	return xdr_string(xdrs, cpp, LASTUNSIGNED);
775 }
776