xref: /freebsd/lib/libc/xdr/xdr.c (revision e627b39baccd1ec9129690167cf5e6d860509655)
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: 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  */
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(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  */
82 bool_t
83 xdr_void(/* xdrs, addr */)
84 	/* XDR *xdrs; */
85 	/* caddr_t addr; */
86 {
87 
88 	return (TRUE);
89 }
90 
91 /*
92  * XDR integers
93  */
94 bool_t
95 xdr_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  */
115 bool_t
116 xdr_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  */
137 bool_t
138 xdr_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  */
159 bool_t
160 xdr_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  */
177 bool_t
178 xdr_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  */
206 bool_t
207 xdr_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  */
236 bool_t
237 xdr_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  */
254 bool_t
255 xdr_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  */
272 bool_t
273 xdr_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  */
301 bool_t
302 xdr_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  */
330 bool_t
331 xdr_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  */
382 bool_t
383 xdr_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  */
437 bool_t
438 xdr_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  */
457 bool_t
458 xdr_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  */
506 bool_t
507 xdr_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  */
570 bool_t
571 xdr_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