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