xdr.c revision 11669
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: xdr.c,v 1.2 1995/05/30 05:42:03 rgrimes 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
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 */
62static 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 */
68void
69xdr_free(proc, objp)
70	xdrproc_t proc;
71	char *objp;
72{
73	XDR x;
74
75	x.x_op = XDR_FREE;
76	(*proc)(&x, objp);
77}
78
79/*
80 * XDR nothing
81 */
82bool_t
83xdr_void(/* xdrs, addr */)
84	/* XDR *xdrs; */
85	/* caddr_t addr; */
86{
87
88	return (TRUE);
89}
90
91/*
92 * XDR integers
93 */
94bool_t
95xdr_int(xdrs, ip)
96	XDR *xdrs;
97	int *ip;
98{
99
100#ifdef lint
101	(void) (xdr_short(xdrs, (short *)ip));
102	return (xdr_long(xdrs, (long *)ip));
103#else
104	if (sizeof (int) == sizeof (long)) {
105		return (xdr_long(xdrs, (long *)ip));
106	} else {
107		return (xdr_short(xdrs, (short *)ip));
108	}
109#endif
110}
111
112/*
113 * XDR unsigned integers
114 */
115bool_t
116xdr_u_int(xdrs, up)
117	XDR *xdrs;
118	u_int *up;
119{
120
121#ifdef lint
122	(void) (xdr_short(xdrs, (short *)up));
123	return (xdr_u_long(xdrs, (u_long *)up));
124#else
125	if (sizeof (u_int) == sizeof (u_long)) {
126		return (xdr_u_long(xdrs, (u_long *)up));
127	} else {
128		return (xdr_short(xdrs, (short *)up));
129	}
130#endif
131}
132
133/*
134 * XDR long integers
135 * same as xdr_u_long - open coded to save a proc call!
136 */
137bool_t
138xdr_long(xdrs, lp)
139	register XDR *xdrs;
140	long *lp;
141{
142
143	if (xdrs->x_op == XDR_ENCODE)
144		return (XDR_PUTLONG(xdrs, lp));
145
146	if (xdrs->x_op == XDR_DECODE)
147		return (XDR_GETLONG(xdrs, lp));
148
149	if (xdrs->x_op == XDR_FREE)
150		return (TRUE);
151
152	return (FALSE);
153}
154
155/*
156 * XDR unsigned long integers
157 * same as xdr_long - open coded to save a proc call!
158 */
159bool_t
160xdr_u_long(xdrs, ulp)
161	register XDR *xdrs;
162	u_long *ulp;
163{
164
165	if (xdrs->x_op == XDR_DECODE)
166		return (XDR_GETLONG(xdrs, (long *)ulp));
167	if (xdrs->x_op == XDR_ENCODE)
168		return (XDR_PUTLONG(xdrs, (long *)ulp));
169	if (xdrs->x_op == XDR_FREE)
170		return (TRUE);
171	return (FALSE);
172}
173
174/*
175 * XDR short integers
176 */
177bool_t
178xdr_short(xdrs, sp)
179	register XDR *xdrs;
180	short *sp;
181{
182	long l;
183
184	switch (xdrs->x_op) {
185
186	case XDR_ENCODE:
187		l = (long) *sp;
188		return (XDR_PUTLONG(xdrs, &l));
189
190	case XDR_DECODE:
191		if (!XDR_GETLONG(xdrs, &l)) {
192			return (FALSE);
193		}
194		*sp = (short) l;
195		return (TRUE);
196
197	case XDR_FREE:
198		return (TRUE);
199	}
200	return (FALSE);
201}
202
203/*
204 * XDR unsigned short integers
205 */
206bool_t
207xdr_u_short(xdrs, usp)
208	register XDR *xdrs;
209	u_short *usp;
210{
211	u_long l;
212
213	switch (xdrs->x_op) {
214
215	case XDR_ENCODE:
216		l = (u_long) *usp;
217		return (XDR_PUTLONG(xdrs, &l));
218
219	case XDR_DECODE:
220		if (!XDR_GETLONG(xdrs, &l)) {
221			return (FALSE);
222		}
223		*usp = (u_short) l;
224		return (TRUE);
225
226	case XDR_FREE:
227		return (TRUE);
228	}
229	return (FALSE);
230}
231
232
233/*
234 * XDR a char
235 */
236bool_t
237xdr_char(xdrs, cp)
238	XDR *xdrs;
239	char *cp;
240{
241	int i;
242
243	i = (*cp);
244	if (!xdr_int(xdrs, &i)) {
245		return (FALSE);
246	}
247	*cp = i;
248	return (TRUE);
249}
250
251/*
252 * XDR an unsigned char
253 */
254bool_t
255xdr_u_char(xdrs, cp)
256	XDR *xdrs;
257	char *cp;
258{
259	u_int u;
260
261	u = (*cp);
262	if (!xdr_u_int(xdrs, &u)) {
263		return (FALSE);
264	}
265	*cp = u;
266	return (TRUE);
267}
268
269/*
270 * XDR booleans
271 */
272bool_t
273xdr_bool(xdrs, bp)
274	register XDR *xdrs;
275	bool_t *bp;
276{
277	long lb;
278
279	switch (xdrs->x_op) {
280
281	case XDR_ENCODE:
282		lb = *bp ? XDR_TRUE : XDR_FALSE;
283		return (XDR_PUTLONG(xdrs, &lb));
284
285	case XDR_DECODE:
286		if (!XDR_GETLONG(xdrs, &lb)) {
287			return (FALSE);
288		}
289		*bp = (lb == XDR_FALSE) ? FALSE : TRUE;
290		return (TRUE);
291
292	case XDR_FREE:
293		return (TRUE);
294	}
295	return (FALSE);
296}
297
298/*
299 * XDR enumerations
300 */
301bool_t
302xdr_enum(xdrs, ep)
303	XDR *xdrs;
304	enum_t *ep;
305{
306#ifndef lint
307	enum sizecheck { SIZEVAL };	/* used to find the size of an enum */
308
309	/*
310	 * enums are treated as ints
311	 */
312	if (sizeof (enum sizecheck) == sizeof (long)) {
313		return (xdr_long(xdrs, (long *)ep));
314	} else if (sizeof (enum sizecheck) == sizeof (short)) {
315		return (xdr_short(xdrs, (short *)ep));
316	} else {
317		return (FALSE);
318	}
319#else
320	(void) (xdr_short(xdrs, (short *)ep));
321	return (xdr_long(xdrs, (long *)ep));
322#endif
323}
324
325/*
326 * XDR opaque data
327 * Allows the specification of a fixed size sequence of opaque bytes.
328 * cp points to the opaque object and cnt gives the byte length.
329 */
330bool_t
331xdr_opaque(xdrs, cp, cnt)
332	register XDR *xdrs;
333	caddr_t cp;
334	register u_int cnt;
335{
336	register u_int rndup;
337	static crud[BYTES_PER_XDR_UNIT];
338
339	/*
340	 * if no data we are done
341	 */
342	if (cnt == 0)
343		return (TRUE);
344
345	/*
346	 * round byte count to full xdr units
347	 */
348	rndup = cnt % BYTES_PER_XDR_UNIT;
349	if (rndup > 0)
350		rndup = BYTES_PER_XDR_UNIT - rndup;
351
352	if (xdrs->x_op == XDR_DECODE) {
353		if (!XDR_GETBYTES(xdrs, cp, cnt)) {
354			return (FALSE);
355		}
356		if (rndup == 0)
357			return (TRUE);
358		return (XDR_GETBYTES(xdrs, crud, rndup));
359	}
360
361	if (xdrs->x_op == XDR_ENCODE) {
362		if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
363			return (FALSE);
364		}
365		if (rndup == 0)
366			return (TRUE);
367		return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
368	}
369
370	if (xdrs->x_op == XDR_FREE) {
371		return (TRUE);
372	}
373
374	return (FALSE);
375}
376
377/*
378 * XDR counted bytes
379 * *cpp is a pointer to the bytes, *sizep is the count.
380 * If *cpp is NULL maxsize bytes are allocated
381 */
382bool_t
383xdr_bytes(xdrs, cpp, sizep, maxsize)
384	register XDR *xdrs;
385	char **cpp;
386	register u_int *sizep;
387	u_int maxsize;
388{
389	register char *sp = *cpp;  /* sp is the actual string pointer */
390	register u_int nodesize;
391
392	/*
393	 * first deal with the length since xdr bytes are counted
394	 */
395	if (! xdr_u_int(xdrs, sizep)) {
396		return (FALSE);
397	}
398	nodesize = *sizep;
399	if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
400		return (FALSE);
401	}
402
403	/*
404	 * now deal with the actual bytes
405	 */
406	switch (xdrs->x_op) {
407
408	case XDR_DECODE:
409		if (nodesize == 0) {
410			return (TRUE);
411		}
412		if (sp == NULL) {
413			*cpp = sp = (char *)mem_alloc(nodesize);
414		}
415		if (sp == NULL) {
416			(void) fprintf(stderr, "xdr_bytes: out of memory\n");
417			return (FALSE);
418		}
419		/* fall into ... */
420
421	case XDR_ENCODE:
422		return (xdr_opaque(xdrs, sp, nodesize));
423
424	case XDR_FREE:
425		if (sp != NULL) {
426			mem_free(sp, nodesize);
427			*cpp = NULL;
428		}
429		return (TRUE);
430	}
431	return (FALSE);
432}
433
434/*
435 * Implemented here due to commonality of the object.
436 */
437bool_t
438xdr_netobj(xdrs, np)
439	XDR *xdrs;
440	struct netobj *np;
441{
442
443	return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
444}
445
446/*
447 * XDR a descriminated union
448 * Support routine for discriminated unions.
449 * You create an array of xdrdiscrim structures, terminated with
450 * an entry with a null procedure pointer.  The routine gets
451 * the discriminant value and then searches the array of xdrdiscrims
452 * looking for that value.  It calls the procedure given in the xdrdiscrim
453 * to handle the discriminant.  If there is no specific routine a default
454 * routine may be called.
455 * If there is no specific or default routine an error is returned.
456 */
457bool_t
458xdr_union(xdrs, dscmp, unp, choices, dfault)
459	register XDR *xdrs;
460	enum_t *dscmp;		/* enum to decide which arm to work on */
461	char *unp;		/* the union itself */
462	struct xdr_discrim *choices;	/* [value, xdr proc] for each arm */
463	xdrproc_t dfault;	/* default xdr routine */
464{
465	register enum_t dscm;
466
467	/*
468	 * we deal with the discriminator;  it's an enum
469	 */
470	if (! xdr_enum(xdrs, dscmp)) {
471		return (FALSE);
472	}
473	dscm = *dscmp;
474
475	/*
476	 * search choices for a value that matches the discriminator.
477	 * if we find one, execute the xdr routine for that value.
478	 */
479	for (; choices->proc != NULL_xdrproc_t; choices++) {
480		if (choices->value == dscm)
481			return ((*(choices->proc))(xdrs, unp, LASTUNSIGNED));
482	}
483
484	/*
485	 * no match - execute the default xdr routine if there is one
486	 */
487	return ((dfault == NULL_xdrproc_t) ? FALSE :
488	    (*dfault)(xdrs, unp, LASTUNSIGNED));
489}
490
491
492/*
493 * Non-portable xdr primitives.
494 * Care should be taken when moving these routines to new architectures.
495 */
496
497
498/*
499 * XDR null terminated ASCII strings
500 * xdr_string deals with "C strings" - arrays of bytes that are
501 * terminated by a NULL character.  The parameter cpp references a
502 * pointer to storage; If the pointer is null, then the necessary
503 * storage is allocated.  The last parameter is the max allowed length
504 * of the string as specified by a protocol.
505 */
506bool_t
507xdr_string(xdrs, cpp, maxsize)
508	register XDR *xdrs;
509	char **cpp;
510	u_int maxsize;
511{
512	register char *sp = *cpp;  /* sp is the actual string pointer */
513	u_int size;
514	u_int nodesize;
515
516	/*
517	 * first deal with the length since xdr strings are counted-strings
518	 */
519	switch (xdrs->x_op) {
520	case XDR_FREE:
521		if (sp == NULL) {
522			return(TRUE);	/* already free */
523		}
524		/* fall through... */
525	case XDR_ENCODE:
526		size = strlen(sp);
527		break;
528	}
529	if (! xdr_u_int(xdrs, &size)) {
530		return (FALSE);
531	}
532	if (size > maxsize) {
533		return (FALSE);
534	}
535	nodesize = size + 1;
536
537	/*
538	 * now deal with the actual bytes
539	 */
540	switch (xdrs->x_op) {
541
542	case XDR_DECODE:
543		if (nodesize == 0) {
544			return (TRUE);
545		}
546		if (sp == NULL)
547			*cpp = sp = (char *)mem_alloc(nodesize);
548		if (sp == NULL) {
549			(void) fprintf(stderr, "xdr_string: out of memory\n");
550			return (FALSE);
551		}
552		sp[size] = 0;
553		/* fall into ... */
554
555	case XDR_ENCODE:
556		return (xdr_opaque(xdrs, sp, size));
557
558	case XDR_FREE:
559		mem_free(sp, nodesize);
560		*cpp = NULL;
561		return (TRUE);
562	}
563	return (FALSE);
564}
565
566/*
567 * Wrapper for xdr_string that can be called directly from
568 * routines like clnt_call
569 */
570bool_t
571xdr_wrapstring(xdrs, cpp)
572	XDR *xdrs;
573	char **cpp;
574{
575	if (xdr_string(xdrs, cpp, LASTUNSIGNED)) {
576		return (TRUE);
577	}
578	return (FALSE);
579}
580