| #include <rpc/rpc.h> |
| #include <string.h> |
| |
| #define LASTUNSIGNED ((u_int)((int)0-1)) |
| |
| /* |
| * Primitives for stuffing data into and retrieving data from an XDR |
| */ |
| |
| bool_t xdr_bytes (XDR *xdr, char **cpp, u_int *sizep, u_int maxsize) |
| { |
| switch(xdr->x_op) { |
| case XDR_DECODE: |
| if(!XDR_RECV_UINT(xdr, sizep) || *sizep > maxsize) |
| return FALSE; |
| if(*sizep == 0) |
| return TRUE; |
| if(*cpp == NULL) |
| *cpp = (char *) mem_alloc(*sizep); |
| if(*cpp == NULL) return FALSE; |
| return XDR_RECV_BYTES(xdr, (uint8 *) *cpp, *sizep); |
| case XDR_ENCODE: |
| return (XDR_SEND_UINT(xdr, sizep) && |
| *sizep <= maxsize && |
| XDR_SEND_BYTES(xdr, (uint8 *) *cpp, *sizep)); |
| case XDR_FREE: |
| if (*cpp) { |
| mem_free(*cpp); |
| *cpp = NULL; |
| } |
| return TRUE; |
| default: |
| break; |
| } |
| return FALSE; |
| } /* xdr_bytes */ |
| |
| bool_t xdr_send_enum (xdr_s_type *xdr, const void *value, uint32 size) |
| { |
| switch (size) { |
| case 4: |
| return XDR_SEND_INT32(xdr, (int32 *) value); |
| case 2: |
| return XDR_SEND_INT16(xdr, (int16 *) value); |
| case 1: |
| return XDR_SEND_INT8(xdr, (int8 *) value); |
| default: |
| return FALSE; |
| } |
| } /* xdr_send_enum */ |
| |
| bool_t xdr_recv_enum (xdr_s_type *xdr, void *value, uint32 size) |
| { |
| switch (size) { |
| case 4: |
| return XDR_RECV_INT32(xdr, (int32 *) value); |
| case 2: |
| return XDR_RECV_INT16(xdr, (int16 *) value); |
| case 1: |
| return XDR_RECV_INT8(xdr, (int8 *) value); |
| default: |
| return FALSE; |
| } |
| } /* xdr_recv_enum */ |
| |
| #include <stdio.h> |
| |
| bool_t xdr_enum (XDR *xdr, enum_t *ep) |
| { |
| switch(xdr->x_op) { |
| case XDR_ENCODE: |
| return XDR_SEND_INT32(xdr, (int32 *)ep); |
| case XDR_DECODE: |
| return XDR_RECV_INT32(xdr, (int32 *)ep); |
| case XDR_FREE: |
| return TRUE; |
| default: |
| break; |
| } |
| return FALSE; |
| } /* xdr_enum */ |
| |
| bool_t xdr_u_int (XDR *xdr, u_int *uip) |
| { |
| switch(xdr->x_op) { |
| case XDR_ENCODE: |
| return XDR_SEND_UINT32(xdr, (uint32 *) uip); |
| case XDR_DECODE: |
| return XDR_RECV_UINT32(xdr, (uint32 *) uip); |
| case XDR_FREE: |
| return TRUE; |
| default: |
| break; |
| } |
| return FALSE; |
| } /* xdr_u_int */ |
| |
| bool_t xdr_u_char (XDR *xdr, u_char *cp) |
| { |
| u_int u = (*cp); |
| if (!xdr_u_int (xdr, &u)) |
| return FALSE; |
| *cp = (u_char) u; |
| return TRUE; |
| } /* xdr_u_char */ |
| |
| bool_t xdr_long (XDR *xdr, long *lp) |
| { |
| switch (xdr->x_op) { |
| case XDR_ENCODE: |
| return XDR_SEND_INT32(xdr, (int32_t *)lp); |
| case XDR_DECODE: |
| return XDR_RECV_INT32(xdr, (int32_t *)lp); |
| case XDR_FREE: |
| return TRUE; |
| default: |
| break; |
| } |
| return FALSE; |
| } /* xdr_long */ |
| |
| bool_t xdr_u_long (XDR *xdr, u_long *ulp) |
| { |
| switch (xdr->x_op) { |
| case XDR_ENCODE: |
| return XDR_SEND_UINT32(xdr, (uint32_t *)ulp); |
| case XDR_DECODE: |
| return XDR_RECV_UINT32(xdr, (uint32_t *)ulp); |
| case XDR_FREE: |
| return TRUE; |
| default: |
| break; |
| } |
| return FALSE; |
| } /* xdr_u_long */ |
| |
| /* |
| * XDR hyper integers |
| * same as xdr_hyper - open coded to save a proc call! |
| */ |
| bool_t xdr_u_hyper (XDR *xdrs, u_quad_t *ullp) |
| { |
| unsigned long t1; |
| unsigned long t2; |
| |
| if (xdrs->x_op == XDR_ENCODE) { |
| t1 = (unsigned long) ((*ullp) >> 32); |
| t2 = (unsigned long) (*ullp); |
| return (XDR_SEND_INT32(xdrs, (int32 *)&t1) && |
| XDR_SEND_INT32(xdrs, (int32 *)&t2)); |
| } |
| |
| if (xdrs->x_op == XDR_DECODE) { |
| if (!XDR_RECV_INT32(xdrs, (int32 *)&t1) || |
| !XDR_RECV_INT32(xdrs, (int32 *)&t2)) |
| return FALSE; |
| *ullp = ((u_quad_t) t1) << 32; |
| *ullp |= t2; |
| return TRUE; |
| } |
| |
| return xdrs->x_op == XDR_FREE; |
| } |
| |
| bool_t |
| xdr_u_quad_t (XDR *xdrs, u_quad_t *ullp) |
| { |
| return xdr_u_hyper(xdrs, ullp); |
| } |
| |
| bool_t xdr_u_short (XDR *xdr, u_short *usp) |
| { |
| u_long l; |
| |
| switch (xdr->x_op) { |
| case XDR_ENCODE: |
| l = *usp; |
| return XDR_SEND_UINT32(xdr, (uint32_t *)&l); |
| case XDR_DECODE: |
| if(!XDR_RECV_UINT32(xdr, (uint32_t *)&l)) |
| return FALSE; |
| *usp = (u_short)l; |
| return TRUE; |
| case XDR_FREE: |
| return TRUE; |
| default: |
| break; |
| } |
| |
| return FALSE; |
| } /* xdr_u_short */ |
| |
| /* |
| * xdr_vector(): |
| * |
| * XDR a fixed length array. Unlike variable-length arrays, |
| * the storage of fixed length arrays is static and unfreeable. |
| * > basep: base of the array |
| * > size: size of the array |
| * > elemsize: size of each element |
| * > xdr_elem: routine to XDR each element |
| */ |
| bool_t |
| xdr_vector (XDR *xdrs, |
| char *basep, |
| u_int nelem, |
| u_int elemsize, |
| xdrproc_t xdr_elem) |
| { |
| u_int i; |
| char *elptr; |
| |
| elptr = basep; |
| for (i = 0; i < nelem; i++) { |
| if (!(*xdr_elem) (xdrs, elptr, LASTUNSIGNED)) |
| return FALSE; |
| elptr += elemsize; |
| } |
| return TRUE; |
| } |
| |
| bool_t xdr_bool (XDR *xdr, bool_t *bp) |
| { |
| uint32 lb; |
| |
| switch(xdr->x_op) { |
| case XDR_ENCODE: |
| lb = *bp ? TRUE : FALSE; |
| return XDR_SEND_UINT32(xdr, &lb); |
| case XDR_DECODE: |
| if (!XDR_RECV_UINT32(xdr, &lb)) |
| return FALSE; |
| *bp = (lb == FALSE) ? FALSE : TRUE; |
| return TRUE; |
| case XDR_FREE: |
| return TRUE; |
| default: |
| break; |
| } |
| |
| return FALSE; |
| } /* xdr_bool */ |
| |
| /* |
| * XDR an indirect pointer |
| * xdr_reference is for recursively translating a structure that is |
| * referenced by a pointer inside the structure that is currently being |
| * translated. pp references a pointer to storage. If *pp is null |
| * the necessary storage is allocated. |
| * size is the size of the referneced structure. |
| * proc is the routine to handle the referenced structure. |
| */ |
| bool_t |
| xdr_reference (XDR *xdrs, |
| caddr_t *pp, /* the pointer to work on */ |
| u_int size, /* size of the object pointed to */ |
| xdrproc_t proc) /* xdr routine to handle the object */ |
| { |
| bool_t stat; |
| |
| if (*pp == NULL) { |
| switch (xdrs->x_op) { |
| case XDR_FREE: |
| return TRUE; |
| |
| case XDR_DECODE: |
| *pp = (caddr_t) mem_alloc (size); |
| if (*pp == NULL) return FALSE; |
| memset(*pp, 0, size); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| stat = (*proc) (xdrs, *pp, LASTUNSIGNED); |
| |
| if (xdrs->x_op == XDR_FREE) { |
| mem_free(*pp); |
| *pp = NULL; |
| } |
| return stat; |
| } /* xdr_reference */ |
| |
| /* |
| * xdr_pointer(): |
| * |
| * XDR a pointer to a possibly recursive data structure. This |
| * differs with xdr_reference in that it can serialize/deserialize |
| * trees correctly. |
| * |
| * What's sent is actually a union: |
| * |
| * union object_pointer switch (bool_t b) { |
| * case TRUE: object_data data; |
| * case FALSE: void nothing; |
| * } |
| * |
| * > objpp: Pointer to the pointer to the object. |
| * > obj_size: size of the object. |
| * > xdr_obj: routine to XDR an object. |
| * |
| */ |
| |
| bool_t |
| xdr_pointer (XDR *xdrs, |
| char **objpp, |
| u_int obj_size, |
| xdrproc_t xdr_obj) |
| { |
| bool_t more_data; |
| |
| more_data = (*objpp != NULL); |
| if (!xdr_bool (xdrs, &more_data)) |
| return FALSE; |
| |
| if (!more_data) { |
| *objpp = NULL; |
| return TRUE; |
| } |
| return xdr_reference (xdrs, objpp, obj_size, xdr_obj); |
| } /* xdr_pointer */ |
| |
| bool_t xdr_void (void) |
| { |
| return TRUE; |
| } /* xdr_void */ |
| |
| /* |
| * XDR an array of arbitrary elements |
| * *addrp is a pointer to the array, *sizep is the number of elements. |
| * If addrp is NULL (*sizep * elsize) bytes are allocated. |
| * elsize is the size (in bytes) of each element, and elproc is the |
| * xdr procedure to call to handle each element of the array. |
| */ |
| bool_t |
| xdr_array (XDR *xdrs, |
| caddr_t *addrp,/* array pointer */ |
| u_int *sizep, /* number of elements */ |
| u_int maxsize, /* max numberof elements */ |
| u_int elsize, /* size in bytes of each element */ |
| xdrproc_t elproc) /* xdr routine to handle each element */ |
| { |
| u_int i; |
| caddr_t target = *addrp; |
| u_int c;/* the actual element count */ |
| bool_t stat = TRUE; |
| u_int nodesize; |
| |
| /* like strings, arrays are really counted arrays */ |
| if (!xdr_u_int (xdrs, sizep)) |
| return FALSE; |
| c = *sizep; |
| if ((c > maxsize) && (xdrs->x_op != XDR_FREE)) |
| return FALSE; |
| nodesize = c * elsize; |
| |
| /* |
| * if we are deserializing, we may need to allocate an array. |
| * We also save time by checking for a null array if we are freeing. |
| */ |
| if (target == NULL) |
| switch (xdrs->x_op) { |
| case XDR_DECODE: |
| if (c == 0) |
| return TRUE; |
| *addrp = target = mem_alloc (nodesize); |
| if (!*addrp) return FALSE; |
| memset (target, 0, nodesize); |
| break; |
| case XDR_FREE: |
| return TRUE; |
| default: |
| break; |
| } |
| |
| /* |
| * now we xdr each element of array |
| */ |
| for (i = 0; (i < c) && stat; i++) { |
| stat = (*elproc) (xdrs, target, LASTUNSIGNED); |
| target += elsize; |
| } |
| |
| /* |
| * the array may need freeing |
| */ |
| if (xdrs->x_op == XDR_FREE) { |
| mem_free(*addrp); |
| *addrp = NULL; |
| } |
| |
| return stat; |
| } |
| |
| bool_t xdr_int(XDR *xdr, int *ip) |
| { |
| switch (xdr->x_op) { |
| case XDR_ENCODE: |
| return XDR_SEND_INT32(xdr, (int32 *) ip); |
| case XDR_DECODE: |
| return XDR_RECV_INT32(xdr, (int32 *) ip); |
| case XDR_FREE: |
| return TRUE; |
| default: |
| break; |
| } |
| |
| return FALSE; |
| } /* xdr_int */ |
| |
| bool_t xdr_opaque (XDR *xdr, caddr_t cp, u_int cnt) |
| { |
| /* if no data we are done */ |
| if (cnt == 0) |
| return TRUE; |
| |
| switch (xdr->x_op) { |
| case XDR_ENCODE: |
| return XDR_SEND_BYTES(xdr, (uint8 *) cp, cnt); |
| case XDR_DECODE: |
| return XDR_RECV_BYTES(xdr, (uint8 *) cp, cnt); |
| case XDR_FREE: |
| return TRUE; |
| default: |
| break; |
| } |
| |
| return FALSE; |
| } /* xdr_opaque */ |
| |
| bool_t xdr_char (XDR *xdr, char *cp) |
| { |
| int i; |
| i = (*cp); |
| if (!xdr_int (xdr, &i)) |
| return FALSE; |
| *cp = i; |
| return TRUE; |
| } /* xdr_char */ |
| |
| bool_t |
| xdr_quad_t (XDR *xdrs, quad_t *llp) |
| { |
| return xdr_u_quad_t(xdrs, (u_quad_t *)llp); |
| } |
| |
| bool_t xdr_short (XDR *xdr, short *sp) |
| { |
| long l; |
| switch (xdr->x_op) { |
| case XDR_ENCODE: |
| l = *sp; |
| return XDR_SEND_INT32(xdr, (int32_t *)&l); |
| case XDR_DECODE: |
| if (!XDR_RECV_INT32(xdr, (int32_t *)&l)) |
| return FALSE; |
| *sp = (short)l; |
| return TRUE; |
| case XDR_FREE: |
| return TRUE; |
| default: |
| break; |
| } |
| return FALSE; |
| } /* xdr_short */ |
| |
| /* |
| * Non-portable xdr primitives. |
| * Care should be taken when moving these routines to new architectures. |
| */ |
| |
| /* |
| * XDR null terminated ASCII strings |
| * xdr_string deals with "C strings" - arrays of bytes that are |
| * terminated by a NULL character. The parameter cpp references a |
| * pointer to storage; If the pointer is null, then the necessary |
| * storage is allocated. The last parameter is the max allowed length |
| * of the string as specified by a protocol. |
| */ |
| bool_t xdr_string (XDR *xdr, char **cpp, u_int maxsize) |
| { |
| u_int size; |
| u_int nodesize; |
| |
| /* |
| * first deal with the length since xdr strings are counted-strings |
| */ |
| switch (xdr->x_op) { |
| case XDR_FREE: |
| if (*cpp == NULL) return TRUE; |
| /* fall through... */ |
| case XDR_ENCODE: |
| if (*cpp == NULL) return FALSE; |
| size = strlen(*cpp); |
| break; |
| case XDR_DECODE: |
| break; |
| default: |
| break; |
| } |
| |
| if (!xdr_u_int(xdr, &size)) return FALSE; |
| if (size > maxsize) return FALSE; |
| nodesize = size + 1; |
| |
| /* |
| * now deal with the actual bytes |
| */ |
| switch (xdr->x_op) { |
| case XDR_DECODE: |
| if (nodesize == 0) return TRUE; |
| if (*cpp == NULL) |
| *cpp = (char *)mem_alloc(nodesize); |
| if (*cpp == NULL) return FALSE; |
| (*cpp)[size] = 0; |
| /* fall through... */ |
| case XDR_ENCODE: |
| return xdr_opaque(xdr, *cpp, size); |
| case XDR_FREE: |
| mem_free(*cpp); |
| *cpp = NULL; |
| return TRUE; |
| default: |
| break; |
| } |
| return FALSE; |
| } /* xdr_string */ |