NASD Programmer's Documentation
Adding marshalled types

NASD uses its own code for marshalling and unmarshalling structures for network communication between hosts with different byte-orderings and natural alignments, regardless of the RPC transport mechanism being used. The functions which perform these operations are automatically generated from descriptions of these marshalled types in the .idl files in include/nasd/. These files include
nasd_types.idl
nasd_drive_types.idl
nasd_control.idl
nasd_nfs_types.idl
nasd_cheops_types.idl

To add a new type, create a typedef for it which looks something like:

typedef struct nasd_new_type_s {
  /* contents here */
} nasd_new_type_t;
The elements of the structure should be padded to 8-byte boundaries using arrays of type nasd_byte_t. If necessary, a pad should be added to the end of the structure to ensure that the entire structure is a multiple of 8 bytes in size. For example, say we were creating a structure with two elements - a partition number (nasd_partnum_t) and a NASD identifier (nasd_identifier_t). A nasd_partnum_t is 2 bytes long, and a nasd_identifier_t is 8 bytes long. So, we must pad after the nasd_partnum_t. That could look like: typedef struct nasd_new_type_s {
  nasd_identifier_t       identifier;
  nasd_partnum_t          partnum;
  nasd_byte_t             pad[6];
} nasd_new_type_t;

or

typedef struct nasd_new_type_s {
  nasd_partnum_t          partnum;
  nasd_byte_t             pad[6];
  nasd_identifier_t       identifier;
} nasd_new_type_t;

Additionally, a network-opaque structure should be defined to represent the canonical form of the structure. This is an array of nasd_byte_t sufficient to hold the structure. All together, that is: typedef struct nasd_new_type_s {
  nasd_partnum_t          partnum;
  nasd_byte_t             pad[6];
  nasd_identifier_t       identifier;
} nasd_new_type_t;
const long NASD_NEW_TYPE_MAX = 2 + 6 + 8;
typedef nasd_byte_t nasd_new_type_otw_t[NASD_NEW_TYPE_MAX];
The "otw" is short for "on-the-wire."

Next, a marshalling array type handle should be added to include/nasd/nasd_net_convert.h. This should have type nasd_byte, and is defined like this:

typedef nasd_byte nasd_otw_new_type_t;
This type is not declared as an array, and has the _otw_ immediately after nasd_, not at the end of the type definition (before _t), as with the network-opaque array described above. This is because this definition is used in describing the stub of the marshalling and unmarshalling functions. These stubs are found in common/nasd_net_convert.usc. They look like:
void nasd_new_type_to_net(nasd_new_type_t *in, nasd_otw_new_type_t *out) { *out = *in; } void nasd_new_type_from_net(nasd_otw_new_type_t *in, nasd_new_type_t *out) { *out = *in; } The NASD compilation process expands these into "real" marshalling and unmarshalling functions and compiles them into libnasd_common.a.

It is necessary to wrap these generated conversion functions in code which is more pleasant for others to call. To do this, first add a marshalling declaration to the bottom of include/nasd/nasd_marshall.h. That looks like:

NASD_M(new_type) Next, add the marshalling and unmarshalling routines to common/nasd_marshall.c. void
nasd_new_type_marshall(
  nasd_new_type_t      *in,
  nasd_new_type_otw_t   out)
{
  nasd_new_type_to_net(in, out);
}

void
nasd_new_type_unmarshall(
  nasd_new_type_otw_t   in,
  nasd_new_type_t      *out)
{
  nasd_new_type_from_net(in, out);
}

To test the correctness of these additions, you should add code to to tests/marshall_tester.c. It is traditional to test that the size of the net-opaque type and the size of the type are the same, and that you can take a host-ordered structure, marshall it to network order, then unmarshall it, and have the same contents as you started with.
<--- ---> ^<br>|<br>|
Adding modules Adding RPCs NASD Programmer's Documentation