AgentXcpp  Version:0.3
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, OidValue or IntegerValue, 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 Varbind::Varbind(binary::const_iterator&, const binary::const_iterator&, bool). 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 OidValue. The Varbind constructor therefore creates an OidValue object by passing the 'pos' iterator to the constructor of the OidValue class, which reads the serialized OidValue and constructs the OidValue object. If needed, another variable is created the same way (e.g. an IntegerValue or an OctetStringValue). 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.

Parsing a PDU is initiated by calling the static class function agentxcpp::PDU::parse_pdu(agentxcpp::binary). The function reads the PDU header from the given buffer 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, by using their parse constructors. Finally, a shared pointer to the created object is returned.

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,
const binary::const_iterator& end,
bool big_endian)
: PDU(pos, big_endian) // parse header
: PDU(pos, end, big_endian)
{
timeout = *pos++; // parse timeout field
pos += 3; // skip reserved fields
id = OidValue(pos, end, big_endian); // parse OidValue
descr = OctetStringValue(pos, end, big_endian); // parse description
}

Note that the header is parsed two times. The first time is in the agentxcpp::PDU::parse_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::parse_pdu(). The second time is in the agentxcpp::PDU::PDU() constructor, where the sessionID, transactionID, packetID and some flags are picked up.