ONC+ Developer's Guide


The XDR library package provides a primitive for handling arrays of arbitrary elements. The xdr_bytes() routine treats a subset of generic arrays, in which the size of array elements is known to be 1, and the external description of each element is built in. The generic array primitive, xdr_array() requires parameters identical to those of xdr_bytes() plus two more: the size of array elements, and an XDR routine to handle each of the elements. This routine is called to encode or decode each element of the array.

xdr_array(xdrs, ap, lp, maxlength, elementsize, xdr_element)
   XDR *xdrs;
   char **ap;
   u_int *lp;
   u_int maxlength;
   u_int elementsize;
   bool_t (*xdr_element)();

The parameter ap is the address of the pointer to the array. If *ap is NULL when the array is being deserialized, XDR allocates an array of the appropriate size and sets *ap to that array. The element count of the array is obtained from *lp when the array is serialized; *lp is set to the array length when the array is deserialized. The parameter maxlength is the maximum number of elements that the array is allowed to have; elementsiz is the byte size of each element of the array (the C function sizeof() can be used to obtain this value). The xdr_element() routine is called to serialize, deserialize, or free each element of the array.

Before defining more constructed data types, three examples are presented.

Array Example 1

A user on a networked machine can be identified by

A structure with this information and its associated XDR routine could be coded as in the following code example.

Example A–7 Array Example #1

struct netuser {
 	char  *nu_machinename;
 	int   nu_uid;
 	u_int nu_glen;
 	int   *nu_gids;
#define NLEN 255       /* machine names < 256 chars */
#define NGRPS 20       /* user can't be in > 20 groups */

xdr_netuser(xdrs, nup)
 	XDR *xdrs;
 	struct netuser *nup;
 	return(xdr_string(xdrs, &nup->nu_machinename, NLEN) &&
 		    xdr_int(xdrs, &nup->nu_uid) &&
 		    xdr_array(xdrs, &nup->nu_gids, &nup->nu_glen, NGRPS,
		               sizeof (int), xdr_int));

Array Example 2

You could implement a party of network users as an array of netuser structure. The declaration and its associated XDR routines are as shown in the following code example.

Example A–8 Array Example #2

struct party {

 	u_int p_len;
 	struct netuser *p_nusers;
#define PLEN 500 /* max number of users in a party */
xdr_party(xdrs, pp)
 	XDR *xdrs;
 	struct party *pp;
 	return(xdr_array(xdrs, &pp->p_nusers, &pp->p_len, PLEN,
 	 sizeof (struct netuser), xdr_netuser));

Array Example 3

You can combine the well-known parameters to main, argc and argv, into a structure. An array of these structures can make up a history of commands. The declarations and XDR routines might look like the following example.

Example A–9 Array Example #3

struct cmd {
 	u_int c_argc;
 	char **c_argv;
#define ALEN 1000           /* args cannot be > 1000 chars */
 #define NARGC 100          /* commands cannot have > 100 args */

struct history {
 	u_int h_len;
 	struct cmd *h_cmds;
#define NCMDS 75            /* history is no more than 75 commands */

xdr_wrapstring(xdrs, sp)

 	XDR *xdrs;
 	char **sp;
 	return(xdr_string(xdrs, sp, ALEN));


xdr_cmd(xdrs, cp)

 	XDR *xdrs;
 	struct cmd *cp;
 	return(xdr_array(xdrs, &cp->c_argv, &cp->c_argc, NARGC,
 	        sizeof (char *), xdr_wrapstring));
xdr_history(xdrs, hp)

 	XDR *xdrs;
 	struct history *hp;
 	return(xdr_array(xdrs, &hp->h_cmds, &hp->h_len, NCMDS,
 	        sizeof (struct cmd), xdr_cmd));

Some confusion in this example is that you need the routine xdr_wrapstring() to package the xdr_string() routine, because the implementation of xdr_array() passes only two parameters to the array element description routine. xdr_wrapstring() supplies the third parameter to xdr_string().

By now, the recursive nature of the XDR library should be obvious. A discussion follows of more constructed data types.