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