#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 */