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