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