xref: /original-bsd/lib/librpc/rpc/xdr.c (revision e59fb703)
1 /* @(#)xdr.c	2.1 88/07/29 4.0 RPCSRC */
2 /*
3  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
4  * unrestricted use provided that this legend is included on all tape
5  * media and as a part of the software program in whole or part.  Users
6  * may copy or modify Sun RPC without charge, but are not authorized
7  * to license or distribute it to anyone else except as part of a product or
8  * program developed by the user.
9  *
10  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
11  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13  *
14  * Sun RPC is provided with no support and without any obligation on the
15  * part of Sun Microsystems, Inc. to assist in its use, correction,
16  * modification or enhancement.
17  *
18  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
19  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
20  * OR ANY PART THEREOF.
21  *
22  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
23  * or profits or other special, indirect and consequential damages, even if
24  * Sun has been advised of the possibility of such damages.
25  *
26  * Sun Microsystems, Inc.
27  * 2550 Garcia Avenue
28  * Mountain View, California  94043
29  */
30 #if !defined(lint) && defined(SCCSIDS)
31 static char sccsid[] = "@(#)xdr.c 1.35 87/08/12";
32 #endif
33 
34 /*
35  * xdr.c, Generic XDR routines implementation.
36  *
37  * Copyright (C) 1986, Sun Microsystems, Inc.
38  *
39  * These are the "generic" xdr routines used to serialize and de-serialize
40  * most common data items.  See xdr.h for more info on the interface to
41  * xdr.
42  */
43 
44 #include <stdio.h>
45 
46 #include <rpc/types.h>
47 #include <rpc/xdr.h>
48 
49 /*
50  * constants specific to the xdr "protocol"
51  */
52 #define XDR_FALSE	((long) 0)
53 #define XDR_TRUE	((long) 1)
54 #define LASTUNSIGNED	((u_int) 0-1)
55 
56 /*
57  * for unit alignment
58  */
59 static char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 };
60 
61 /*
62  * Free a data structure using XDR
63  * Not a filter, but a convenient utility nonetheless
64  */
65 void
66 xdr_free(proc, objp)
67 	xdrproc_t proc;
68 	char *objp;
69 {
70 	XDR x;
71 
72 	x.x_op = XDR_FREE;
73 	(*proc)(&x, objp);
74 }
75 
76 /*
77  * XDR nothing
78  */
79 bool_t
80 xdr_void(/* xdrs, addr */)
81 	/* XDR *xdrs; */
82 	/* caddr_t addr; */
83 {
84 
85 	return (TRUE);
86 }
87 
88 /*
89  * XDR integers
90  */
91 bool_t
92 xdr_int(xdrs, ip)
93 	XDR *xdrs;
94 	int *ip;
95 {
96 
97 #ifdef lint
98 	(void) (xdr_short(xdrs, (short *)ip));
99 	return (xdr_long(xdrs, (long *)ip));
100 #else
101 	if (sizeof (int) == sizeof (long)) {
102 		return (xdr_long(xdrs, (long *)ip));
103 	} else {
104 		return (xdr_short(xdrs, (short *)ip));
105 	}
106 #endif
107 }
108 
109 /*
110  * XDR unsigned integers
111  */
112 bool_t
113 xdr_u_int(xdrs, up)
114 	XDR *xdrs;
115 	u_int *up;
116 {
117 
118 #ifdef lint
119 	(void) (xdr_short(xdrs, (short *)up));
120 	return (xdr_u_long(xdrs, (u_long *)up));
121 #else
122 	if (sizeof (u_int) == sizeof (u_long)) {
123 		return (xdr_u_long(xdrs, (u_long *)up));
124 	} else {
125 		return (xdr_short(xdrs, (short *)up));
126 	}
127 #endif
128 }
129 
130 /*
131  * XDR long integers
132  * same as xdr_u_long - open coded to save a proc call!
133  */
134 bool_t
135 xdr_long(xdrs, lp)
136 	register XDR *xdrs;
137 	long *lp;
138 {
139 
140 	if (xdrs->x_op == XDR_ENCODE)
141 		return (XDR_PUTLONG(xdrs, lp));
142 
143 	if (xdrs->x_op == XDR_DECODE)
144 		return (XDR_GETLONG(xdrs, lp));
145 
146 	if (xdrs->x_op == XDR_FREE)
147 		return (TRUE);
148 
149 	return (FALSE);
150 }
151 
152 /*
153  * XDR unsigned long integers
154  * same as xdr_long - open coded to save a proc call!
155  */
156 bool_t
157 xdr_u_long(xdrs, ulp)
158 	register XDR *xdrs;
159 	u_long *ulp;
160 {
161 
162 	if (xdrs->x_op == XDR_DECODE)
163 		return (XDR_GETLONG(xdrs, (long *)ulp));
164 	if (xdrs->x_op == XDR_ENCODE)
165 		return (XDR_PUTLONG(xdrs, (long *)ulp));
166 	if (xdrs->x_op == XDR_FREE)
167 		return (TRUE);
168 	return (FALSE);
169 }
170 
171 /*
172  * XDR short integers
173  */
174 bool_t
175 xdr_short(xdrs, sp)
176 	register XDR *xdrs;
177 	short *sp;
178 {
179 	long l;
180 
181 	switch (xdrs->x_op) {
182 
183 	case XDR_ENCODE:
184 		l = (long) *sp;
185 		return (XDR_PUTLONG(xdrs, &l));
186 
187 	case XDR_DECODE:
188 		if (!XDR_GETLONG(xdrs, &l)) {
189 			return (FALSE);
190 		}
191 		*sp = (short) l;
192 		return (TRUE);
193 
194 	case XDR_FREE:
195 		return (TRUE);
196 	}
197 	return (FALSE);
198 }
199 
200 /*
201  * XDR unsigned short integers
202  */
203 bool_t
204 xdr_u_short(xdrs, usp)
205 	register XDR *xdrs;
206 	u_short *usp;
207 {
208 	u_long l;
209 
210 	switch (xdrs->x_op) {
211 
212 	case XDR_ENCODE:
213 		l = (u_long) *usp;
214 		return (XDR_PUTLONG(xdrs, &l));
215 
216 	case XDR_DECODE:
217 		if (!XDR_GETLONG(xdrs, &l)) {
218 			return (FALSE);
219 		}
220 		*usp = (u_short) l;
221 		return (TRUE);
222 
223 	case XDR_FREE:
224 		return (TRUE);
225 	}
226 	return (FALSE);
227 }
228 
229 
230 /*
231  * XDR a char
232  */
233 bool_t
234 xdr_char(xdrs, cp)
235 	XDR *xdrs;
236 	char *cp;
237 {
238 	int i;
239 
240 	i = (*cp);
241 	if (!xdr_int(xdrs, &i)) {
242 		return (FALSE);
243 	}
244 	*cp = i;
245 	return (TRUE);
246 }
247 
248 /*
249  * XDR an unsigned char
250  */
251 bool_t
252 xdr_u_char(xdrs, cp)
253 	XDR *xdrs;
254 	char *cp;
255 {
256 	u_int u;
257 
258 	u = (*cp);
259 	if (!xdr_u_int(xdrs, &u)) {
260 		return (FALSE);
261 	}
262 	*cp = u;
263 	return (TRUE);
264 }
265 
266 /*
267  * XDR booleans
268  */
269 bool_t
270 xdr_bool(xdrs, bp)
271 	register XDR *xdrs;
272 	bool_t *bp;
273 {
274 	long lb;
275 
276 	switch (xdrs->x_op) {
277 
278 	case XDR_ENCODE:
279 		lb = *bp ? XDR_TRUE : XDR_FALSE;
280 		return (XDR_PUTLONG(xdrs, &lb));
281 
282 	case XDR_DECODE:
283 		if (!XDR_GETLONG(xdrs, &lb)) {
284 			return (FALSE);
285 		}
286 		*bp = (lb == XDR_FALSE) ? FALSE : TRUE;
287 		return (TRUE);
288 
289 	case XDR_FREE:
290 		return (TRUE);
291 	}
292 	return (FALSE);
293 }
294 
295 /*
296  * XDR enumerations
297  */
298 bool_t
299 xdr_enum(xdrs, ep)
300 	XDR *xdrs;
301 	enum_t *ep;
302 {
303 #ifndef lint
304 	enum sizecheck { SIZEVAL };	/* used to find the size of an enum */
305 
306 	/*
307 	 * enums are treated as ints
308 	 */
309 	if (sizeof (enum sizecheck) == sizeof (long)) {
310 		return (xdr_long(xdrs, (long *)ep));
311 	} else if (sizeof (enum sizecheck) == sizeof (short)) {
312 		return (xdr_short(xdrs, (short *)ep));
313 	} else {
314 		return (FALSE);
315 	}
316 #else
317 	(void) (xdr_short(xdrs, (short *)ep));
318 	return (xdr_long(xdrs, (long *)ep));
319 #endif
320 }
321 
322 /*
323  * XDR opaque data
324  * Allows the specification of a fixed size sequence of opaque bytes.
325  * cp points to the opaque object and cnt gives the byte length.
326  */
327 bool_t
328 xdr_opaque(xdrs, cp, cnt)
329 	register XDR *xdrs;
330 	caddr_t cp;
331 	register u_int cnt;
332 {
333 	register u_int rndup;
334 	static crud[BYTES_PER_XDR_UNIT];
335 
336 	/*
337 	 * if no data we are done
338 	 */
339 	if (cnt == 0)
340 		return (TRUE);
341 
342 	/*
343 	 * round byte count to full xdr units
344 	 */
345 	rndup = cnt % BYTES_PER_XDR_UNIT;
346 	if (rndup > 0)
347 		rndup = BYTES_PER_XDR_UNIT - rndup;
348 
349 	if (xdrs->x_op == XDR_DECODE) {
350 		if (!XDR_GETBYTES(xdrs, cp, cnt)) {
351 			return (FALSE);
352 		}
353 		if (rndup == 0)
354 			return (TRUE);
355 		return (XDR_GETBYTES(xdrs, crud, rndup));
356 	}
357 
358 	if (xdrs->x_op == XDR_ENCODE) {
359 		if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
360 			return (FALSE);
361 		}
362 		if (rndup == 0)
363 			return (TRUE);
364 		return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
365 	}
366 
367 	if (xdrs->x_op == XDR_FREE) {
368 		return (TRUE);
369 	}
370 
371 	return (FALSE);
372 }
373 
374 /*
375  * XDR counted bytes
376  * *cpp is a pointer to the bytes, *sizep is the count.
377  * If *cpp is NULL maxsize bytes are allocated
378  */
379 bool_t
380 xdr_bytes(xdrs, cpp, sizep, maxsize)
381 	register XDR *xdrs;
382 	char **cpp;
383 	register u_int *sizep;
384 	u_int maxsize;
385 {
386 	register char *sp = *cpp;  /* sp is the actual string pointer */
387 	register u_int nodesize;
388 
389 	/*
390 	 * first deal with the length since xdr bytes are counted
391 	 */
392 	if (! xdr_u_int(xdrs, sizep)) {
393 		return (FALSE);
394 	}
395 	nodesize = *sizep;
396 	if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
397 		return (FALSE);
398 	}
399 
400 	/*
401 	 * now deal with the actual bytes
402 	 */
403 	switch (xdrs->x_op) {
404 
405 	case XDR_DECODE:
406 		if (nodesize == 0) {
407 			return (TRUE);
408 		}
409 		if (sp == NULL) {
410 			*cpp = sp = (char *)mem_alloc(nodesize);
411 		}
412 		if (sp == NULL) {
413 			(void) fprintf(stderr, "xdr_bytes: out of memory\n");
414 			return (FALSE);
415 		}
416 		/* fall into ... */
417 
418 	case XDR_ENCODE:
419 		return (xdr_opaque(xdrs, sp, nodesize));
420 
421 	case XDR_FREE:
422 		if (sp != NULL) {
423 			mem_free(sp, nodesize);
424 			*cpp = NULL;
425 		}
426 		return (TRUE);
427 	}
428 	return (FALSE);
429 }
430 
431 /*
432  * Implemented here due to commonality of the object.
433  */
434 bool_t
435 xdr_netobj(xdrs, np)
436 	XDR *xdrs;
437 	struct netobj *np;
438 {
439 
440 	return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
441 }
442 
443 /*
444  * XDR a descriminated union
445  * Support routine for discriminated unions.
446  * You create an array of xdrdiscrim structures, terminated with
447  * an entry with a null procedure pointer.  The routine gets
448  * the discriminant value and then searches the array of xdrdiscrims
449  * looking for that value.  It calls the procedure given in the xdrdiscrim
450  * to handle the discriminant.  If there is no specific routine a default
451  * routine may be called.
452  * If there is no specific or default routine an error is returned.
453  */
454 bool_t
455 xdr_union(xdrs, dscmp, unp, choices, dfault)
456 	register XDR *xdrs;
457 	enum_t *dscmp;		/* enum to decide which arm to work on */
458 	char *unp;		/* the union itself */
459 	struct xdr_discrim *choices;	/* [value, xdr proc] for each arm */
460 	xdrproc_t dfault;	/* default xdr routine */
461 {
462 	register enum_t dscm;
463 
464 	/*
465 	 * we deal with the discriminator;  it's an enum
466 	 */
467 	if (! xdr_enum(xdrs, dscmp)) {
468 		return (FALSE);
469 	}
470 	dscm = *dscmp;
471 
472 	/*
473 	 * search choices for a value that matches the discriminator.
474 	 * if we find one, execute the xdr routine for that value.
475 	 */
476 	for (; choices->proc != NULL_xdrproc_t; choices++) {
477 		if (choices->value == dscm)
478 			return ((*(choices->proc))(xdrs, unp, LASTUNSIGNED));
479 	}
480 
481 	/*
482 	 * no match - execute the default xdr routine if there is one
483 	 */
484 	return ((dfault == NULL_xdrproc_t) ? FALSE :
485 	    (*dfault)(xdrs, unp, LASTUNSIGNED));
486 }
487 
488 
489 /*
490  * Non-portable xdr primitives.
491  * Care should be taken when moving these routines to new architectures.
492  */
493 
494 
495 /*
496  * XDR null terminated ASCII strings
497  * xdr_string deals with "C strings" - arrays of bytes that are
498  * terminated by a NULL character.  The parameter cpp references a
499  * pointer to storage; If the pointer is null, then the necessary
500  * storage is allocated.  The last parameter is the max allowed length
501  * of the string as specified by a protocol.
502  */
503 bool_t
504 xdr_string(xdrs, cpp, maxsize)
505 	register XDR *xdrs;
506 	char **cpp;
507 	u_int maxsize;
508 {
509 	register char *sp = *cpp;  /* sp is the actual string pointer */
510 	u_int size;
511 	u_int nodesize;
512 
513 	/*
514 	 * first deal with the length since xdr strings are counted-strings
515 	 */
516 	switch (xdrs->x_op) {
517 	case XDR_FREE:
518 		if (sp == NULL) {
519 			return(TRUE);	/* already free */
520 		}
521 		/* fall through... */
522 	case XDR_ENCODE:
523 		size = strlen(sp);
524 		break;
525 	}
526 	if (! xdr_u_int(xdrs, &size)) {
527 		return (FALSE);
528 	}
529 	if (size > maxsize) {
530 		return (FALSE);
531 	}
532 	nodesize = size + 1;
533 
534 	/*
535 	 * now deal with the actual bytes
536 	 */
537 	switch (xdrs->x_op) {
538 
539 	case XDR_DECODE:
540 		if (nodesize == 0) {
541 			return (TRUE);
542 		}
543 		if (sp == NULL)
544 			*cpp = sp = (char *)mem_alloc(nodesize);
545 		if (sp == NULL) {
546 			(void) fprintf(stderr, "xdr_string: out of memory\n");
547 			return (FALSE);
548 		}
549 		sp[size] = 0;
550 		/* fall into ... */
551 
552 	case XDR_ENCODE:
553 		return (xdr_opaque(xdrs, sp, size));
554 
555 	case XDR_FREE:
556 		mem_free(sp, nodesize);
557 		*cpp = NULL;
558 		return (TRUE);
559 	}
560 	return (FALSE);
561 }
562 
563 /*
564  * Wrapper for xdr_string that can be called directly from
565  * routines like clnt_call
566  */
567 bool_t
568 xdr_wrapstring(xdrs, cpp)
569 	XDR *xdrs;
570 	char **cpp;
571 {
572 	if (xdr_string(xdrs, cpp, LASTUNSIGNED)) {
573 		return (TRUE);
574 	}
575 	return (FALSE);
576 }
577