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