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