xdr.c revision 22993
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";*/
33static 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 */
63static 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 */
69void
70xdr_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 */
83bool_t
84xdr_void(/* xdrs, addr */)
85	/* XDR *xdrs; */
86	/* caddr_t addr; */
87{
88
89	return (TRUE);
90}
91
92
93/*
94 * XDR integers
95 */
96bool_t
97xdr_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 */
125bool_t
126xdr_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 */
156bool_t
157xdr_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 */
177bool_t
178xdr_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 */
198bool_t
199xdr_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 */
228bool_t
229xdr_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 */
258bool_t
259xdr_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 */
287bool_t
288xdr_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 */
317bool_t
318xdr_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 */
346bool_t
347xdr_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 */
376bool_t
377xdr_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 */
394bool_t
395xdr_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 */
412bool_t
413xdr_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 */
441bool_t
442xdr_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 */
473bool_t
474xdr_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 */
525bool_t
526xdr_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 */
580bool_t
581xdr_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 */
600bool_t
601xdr_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 */
649bool_t
650xdr_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 */
713bool_t
714xdr_wrapstring(xdrs, cpp)
715	XDR *xdrs;
716	char **cpp;
717{
718	return xdr_string(xdrs, cpp, LASTUNSIGNED);
719}
720