AgentXcpp  Revision:0.1.1
Internals Documentation
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Friends Pages
Parsing incoming PDUs

This section explains how PDU parsing is done in agentXcpp.

AgentX PDUs are read from a stream, constructing C++ objects which represent the PDUs and all their parts (such as varbinds, for example). In general, the C++ objects, such as OpenPDU, varbind, oid or Integer, are created by providing an iterator (pointing into a buffer) to their constructors. The constructor uses the iterator to read the serialized form of the object and construct the C++ object accordingly. Along the way, the iterator is modified to point behind the object which was just deserialized.

An example of such a constructor is agentxcpp::varbind::varbind(binary::const_iterator& pos, binary::const_iterator& end, bool big_endian). It takes an iterator ('pos') and begins parsing at where 'pos' points to. While reading, the varbind object is constructed. A varbind always contains (at least) an oid. The varbind constructor therefore creates an oid object by passing the 'pos' iterator to the constructor of the oid class, which reads the serialized oid and constructs the oid object. If needed, another variable is created the same way (e.g. an Integer or an Octet_String). When the varbind object is fully constructed, the 'pos' iterator points to the position behind the varbind and the constructor returns. Note that the iterator is modified by the constructor. The caller may then use 'pos' to create the next object, until the buffer is completely parsed.

The 'end' iterator seen in the above constructor prototype is needed to know the end of the buffer. Parse constructors use it to detect missing data at the end of the buffer. For example, the serialized form of an Integer is 4 bytes in size; if pos points to the last byte in the buffer, the integer is corrupted. This can be detected using the 'end' iterator.

Reading a PDU is initiated by calling the static class function agentxcpp::PDU::get_pdu(boost::asio::local::stream_protocol::socket& in, unsigned timeout=1000). The function first reads the PDU from the socket into a buffer. It then interprets the PDU header and creates a concrete PDU object (e.g. OpenPDU) corresponding to the type field found in the header. The PDU and its subobjects are created as described above. Finally, a pointer to the created object is returned, and the caller is responsible for deleting it when it is not longer needed.

The agentxcpp::PDU class cannot be instantiated itself, as it does not represent a PDU type defined in RFC 2741. It serves as base class for the concrete PDU types. Each concrete PDU type (for example the OpenPDU class) inherits from PDU. The constructor of such a concrete class must call the constructor of the PDU class, which parses the header. Example:

OpenPDU::OpenPDU(binary::const_iterator& pos, bool big_endian)
: PDU(pos, big_endian) // parse header
{
timeout = *pos++; // parse timeout field
pos += 3; // skip reserved fields
id = oid(pos, big_endian); // parse oid
descr = Octet_String(pos, big_endian); // parse desciption
}

Note that the header is parsed two times. The first time is in the agentxcpp::PDU::get_pdu() function (described above), where the header is inspected to determine the payload length, the PDU type and the endianess of the PDU. The protocol version is also checked in PDU::get_pdu(). The second time is in the agentxcpp::PDU::PDU() constructor, where the sessionID, transactionID, packetID and some flags are picked up.