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