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