The CDEV Linear Internet Protocol Definition

Structure and Syntax of CDEV Client/Server Network Transmissions




Prepared for
South Eastern Universities Research Association /
Thomas Jefferson National Accelerator Facility

by

Walt Akers, Chip Watson, and Jie Chen

September 19, 1996








DOCUMENT DATE: September 19, 1996




TRADEMARKS: UNIX is a registered trademark of AT&T in the USA and other countries.
VxWorks is a register trademark of Wind River Systems.
The X Window System is a trademark of Massachusetts Institute of Technology.
OSF/Motif and Motif are trademarks of Open Software Foundation, Inc.
Ultrix and DEC are registered trademarks of Digital Equipment Corporation.
HPUX is a registered trademark of Hewlett Packard.




SURA/TJNAF: The Southeastern Universities Research Association (SURA) operates the Thomas Jefferson National Accelerator Facility (CEBAF) for the United States Department of Energy under contract DE-AC05-84ER40150.




DISCLAIMER: This report was prepared as an account of work sponsored by the United States government. Neither the United States nor the United States Department of Energy, nor any of their employees, makes any warranty, express or implied, or assumes any legal liability or responsibility for the accuracy, completeness, or usefulness of any information, apparatus, product or process disclosed, or represents that its use would not infringe privately owned rights. Reference herein to any specific commercial product, process, or service by trade name, mark, manufacturer, or otherwise, does not necessarily constitute or imply its endorsement, recommendation, or favoring by the United States government or any agency thereof. The view and opinions of the authors expressed herein do not necessarily state or reflect those of the United States government or any agency thereof.





ii



CONTENTS


List of Illustrations ....................................... iv
1. Overview of the CDEV Protocol ....................................... 1
2. The CDEV Multi-Packet Architecture ....................................... 2
3. Binary Structure of the CDEV Packet (Version 1) ....................................... 3
4. The cdevPacket Class ....................................... 4
5. The cdevPacket1 Class ....................................... 5
4. The cdevMessage Class ....................................... 6





iii



LIST OF ILLUSTRATIONS


Figure 1: Structure of a Multi-Packet Transmission ....................................... 2
Figure 2: Structure of the CDEV Packet Binary Stream (Version 1) ....................................... 3
Figure 3: The CDEV Packet Map ....................................... 3
Figure 4: Object Model of the cdevPacket Class ....................................... 4
Figure 5: Object Model of the cdevPacket1 Class ....................................... 5
Figure 6: Object Model of the cdevMessage Class ....................................... 6





iv



1. Overview of the CDEV Linear Internet Protocol
Purpose of This Document This document is designed to provide a clear description of the communications protocol that should be used to pass information between CDEV compliant applications. Adherence to the structure and syntax that is specified by this document will improve the likelihood that the CDEV service/server developer's application will be compatible with other similar applications using CDEV.

This protocol was designed to be as lightweight as possible and still maintain the flexibility to allow CDEV service/server developers to use it without modification. In addition to describing the physical structure of the data packets, this document will also discuss the C++ classes that are provided to allow the developer to rapidly generate packets for transmission and decompose them upon receipt.

Intended Audience This document is intended for anyone who will be developing a CDEV server or will be developing CDEV applications that will communicate with one another over a network. This document will also be useful for software developers who wish to develop a non-CDEV application that can communicate with an existing server that uses this protocol.

Layout of Document This document will begin by discussing the multi-packet architecture that was used to design the data flow for this protocol. The internal structure of the binary stream will be described.

The document will then describe the structure of the individual cdevPacket binary streams that comprise the multi-packet stream. This section will describe the internal structure of the binary stream, as well as the classes that are used to manipulate the component data items and generate and decompose the binary stream.

Next the individual components of the cdevPacket binary stream will be dissected and analyzed. This will include the format of the cdevData binary stream and the intended usage of each element within the cdevPacket binary stream.





1



2. The Multi-Packet Architecture
Multi-Packet Architecture Overview When transmitting data using TCP/IP, performance may normally be improved substantially by placing outbound data into a single buffer and then transmitting many packets simultaneously using a single write call. The CDEV Linear Internet Protocol is designed to support this concept. By buffering small binary packets into a single, larger buffer we are able to substantially improve performance for high-volume, asynchronous transmissions.

To encode individual binary packets using this design required the addition of two 32 bit integers at the beginning of the data stream; the length and the packet count. While this method adds an additional 8 bytes to each synchronous transmission of single CDEV packets, this was considered inconsequential because even with the added size the average CDEV packet would still need to be padded to fulfill the minimum TCP/IP packet size.

Multi-Packet Data Structure Figure 1: Structure of a Multi-Packet Transmission

The following components are contained within a CDEV multi-packet transmission.

Overall Length: This field is a 32 bit integer that identifies the amount of binary data that will be transmitted following the overall length integer.

Packet Count: This field is a 32 bit integer that identifies the number of data packets that will comprise the transmission. While this data item is not required to decode the packet, it is provided to allow verification that the packet was received intact.

Packet Length: This field is a 32 bit integer that identifies the size of the binary packet data following the packet length. It is important to note that this variable represents the length of the data that follows, however, because the next packet length must begin on a four byte boundary the binary data may be followed by up to three bytes of padding.

Binary Data: This field is a variable length binary stream that contains a binary encoded cdevPacket object.





2



3. Binary Structure of the CDEV Packet (Version 1)
CDEV Packet Overview The CDEV packet is a binary stream that contains all of the data items that are required to submit a request or receive a reply from a CDEV server. All of the data elements within the CDEV packet are encoded for network transport using SUN's External Data Representation (XDR) and are aligned on four byte boundaries. The following diagram shows the structure of the CDEV packet binary stream.

Figure 2: Structure of the CDEV Packet Binary Stream (Version 1)

CDEV Packet Map
The CDEV packet map is the only component of the binary stream that is required by the protocol. This 32 bit integer is implemented as two 16 bit integers. The first 16 bits contains the version number of the packet (this will be true regardless of the packet version that is being transferred.) In version1, the next 16 bits contains a bit mask that identifies which optional elements of the packet will be included in this transmission. The following diagram shows the structure of the CDEV packet map. This 32 bit integer is encoded using XDR prior to placing it in the stream.

The meaning of the individual components of the CDEV packet map is described below.

Figure 3: CDEV Packet Map

Components of the CDEV Packet Map
Version This short integer identifies the version number of the packet. Because the rest of the CDEV packet map is version specific, the first 16 bits of all CDEV packets will identify the version of the packet.

Client ID Flag This is a boolean bit that is used to specify the presence (1) or absence (0) of the client identifier in the packet. The definition and intended usage of the client identifier is explained later.
Trans Index Flag This is a boolean bit that is used to specify the presence (1) or absence (0) of the transaction index in the packet. The definition and intended usage of the transaction index is explained later.

Cancel Trans Index Flag This is a boolean bit that is used to specify the presence (1) or absence (0) of the cancel transaction index in the packet. The definition and intended usage of the cancel transaction index is explained later.
Local Data Index Flag This is a boolean bit that is used to specify the presence (1) or absence (0) of the local data index in the packet. The definition and intended usage of the local data index is explained later.

Foreign Data Index Flag This is a boolean bit that is used to specify the presence (1) or absence (0) of the foreign data index in the packet. The definition and intended usage of the foreign data index is explained later.

Operation Code Flag This is a boolean bit that is used to specify the presence (1) or absence (0) of the operation code in the packet. The definition and intended usage of the operation code is explained later.

Device List Flag This is a boolean bit that is used to specify the presence (1) or absence (0) of the device count and the corresponding device list in the packet. The definition and intended usage of the device list is explained later.

Message Flag This is a boolean bit that is used to specify the presence (1) or absence (0) of the message string in the packet. The definition and intended usage of the message string is explained later.

Data Flag This is a boolean bit that is used to specify the presence (1) or absence (0) of the request data in the packet. The definition and intended usage of the request data is explained later.

Context Flag This is a boolean bit that is used to specify the presence (1) or absence (0) of the context data in the packet. The definition and intended usage of the context data is explained later.

Tag Map Flag This is a boolean bit that is used to specify the presence (1) or absence (0) of the tag map data in the packet. The definition and intended usage of the tag map data is explained later.

Client Identifier The client identifier is a short integer that is used by the client to identify different program elements that may be communicating with the server using a single socket. While the value is passed using four bytes in order to preserve data alignment, the value should be a short integer. The value of the client identifier is selected by the client and should be included with each message that is sent to a CDEV server. The server will always include the client identifier in its reply packets.

When the server receives the client identifier, it will merge it with the socket identifier in order to generate an identification number that will be unique within the server. In the design that is currently being implemented the 16 bit socket handle is placed in the high order word of an unsigned long integer and the 16 bit client identifier is placed in the low order word.

This 32 bit integer is encoded using XDR before placing it in the stream.

Transaction Index The transaction index is a 32 bit integer that is an index into a table of transaction objects that is stored on the client side. A transaction object is used to maintain information about a specific request that was submitted to a server. The information that is stored includes the device name, the message, the callback function to be executed upon reply and a void pointer to be sent as a parameter to the callback. The server should always return this value as part of its reply.

It should be noted that the transaction index is not merely a pointer to an object in memory on the client side. It is an index that has an embedded checksum that allows the client to verify that the specified transaction object has not been deleted. This functionality is described in detail in the documentation for the CDEV Generic Server Engine.

This 32 bit integer is encoded using XDR before placing it in the stream.

Cancel Transaction Index This is a transaction index that the client now wishes to cancel. This technique is typically used to cancel a monitor that was previously installed on a specific server attribute. The cancel transaction index should be a transaction index that was submitted as part of a prior request.

This 32 bit integer is encoded using XDR before placing it in the stream.

Local Data Index and Foreign Data Index These elements are a pair of developer usable 32 bit indexes. The original design consideration that led to the introduction of these indexes was to allow the client to define a memory structure in his local memory (such as a list of device names) and assign an integer identifier to the structure. The client would then pass the list to the server once and, at that time the server would create a similar structure and assign its own integer identifier to it. The client could then refer to the large data structure using one or both of the 32 bit integer identifiers.

This functionality is only implemented in the CDEV Generic Server Engine in so much as, the server will swap the local data index and the foreign data index when it receives a packet and will swap them back when it sends a reply. The client will always receive the packet with the data in the correct order.

These 32 bit integers are encoded using XDR before placing them in the stream.

Operation Code The operation code is a 32 bit integer that was added to the protocol in order to provide a server that supports very few message types with a mechanism to pre-parse the message at the client and then simply send an integer code. This implementation is not currently used in the CDEV Generic Server Engine.

This 32 bit integer is encoded using XDR before placing it in the stream.

Device Count The device count is a 32 bit integer that identifies the number of character strings that are included in the device list.

This 32 bit integer is encoded using XDR before placing it in the stream.

Device List This is the list of device names to which the message will be sent. The server is responsible for descending this list and submitting the message and any associated data and context to each of them.

Each string is placed in the binary stream using xdr_string function of SUN's External Data Representation. For each string XDR will write the length of the string as a four byte integer followed by the string itself. If the string length is not evenly divisible by four, then XDR will insert pad characters at the end of the string to force it to end on a four byte boundary.

Message The message string is the command that is to be sent to each device in the device list. In this version of the CDEV packet this is a single string, however, in future versions this may be expanded to be a list of message strings.

This string is inserted into the binary stream using the xdr_string function. XDR will write the length of the string as a four byte integer, followed by the string itself. If the length of the string is not evenly divisible by four, then XDR will insert pad characters at the end of the string to force it to end on a four byte boundary.

Request/Reply Data The request data element is a binary stream that represents the contents of a cdevData object. When a message is transmitted from a CDEV client to a CDEV server this element contains the contents of the outbound cdevData object that the caller provided as a parameter to the send call. When a reply is returned from the server this element contains the resultant data from the call.

The binary representation of the cdevData object is placed in the stream in two parts; the first is a four byte integer that specifies the length of the binary stream and the second part is the binary stream itself.

This length and binary representation of any cdevData object can be obtained by using the xdrExport method of the cdevData class. The xdrImport method is used to read this binary stream back into a cdevData object.

Request Context The context data element is a binary stream that represents the contents of a cdevData object that contains the context of the device/message combination at the time the message was transmitted. The CDEV Generic Server Engine is designed to only resubmit the context element when it is differs from the previous context that was transmitted through the socket. The server is responsible for using the most recent context cdevData object until a new one is received. The context associated with each transaction is currently not returned to the client when a reply is sent from the server.

Refer to the Request Data section for a description of how cdevData objects are stored and retrieved from a binary stream.

Tag Map The tag map data element is a binary stream that represents the contents of a cdevData object. This object is populated with current tag table integers and tag table strings that are in use in the client process. This data is used to construct a tag conversion table on the server that can be used to convert between client tags and server tags (and vice-versa).

Because tag names cannot be used to specify where data is inserted in this object, tag number 1 is used to store an array of integer tag numbers that are in use on the client. Tag number 2 will contain an array of corresponding tag strings.

The client should only submit this table to the server when it initially creates the connection, or when new tags are added to the client's global tag table.

Refer to the Request Data section for a description of how cdevData objects are stored and retrieved from a binary stream.





3



4. The cdevPacket Class
cdevPacket Class Overview The cdevPacket class is the base class from which all other versioned cdevPacket classes will be inherited. It defines the functionality that should be inherent in all versions of a cdevPacket object.

The cdevPacket class has the following structure.

Figure 4: Object Model of the cdevPacket Class

Attributes of the cdevPacket Class
binary This is a pointer to a character string buffer that will be used to store the address of the binary output stream. This stream is typically allocated by the class, however, an existing buffer may be attached using the attachData method. If the character string pointer has not been cleared using the detachData method, then the buffer will be deleted when the object is destroyed.

binaryLen This is the length of the binary data that is stored in the character string pointed to by the binary attribute.

Methods of the cdevPacket Class
cdevPacket cdevPacket (void);

This is the default constructor for the class. In the absence of parameters, this constructor will initialize the binary attribute to NULL and the binaryLen attribute to 0.

cdevPacket cdevPacket (cdevPacket & packet);

This is the copy constructor for the class. This method will call the virtual streamIn method to copy the binary and binaryLen attributes of the user specified packet into this object.
~cdevPacket ~cdevPacket (void);

This is the destructor for the class. If the binary attribute has not been set to NULL using the detachData method, this destructor will delete the binary buffer.

getVersion int getVersion (short & version);

This method will read a short integer from the first 16 bits of the binary stream. The method will return 0 if the version was successfully read, otherwise -1 is returned.

streamOut int streamOut (char ** stream, size_t * len);

This method is used to obtain a copy of the binary and binaryLen parameters. A pointer to the binary parameter will be placed in the stream pointer, and the binaryLen value will be placed in len. This method returns 0 to indicate success.

streamIn int streamIn (char * stream, size_t len);

This method is used to copy a new stream into the object. If the binary attribute is not NULL, then it will be deleted before a new buffer is allocated. This method returns 0 to indicate success.

attachData int attachData (char * stream, size_t len);

This method is used to assign a preallocated pointer to the internal binary attribute. If the binary attribute is not NULL, then it will be deleted before the new pointer is assigned. This method returns 0 on success.

detachData void detachData (void);

This method sets the binary attribute to NULL and the binaryLen attribute to 0. This prevents the buffer from being deleted when the object is destroyed or a new buffer is attached to the object. Before using this method the user should call the streamOut method to obtain a copy of the binary address and the binary length.





4



5. The cdevPacket1 Class
cdevPacket1 Class Overview The cdevPacket1 class supports the data elements and structure for version 1 of the CDEV Linear Internet Protocol definition. This class provides the functionality to generate and read a binary packet that is CDEV compliant.

The cdevPacket1 class has the following structure.

Figure 5: Object Model of the cdevPacket1 Class

Methods of the cdevPacket1 Class
cdevPacket1 cdevPacket1 (cdevPacket1 & packet);

This is the copy constructor for the class. This method will call the virtual streamIn method to copy the binary and binaryLen attributes of the user specified packet into this object.

cdevPacket1 cdevPacket1 (
short clientID = -1,
unsigned transIndex = 0,
unsigned cancelTransIndex = 0,
unsigned localDataIndex = 0,
unsigned foreignDataIndex = 0,
unsigned operationCode = 0,
unsigned deviceCount = 0,
char ** deviceList = NULL,
char * message = NULL,
cdevData * data = NULL,
cdevData * context = NULL,
cdevData * tagMap = NULL);

This constructor will call the set method to initialize the object with the individual data items.

~cdevPacket1 ~cdevPacket1 (void);

This is the destructor for the class. If the binary attribute has not been set to NULL using the detachData method, this destructor will delete the binary buffer.

asciiDump void asciiDump (FILE * fp = stdout);

This method is used to generate a diagnostic dump of the contents of the binary. The method will convert each of the data items to its ASCII text representation and then will print a report of the contents to the specified file pointer.

streamIn int streamIn (char * stream, size_t len);

This method is used to copy a new stream into the object. If the binary attribute is not NULL, then it will be deleted before a new buffer is allocated. This method returns 0 to indicate success.

attachData int attachData (char * stream, size_t len);

This method is used to assign a preallocated pointer to the internal binary attribute. If the binary attribute is not NULL, then it will be deleted before the new pointer is assigned. This method returns 0 on success.

getVersion virtual int getVersion (short & version)

This method reads the version from the binary stream and places the value in the user specified parameter. This method returns 0 on success or -1 if the stream is empty or the version is not contained in the stream.

getClientID int getClientID (short & clientID)

This method reads the clientID from the binary stream and places the value in the user specified parameter. This method returns 0 on success or -1 if the stream is empty or the clientID is not contained in the stream.

getTransIndex int getTransIndex (unsigned & transIndex)

This method reads the transaction index from the binary stream and places the value in the user specified parameter. This method returns 0 on success or -1 if the stream is empty or the transaction index is not contained in the stream.

getCancelTransIndex int getCancelTransIndex (unsigned & cancelTransIndex)

This method reads the cancel transaction index from the binary stream and places the value in the user specified parameter. This method returns 0 on success or -1 if the stream is empty or the cancel transaction index is not contained in the stream.

getLocalDataIndex int getLocalDataIndex (unsigned & localDataIndex)

This method reads the local data index from the binary stream and places the value in the user specified parameter. This method returns 0 on success or -1 if the stream is empty or the local data index is not contained in the stream.

getForeignDataIndex int getForeignDataIndex (unsigned & foreignDataIndex)

This method reads the foreign data index from the binary stream and places the value in the user specified parameter. This method returns 0 on success or -1 if the stream is empty or the foreign data index is not contained in the stream.

getOperationCode int getOperationCode (unsigned & operationCode)

This method reads the operation code from the binary stream and places the value in the user specified parameter. This method returns 0 on success or -1 if the stream is empty or the operation code is not contained in the stream.

getDeviceList int getDeviceList (char ** & deviceList, unsigned & deviceCount)

This method reads the device count and device list from the binary stream and places the values in the user specified parameter. This method returns 0 on success or -1 if the stream is empty or these items are not contained in the stream.

getMessage int getMessage (char * & message)

This method reads the message string from the binary stream and places the value in the user specified parameter. This method returns 0 on success or -1 if the stream is empty or the message string is not contained in the stream.

getData int getData (cdevData & data)

This method reads the request/reply data from the binary stream and places the value in the user specified parameter. This method returns 0 on success or -1 if the stream is empty or the data object is not contained in the stream.

getContext int getContext (cdevData & context)

This method reads the context data from the binary stream and places the value in the user specified parameter. This method returns 0 on success or -1 if the stream is empty or the context data is not contained in the stream.

getTagMap int getTagMap (cdevData & tagMap)

This method reads the tag map from the binary stream and places the value in the user specified parameter. This method returns 0 on success or -1 if the stream is empty or the tag map is not contained in the stream.

get int get (
short & clientID,
unsigned & transIndex,
unsigned & cancelTransIndex,
unsigned & localDataIndex,
unsigned & foreignDataIndex,
unsigned & operationCode,
unsigned & deviceCount,
char ** & deviceList,
char * & message,
cdevData & data,
cdevData & context,
cdevData & tagMap);

This method will read the entire contents of the binary stream into the user specified parameters. If a data item is not included in the stream, then its associated parameter will be set to a default value. This method returns 0 on success or -1 if the stream is empty.

set void set (
short clientID = -1,
unsigned transIndex = 0,
unsigned cancelTransIndex = 0,
unsigned localDataIndex = 0,
unsigned foreignDataIndex = 0,
unsigned operationCode = 0,
unsigned deviceCount = 0,
char ** deviceList = NULL,
char * message = NULL,
cdevData * data = NULL,
cdevData * context = NULL,
cdevData * tagMap = NULL);

This method is used to explicitly set the contents of the binary stream using the user specified parameters. If a binary buffer has already been allocated it will be deleted prior to allocating the new buffer. This new buffer will be sufficiently large to hold all of the data and the method will copy the binary representation of the data elements into the binary stream.

has... int hasClientID (void);
int hasTransIndex (void);
int hasCancelTransIndex (void);
int hasLocalDataIndex (void);
int hasForeignDataIndex (void);
int hasOperationCode (void);
int hasDeviceList (void);
int hasMessage (void);
int hasData (void);
int hasContext (void);
int hasTagMap (void);

These methods are used to query the cdevpacket1 object for the presence of each data item. The methods will return a boolean result of (1) if the item exists in the stream, or (0) if the item does not exist or the stream is empty.





5



6. The cdevMessage Class
cdevMessage Class Overview The cdevMessage class is a simple contained class that provides a way of realizing the elements that are compressed within the binary stream used by the cdevPacket1 class. The cdevMessage class has a very lightweight interface and allows the developer to access its internals through the use of public data.

The cdevMessage class has the following structure.

Figure 6: Object Model of the cdevMessage Class

Attributes of the cdevMessage Class
saveTbl This is a union that is used by the destructor when deleting the object. It contains an entry for each pointer that might be allocated within the class. If the save flag for the associated data is TRUE (non-zero), then that element will not be deleted when the cdevMessage object is destroyed.

clientID This is the identifier of the client that generated the request or will receive the reply.

transIndex This is the transaction index that is used on the client side to lookup the transaction object that corresponds to this message.

cancelTransIndex This is a previously submitted transaction that the client now wishes to cancel.

localDataIndex This is an index into a block of data in the local process that corresponds to the block of data in the remote process that is specified by the foreignDataIndex entry.

foreignDataIndex This is an index into a block of data in the remote process that corresponds to the block of data in the local process that is specified by the localDataIndex entry.

operationCode This is a developer specified operation code.

deviceCount This is the number of device strings in the deviceList entry.

deviceList This is a list of device names to which the specified message should be sent.

message This is the message string or command that should be sent to each of the specified devices in the device list. In the absence of a deviceList, this may be a command that is intrinsic to the server.

data This is the data that is associated with the request or reply.

context This is the context that was in effect at the time that the call was made on the client side. The server does not guarantee that this value will be returned with its reply.

tagMap This is a table of tag integers and tag strings that are in use on the client side of the connection. The array of tag integers is stored in tag 1, and the array of corresponding names is stored in tag 2.

Methods of the cdevMessage Class
cdevMessage cdevMessage (char * binary, size_t binaryLen);

This constructor uses the binary stream from a cdevPacket object to populate its data items.

cdevMessage cdevMessage (cdevMessage & Message)

This is the copy constructor for the class. It will make a copy of each of the items that is stored in the caller specified Message and use these values to populate its data items.

cdevMessage cdevMessage (
short ClientID = -1,
unsigned TransIndex = 0,
unsigned CancelTransIndex = 0,
unsigned LocalDataIndex = 0,
unsigned ForeignDataIndex = 0,
unsigned OperationCode = 0,
unsigned DeviceCount = 0,
char ** DeviceList = NULL,
char * Message = NULL,
cdevData * Data = NULL,
cdevData * Context = NULL,
cdevData * TagMap = NULL);

This constructor will use the user specified parameters to populate its internal data items. note that new items will be allocated and the user specified items will be duplicated.

~cdevMessage ~cdevMessage (void)

This is the destructor for the object. When the object is deleted this method will consult the saveTbl and will delete any data item that does not have its corresponding saveTbl entry set to non-zero.

clear void clear (void)

This method consults the saveTbl and then deletes any allocated data item that does not have its corresponding saveTbl entry set to non-zero. The method will then set all of the data items and pointers to their default values.

streamIn int streamIn (char * stream, size_t len)

This method is used to repopulate the cdevMessage object with new data from a cdevPacket1 object. This method will call clear to remove any existing data before loading the data specified in the binary stream. This method will return 0 on success or -1 if an error occurred.

streamOut int streamOut (char ** stream, size_t * len)

This method is used to obtain a copy of a binary stream of the data that is stored in the cdevMessage object. It is the callers responsibility to delete this data buffer when it is no longer needed. This method will return 0 on success or -1 if an error occurred.

asciiDump void asciiDump (FILE * fp = stdout)

This method is used to generate a diagnostic dump of the contents of the cdevMessage object. The method will convert each of the data items to its ASCII text representation and then will print a report of the contents to the specified file pointer.





6