1#include <rpc/rpc.h>
2#include <string.h>
3
4#define LASTUNSIGNED    ((u_int)((int)0-1))
5
6/*
7 * Primitives for stuffing data into and retrieving data from an XDR
8 */
9
10bool_t xdr_bytes (XDR *xdr, char **cpp, u_int *sizep, u_int maxsize)
11{
12    switch(xdr->x_op) {
13    case XDR_DECODE:
14        if(!XDR_RECV_UINT(xdr, sizep) || *sizep > maxsize)
15            return FALSE;
16        if(*sizep == 0)
17            return TRUE;
18        if(*cpp == NULL)
19            *cpp = (char *) mem_alloc(*sizep);
20        if(*cpp == NULL) return FALSE;
21        return XDR_RECV_BYTES(xdr, (uint8 *) *cpp, *sizep);
22    case XDR_ENCODE:
23        return (XDR_SEND_UINT(xdr, sizep) &&
24                *sizep <= maxsize &&
25                XDR_SEND_BYTES(xdr, (uint8 *) *cpp, *sizep));
26    case XDR_FREE:
27        if (*cpp) {
28            mem_free(*cpp);
29            *cpp = NULL;
30        }
31        return TRUE;
32    default:
33        break;
34    }
35    return FALSE;
36} /* xdr_bytes */
37
38bool_t xdr_send_enum (xdr_s_type *xdr, const void *value, uint32 size)
39{
40    switch (size) {
41    case 4:
42        return XDR_SEND_INT32(xdr, (int32 *) value);
43    case 2:
44        return XDR_SEND_INT16(xdr, (int16 *) value);
45    case 1:
46        return XDR_SEND_INT8(xdr, (int8 *) value);
47    default:
48        return FALSE;
49    }
50} /* xdr_send_enum */
51
52bool_t xdr_recv_enum (xdr_s_type *xdr, void *value, uint32 size)
53{
54    switch (size) {
55    case 4:
56        return XDR_RECV_INT32(xdr, (int32 *) value);
57    case 2:
58        return XDR_RECV_INT16(xdr, (int16 *) value);
59    case 1:
60        return XDR_RECV_INT8(xdr, (int8 *) value);
61    default:
62        return FALSE;
63    }
64} /* xdr_recv_enum */
65
66#include <stdio.h>
67
68bool_t xdr_enum (XDR *xdr, enum_t *ep)
69{
70    switch(xdr->x_op) {
71    case XDR_ENCODE:
72        return XDR_SEND_INT32(xdr, (int32 *)ep);
73    case XDR_DECODE:
74        return XDR_RECV_INT32(xdr, (int32 *)ep);
75    case XDR_FREE:
76        return TRUE;
77    default:
78        break;
79    }
80    return FALSE;
81} /* xdr_enum */
82
83bool_t xdr_u_int (XDR *xdr, u_int *uip)
84{
85    switch(xdr->x_op) {
86    case XDR_ENCODE:
87        return XDR_SEND_UINT32(xdr, (uint32 *) uip);
88    case XDR_DECODE:
89        return XDR_RECV_UINT32(xdr, (uint32 *) uip);
90    case XDR_FREE:
91        return TRUE;
92    default:
93        break;
94    }
95    return FALSE;
96} /* xdr_u_int */
97
98bool_t xdr_u_char (XDR *xdr, u_char *cp)
99{
100    u_int u = (*cp);
101    if (!xdr_u_int (xdr, &u))
102        return FALSE;
103    *cp = (u_char) u;
104    return TRUE;
105} /* xdr_u_char */
106
107bool_t xdr_long (XDR *xdr, long *lp)
108{
109    switch (xdr->x_op) {
110    case XDR_ENCODE:
111        return XDR_SEND_INT32(xdr, (int32_t *)lp);
112    case XDR_DECODE:
113        return XDR_RECV_INT32(xdr, (int32_t *)lp);
114    case XDR_FREE:
115        return TRUE;
116    default:
117        break;
118    }
119    return FALSE;
120} /* xdr_long */
121
122bool_t xdr_u_long (XDR *xdr, u_long *ulp)
123{
124    switch (xdr->x_op) {
125    case XDR_ENCODE:
126        return XDR_SEND_UINT32(xdr, (uint32_t *)ulp);
127    case XDR_DECODE:
128        return XDR_RECV_UINT32(xdr, (uint32_t *)ulp);
129    case XDR_FREE:
130        return TRUE;
131    default:
132        break;
133    }
134    return FALSE;
135} /* xdr_u_long */
136
137/*
138 * XDR hyper integers
139 * same as xdr_hyper - open coded to save a proc call!
140 */
141bool_t xdr_u_hyper (XDR *xdrs, u_quad_t *ullp)
142{
143    unsigned long t1;
144    unsigned long t2;
145
146    if (xdrs->x_op == XDR_ENCODE) {
147        t1 = (unsigned long) ((*ullp) >> 32);
148        t2 = (unsigned long) (*ullp);
149        return (XDR_SEND_INT32(xdrs, (int32 *)&t1) &&
150                XDR_SEND_INT32(xdrs, (int32 *)&t2));
151    }
152
153    if (xdrs->x_op == XDR_DECODE) {
154        if (!XDR_RECV_INT32(xdrs, (int32 *)&t1) ||
155            !XDR_RECV_INT32(xdrs, (int32 *)&t2))
156            return FALSE;
157        *ullp = ((u_quad_t) t1) << 32;
158        *ullp |= t2;
159        return TRUE;
160    }
161
162    return xdrs->x_op == XDR_FREE;
163}
164
165bool_t
166xdr_u_quad_t (XDR *xdrs, u_quad_t *ullp)
167{
168    return xdr_u_hyper(xdrs, ullp);
169}
170
171bool_t xdr_u_short (XDR *xdr, u_short *usp)
172{
173    u_long l;
174
175    switch (xdr->x_op) {
176    case XDR_ENCODE:
177        l = *usp;
178        return XDR_SEND_UINT32(xdr, (uint32_t *)&l);
179    case XDR_DECODE:
180        if(!XDR_RECV_UINT32(xdr, (uint32_t *)&l))
181            return FALSE;
182        *usp = (u_short)l;
183        return TRUE;
184    case XDR_FREE:
185        return TRUE;
186    default:
187        break;
188    }
189
190    return FALSE;
191} /* xdr_u_short */
192
193/*
194 * xdr_vector():
195 *
196 * XDR a fixed length array. Unlike variable-length arrays,
197 * the storage of fixed length arrays is static and unfreeable.
198 * > basep: base of the array
199 * > size: size of the array
200 * > elemsize: size of each element
201 * > xdr_elem: routine to XDR each element
202 */
203bool_t
204xdr_vector (XDR *xdrs,
205            char *basep,
206            u_int nelem,
207            u_int elemsize,
208            xdrproc_t xdr_elem)
209{
210    u_int i;
211    char *elptr;
212
213    elptr = basep;
214    for (i = 0; i < nelem; i++) {
215        if (!(*xdr_elem) (xdrs, elptr, LASTUNSIGNED))
216            return FALSE;
217        elptr += elemsize;
218    }
219    return TRUE;
220}
221
222bool_t xdr_bool (XDR *xdr, bool_t *bp)
223{
224    uint32 lb;
225
226    switch(xdr->x_op) {
227    case XDR_ENCODE:
228        lb = *bp ? TRUE : FALSE;
229        return XDR_SEND_UINT32(xdr, &lb);
230    case XDR_DECODE:
231        if (!XDR_RECV_UINT32(xdr, &lb))
232            return FALSE;
233        *bp = (lb == FALSE) ? FALSE : TRUE;
234        return TRUE;
235    case XDR_FREE:
236        return TRUE;
237    default:
238        break;
239    }
240
241    return FALSE;
242} /* xdr_bool */
243
244/*
245 * XDR an indirect pointer
246 * xdr_reference is for recursively translating a structure that is
247 * referenced by a pointer inside the structure that is currently being
248 * translated.  pp references a pointer to storage. If *pp is null
249 * the  necessary storage is allocated.
250 * size is the size of the referneced structure.
251 * proc is the routine to handle the referenced structure.
252 */
253bool_t
254xdr_reference (XDR *xdrs,
255               caddr_t *pp,     /* the pointer to work on */
256               u_int size,      /* size of the object pointed to */
257               xdrproc_t proc)   /* xdr routine to handle the object */
258{
259    bool_t stat;
260
261    if (*pp == NULL) {
262        switch (xdrs->x_op) {
263        case XDR_FREE:
264            return TRUE;
265
266        case XDR_DECODE:
267            *pp = (caddr_t) mem_alloc (size);
268            if (*pp == NULL) return FALSE;
269            memset(*pp, 0, size);
270            break;
271        default:
272            break;
273        }
274    }
275
276    stat = (*proc) (xdrs, *pp, LASTUNSIGNED);
277
278    if (xdrs->x_op == XDR_FREE) {
279        mem_free(*pp);
280        *pp = NULL;
281    }
282    return stat;
283} /* xdr_reference */
284
285/*
286 * xdr_pointer():
287 *
288 * XDR a pointer to a possibly recursive data structure. This
289 * differs with xdr_reference in that it can serialize/deserialize
290 * trees correctly.
291 *
292 *  What's sent is actually a union:
293 *
294 *  union object_pointer switch (bool_t b) {
295 *  case TRUE: object_data data;
296 *  case FALSE: void nothing;
297 *  }
298 *
299 * > objpp: Pointer to the pointer to the object.
300 * > obj_size: size of the object.
301 * > xdr_obj: routine to XDR an object.
302 *
303 */
304
305bool_t
306xdr_pointer (XDR *xdrs,
307             char **objpp,
308             u_int obj_size,
309             xdrproc_t xdr_obj)
310{
311    bool_t more_data;
312
313    more_data = (*objpp != NULL);
314    if (!xdr_bool (xdrs, &more_data))
315        return FALSE;
316
317    if (!more_data) {
318        *objpp = NULL;
319        return TRUE;
320    }
321    return xdr_reference (xdrs, objpp, obj_size, xdr_obj);
322} /* xdr_pointer */
323
324bool_t xdr_void (void)
325{
326    return TRUE;
327} /* xdr_void */
328
329/*
330 * XDR an array of arbitrary elements
331 * *addrp is a pointer to the array, *sizep is the number of elements.
332 * If addrp is NULL (*sizep * elsize) bytes are allocated.
333 * elsize is the size (in bytes) of each element, and elproc is the
334 * xdr procedure to call to handle each element of the array.
335 */
336bool_t
337xdr_array (XDR *xdrs,
338           caddr_t *addrp,/* array pointer */
339           u_int *sizep,  /* number of elements */
340           u_int maxsize,  /* max numberof elements */
341           u_int elsize,  /* size in bytes of each element */
342           xdrproc_t elproc) /* xdr routine to handle each element */
343{
344    u_int i;
345    caddr_t target = *addrp;
346    u_int c;/* the actual element count */
347    bool_t stat = TRUE;
348    u_int nodesize;
349
350    /* like strings, arrays are really counted arrays */
351    if (!xdr_u_int (xdrs, sizep))
352        return FALSE;
353    c = *sizep;
354    if ((c > maxsize) && (xdrs->x_op != XDR_FREE))
355        return FALSE;
356    nodesize = c * elsize;
357
358    /*
359     * if we are deserializing, we may need to allocate an array.
360     * We also save time by checking for a null array if we are freeing.
361     */
362    if (target == NULL)
363        switch (xdrs->x_op) {
364        case XDR_DECODE:
365            if (c == 0)
366                return TRUE;
367            *addrp = target = mem_alloc (nodesize);
368            if (!*addrp) return FALSE;
369            memset (target, 0, nodesize);
370            break;
371        case XDR_FREE:
372            return TRUE;
373        default:
374            break;
375        }
376
377    /*
378     * now we xdr each element of array
379     */
380    for (i = 0; (i < c) && stat; i++) {
381        stat = (*elproc) (xdrs, target, LASTUNSIGNED);
382        target += elsize;
383    }
384
385    /*
386     * the array may need freeing
387     */
388    if (xdrs->x_op == XDR_FREE) {
389        mem_free(*addrp);
390        *addrp = NULL;
391    }
392
393    return stat;
394}
395
396bool_t xdr_int(XDR *xdr, int *ip)
397{
398    switch (xdr->x_op) {
399    case XDR_ENCODE:
400        return XDR_SEND_INT32(xdr, (int32 *) ip);
401    case XDR_DECODE:
402        return XDR_RECV_INT32(xdr, (int32 *) ip);
403    case XDR_FREE:
404        return TRUE;
405    default:
406        break;
407    }
408
409    return FALSE;
410} /* xdr_int */
411
412bool_t xdr_opaque (XDR *xdr, caddr_t cp, u_int cnt)
413{
414    /* if no data we are done */
415    if (cnt == 0)
416        return TRUE;
417
418    switch (xdr->x_op) {
419    case XDR_ENCODE:
420        return XDR_SEND_BYTES(xdr, (uint8 *) cp, cnt);
421    case XDR_DECODE:
422        return XDR_RECV_BYTES(xdr, (uint8 *) cp, cnt);
423    case XDR_FREE:
424        return TRUE;
425    default:
426        break;
427    }
428
429    return FALSE;
430} /* xdr_opaque */
431
432bool_t xdr_char (XDR *xdr, char *cp)
433{
434    int i;
435    i = (*cp);
436    if (!xdr_int (xdr, &i))
437        return FALSE;
438    *cp = i;
439    return TRUE;
440} /* xdr_char */
441
442bool_t
443xdr_quad_t (XDR *xdrs, quad_t *llp)
444{
445    return xdr_u_quad_t(xdrs, (u_quad_t *)llp);
446}
447
448bool_t xdr_short (XDR *xdr, short *sp)
449{
450    long l;
451    switch (xdr->x_op) {
452    case XDR_ENCODE:
453        l = *sp;
454        return XDR_SEND_INT32(xdr, (int32_t *)&l);
455    case XDR_DECODE:
456        if (!XDR_RECV_INT32(xdr, (int32_t *)&l))
457            return FALSE;
458        *sp = (short)l;
459        return TRUE;
460    case XDR_FREE:
461        return TRUE;
462    default:
463        break;
464    }
465    return FALSE;
466} /* xdr_short */
467
468/*
469 * Non-portable xdr primitives.
470 * Care should be taken when moving these routines to new architectures.
471 */
472
473/*
474 * XDR null terminated ASCII strings
475 * xdr_string deals with "C strings" - arrays of bytes that are
476 * terminated by a NULL character.  The parameter cpp references a
477 * pointer to storage; If the pointer is null, then the necessary
478 * storage is allocated.  The last parameter is the max allowed length
479 * of the string as specified by a protocol.
480 */
481bool_t xdr_string (XDR *xdr, char **cpp, u_int maxsize)
482{
483    u_int size;
484    u_int nodesize;
485
486    /*
487     * first deal with the length since xdr strings are counted-strings
488     */
489    switch (xdr->x_op) {
490    case XDR_FREE:
491        if (*cpp == NULL) return TRUE;
492        /* fall through... */
493    case XDR_ENCODE:
494        if (*cpp == NULL) return FALSE;
495        size = strlen(*cpp);
496        break;
497    case XDR_DECODE:
498        break;
499    default:
500        break;
501    }
502
503    if (!xdr_u_int(xdr, &size)) return FALSE;
504    if (size > maxsize) return FALSE;
505    nodesize = size + 1;
506
507    /*
508     * now deal with the actual bytes
509     */
510    switch (xdr->x_op) {
511    case XDR_DECODE:
512        if (nodesize == 0) return TRUE;
513        if (*cpp == NULL)
514            *cpp = (char *)mem_alloc(nodesize);
515        if (*cpp == NULL) return FALSE;
516        (*cpp)[size] = 0;
517        /* fall through... */
518    case XDR_ENCODE:
519        return xdr_opaque(xdr, *cpp, size);
520    case XDR_FREE:
521        mem_free(*cpp);
522        *cpp = NULL;
523        return TRUE;
524    default:
525        break;
526    }
527    return FALSE;
528} /* xdr_string */
529