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