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