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