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