Commit 53dfacdd authored by Marcin Siodelski's avatar Marcin Siodelski

[1955] Use PktTransform class for v6 packets.

parent d16a4ec3
...@@ -136,11 +136,6 @@ public: ...@@ -136,11 +136,6 @@ public:
/// \return false, if unpack operation failed. /// \return false, if unpack operation failed.
bool rawUnpack(); bool rawUnpack();
/// \brief Update packet timestamp with current time
///
/// \throw isc::Unexpected if timestamp update failed
void updateTimestamp();
private: private:
size_t transid_offset_; ///< transaction id offset size_t transid_offset_; ///< transaction id offset
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <dhcp/dhcp6.h> #include <dhcp/dhcp6.h>
#include "perf_pkt6.h" #include "perf_pkt6.h"
#include "pkt_transform.h"
using namespace std; using namespace std;
using namespace isc; using namespace isc;
...@@ -26,165 +27,44 @@ using namespace dhcp; ...@@ -26,165 +27,44 @@ using namespace dhcp;
namespace isc { namespace isc {
namespace perfdhcp { namespace perfdhcp {
PerfPkt6::PerfPkt6(const uint8_t* buf, uint32_t len, PerfPkt6::PerfPkt6(const uint8_t* buf, size_t len) :
uint32_t transid, const Offset& transid_offset) : Pkt6(buf, len),
transid_offset_(1) {
}
PerfPkt6::PerfPkt6(const uint8_t* buf,
size_t len,
size_t transid_offset,
uint32_t transid) :
Pkt6(buf, len, Pkt6::UDP), Pkt6(buf, len, Pkt6::UDP),
transid_offset_(transid_offset.get()) { transid_offset_(transid_offset) {
transid_ = transid; transid_ = transid;
} }
PerfPkt6::PerfPkt6(const uint8_t* buf, PerfPkt6::PerfPkt6(const uint8_t* buf,
uint32_t len, size_t len,
const Offset& size_t transid_offset) :
transid_offset) :
Pkt6(buf, len, Pkt6::UDP), Pkt6(buf, len, Pkt6::UDP),
transid_offset_(transid_offset.get()) { transid_offset_(transid_offset) {
} }
bool bool
PerfPkt6::rawPack() { PerfPkt6::rawPack() {
// Always override the packet if function is called. return (PktTransform::pack(dhcp::Option::V6,
bufferOut_.clear(); data_,
// Write whole buffer to output buffer. options_,
bufferOut_.writeData(&data_[0], data_.size()); transid_offset_,
transid_,
if ((transid_offset_ + 4 > data_.size()) || bufferOut_));
(transid_offset_ == 0)) {
cout << "Failed to build packet: provided transaction id offset: "
<< transid_offset_ << " is out of bounds (expected 1.."
<< data_.size()-1 << ")." << endl;
return (false);
}
// Seek to the transaction id position in output buffer.
bufferOut_.clear();
bufferOut_.skip(transid_offset_);
try {
// Write 3 octets of transaction id
bufferOut_.writeUint8(transid_ >> 16 & 0xFF);
bufferOut_.writeUint8(transid_ >> 8 & 0xFF);
bufferOut_.writeUint8(transid_ & 0xFF);
// Buffer pointer is at the end of transaction id.
// We have to seek to the end of buffer so as data don't
// get truncated.
bufferOut_.skip(data_.size() - bufferOut_.getLength());
// We already have packet template stored in output buffer
// but still some options have to be updated if client
// specified them along with their offsets in the buffer.
rawPackOptions();
} catch (const isc::BadValue& e) {
cout << "Building packet failed: " << e.what() << endl;
return (false);
}
return (true);
} }
bool bool
PerfPkt6::rawUnpack() { PerfPkt6::rawUnpack() {
// Validate transaction id offset. return (PktTransform::unpack(dhcp::Option::V6,
if ((transid_offset_ + 4 > data_.size()) || data_,
(transid_offset_ == 0)) { options_,
cout << "Failed to parse packet: provided transaction id offset: " transid_offset_,
<< transid_offset_ << " is out of bounds (expected 1.." transid_));
<< data_.size()-1 << ")." << endl;
return (false);
}
// Read transaction id from the packet at the given offset.
transid_ = ( (data_[transid_offset_]) << 16 ) +
((data_[transid_offset_ + 1]) << 8) + (data_[transid_offset_ + 2]);
transid_ = transid_ & 0xffffff;
// Get message type - assume it is first octet in the packet.
msg_type_ = data_[0];
try {
rawUnpackOptions();
} catch (const isc::BadValue& e) {
cout << "Packet parsing failed: " << e.what() << endl;
return (false);
}
return (true);
}
void
PerfPkt6::rawPackOptions() {
try {
// If there are any options on the list, we will use provided
// options offsets to override them in the output buffer
// with new contents.
for (Option::OptionCollection::const_iterator it = options_.begin();
it != options_.end(); ++it) {
// Get options with their position (offset).
boost::shared_ptr<LocalizedOption> option =
boost::dynamic_pointer_cast<LocalizedOption>(it->second);
uint32_t offset = option->getOffset();
if ((offset == 0) ||
(offset + option->len() > data_.size())) {
isc_throw(isc::BadValue,
"option offset for option: " << option->getType()
<< " is out of bounds (expected 1.."
<< data_.size() - option->len() << ")");
}
bufferOut_.clear();
bufferOut_.skip(offset);
// Replace existing option with new value.
option->pack(bufferOut_);
}
// Seek to the end of the buffer to make sure its size is correct.
bufferOut_.skip(data_.size() - bufferOut_.getLength());
}
catch (const Exception&) {
isc_throw(isc::BadValue, "failed to pack options into buffer.");
}
}
void
PerfPkt6::rawUnpackOptions() {
for (Option::OptionCollection::const_iterator it = options_.begin();
it != options_.end(); ++it) {
LocalizedOptionPtr option =
boost::dynamic_pointer_cast<LocalizedOption>(it->second);
size_t opt_pos = option->getOffset();
if (opt_pos == 0) {
isc_throw(isc::BadValue, "failed to unpack packet from raw buffer "
"(Option position not specified)");
} else if (opt_pos + 4 > data_.size()) {
isc_throw(isc::BadValue,
"failed to unpack options from from raw buffer "
"(Option position out of bounds)");
}
size_t offset = opt_pos;
// Get option type from first two octets.
uint16_t opt_type = data_[offset] * 256 + data_[offset + 1];
if (opt_type != option->getType()) {
isc_throw(isc::BadValue,
"failed to unpack option from raw buffer "
"(option type mismatch)");
}
// Get length from next two octets.
offset += 2;
uint16_t opt_len = data_[offset] * 256 + data_[offset + 1];
if (offset + opt_len > data_.size()) {
isc_throw(isc::BadValue,
"failed to unpack option from raw buffer "
"(option truncated)");
}
// Seek to actual option data and replace it.
offset += 2;
option->setData(data_.begin() + offset,
data_.begin() + offset + opt_len);
}
} }
} // namespace perfdhcp } // namespace perfdhcp
......
...@@ -28,24 +28,18 @@ namespace perfdhcp { ...@@ -28,24 +28,18 @@ namespace perfdhcp {
/// ///
/// This class extends functionality of \ref isc::dhcp::Pkt6 by /// This class extends functionality of \ref isc::dhcp::Pkt6 by
/// adding ability to specify options offset in DHCP message /// adding ability to specify options offset in DHCP message
/// and override options' contents with new option. /// and override options' contents.
/// This approach is useful when we create paket object from /// This is in particular useful when we create packet object using
/// raw template buffer from file and we want to use it as /// template file (do not build it dynamically). Client class
/// a base to create test packets to be sent to DHCP server. /// should read data from template file and pass data to this class
/// /// as buffer.
/// Some of the contents of such a template packets always /// Contents of such packet can be later partially replaced: preciselly
/// have to be replaced e.g. transaction id, IA_NA. Other /// selected options and transaction id can be replaced.
/// contents (options) may be changed e.g. elapsed time, /// Transaction id and its offset in template file is passed via
/// server id. /// constructor.
/// /// In order to replace contents of options client class has to
/// In order to create packet from raw template buffer /// create collection of \ref LocalizedOption by adding them using
/// we have to pass this buffer along with transaction id /// \ref dhcp::Pkt6::addOption.
/// offset. Class will read transaction id from the buffer.
/// Next, in order to replace contents of selected options
/// in a template packet, we need to add these selected options
/// to packet object using addOption() method. Please note
/// that options must be of the
/// \ref isc::perfdhcp::LocalizedOption type.
/// ///
/// \note: if you don't use template files simply use constructors /// \note: if you don't use template files simply use constructors
/// inherited from parent class and isc::dhcp::Option type instead /// inherited from parent class and isc::dhcp::Option type instead
...@@ -53,77 +47,54 @@ namespace perfdhcp { ...@@ -53,77 +47,54 @@ namespace perfdhcp {
class PerfPkt6 : public dhcp::Pkt6 { class PerfPkt6 : public dhcp::Pkt6 {
public: public:
/// \brief Represents offset value.
///
/// This class represent offsets for DHCP message fields
/// like transaction id. Constructors of PerfPkt6 take
/// number of arguments of integer type so it is easy to
/// mess up arguments of constructors and for example
/// swap transaction id with its offset.
/// Use of this class implies that client class has to
/// explicitely use constructor of this class to pass
/// offset value. This should prevent mistakes and save some
/// time on debugging.
class Offset {
public:
/// \brief Default constructor
explicit Offset() :
offset_(1) { };
/// \brief Constructor
///
/// \param offset offset value
explicit Offset(size_t offset) :
offset_(offset) { };
/// \brief Returns offset value.
///
/// \return offset value.
size_t get() const { return offset_; };
private:
size_t offset_; ///< offset value
};
/// Localized option pointer type. /// Localized option pointer type.
typedef boost::shared_ptr<LocalizedOption> LocalizedOptionPtr; typedef boost::shared_ptr<LocalizedOption> LocalizedOptionPtr;
/// \brief Constructor, used for outgoing and incoming messages
///
/// This constructor initializes transaction id and
/// transaction id offset of the packet with default
/// values.
///
/// \param buf buffer holding contents of the message.
/// \param len length of the data in the buffer.
PerfPkt6(const uint8_t* buf, size_t len);
/// \brief Constructor, used for outgoing DHCP messages. /// \brief Constructor, used for outgoing DHCP messages.
/// ///
/// Creates new DHCPv6 message using provided buffer. /// Creates new DHCPv6 message using provided buffer.
/// Transaction id and its offset are specified through this /// Transaction id and its offset are specified via this
/// constructor so as they are stored in outgoing message /// constructor. Transaction id is stored in outgoing message
/// when client class calls \ref PerfPkt6::rawPack. /// when client class calls \ref PerfPkt6::rawPack.
/// ///
/// \note This constructor should be used only for outgoing /// \note This constructor should be used only for outgoing
/// messages that are created from raw buffer (e.g. read from /// messages that are created from template files.
/// template files).
/// ///
/// \param buf buffer holiding contents of the message (this can /// \param buf buffer holding contents of the message (this can
/// be directly read from template file). /// be directly read from template file).
/// \param len length of the data in the buffer. /// \param len length of the data in the buffer.
/// \param transid transaction id to be stored in outgoing message.
/// \param transid_offset transaction id offset in outgoing message. /// \param transid_offset transaction id offset in outgoing message.
/// \param transid transaction id to be stored in outgoing message.
PerfPkt6(const uint8_t* buf, PerfPkt6(const uint8_t* buf,
uint32_t len, size_t len,
uint32_t transid, size_t transid_offset,
const Offset& transid_offset); uint32_t transid);
/// Constructor, used for incoming DHCP messages. /// Constructor, used for incoming DHCP messages.
/// ///
/// Creates new DHCPv6 message using provided buffer. New object /// Creates new DHCPv6 message using provided buffer.
/// will keep copy of contents of provided buffer. If buffer contains /// Client class may indicate which options are to be read
/// options at custom offsets (e.g. if packet was read from /// from the buffer. Such options should be added to
/// template file) additional information about options' /// options collection using dhcp::Pkt4::addOption. Such
/// offsets has to be provided - see /// options should be of \ref LocalizedOption class.
/// \ref isc::perfdhcp::LocalizedOption for details.
/// ///
/// Transaction id offset point to location of raw data where /// Transaction id offset points to location where
/// transaction id field is stored. The transaction id will /// transaction id field is stored. The transaction id will
/// be read from this location when PerfPkt6::rawUnpack is /// be read from this location when PerfPkt4::rawUnpack is
/// called. The transid_ class member will be updated accordingly. /// called. The transid_ class member will be updated accordingly.
/// ///
/// \note use this constructor only in case you want to create /// \note use this constructor only in case you want to create
/// incoming DHCPv6 object from the raw buffer /// incoming DHCPv4 object from the raw buffer
/// and you know options offsets. Options offsets are /// and you know options offsets. Options offsets are
/// specified from perfdhcp command line by the user. /// specified from perfdhcp command line by the user.
/// ///
...@@ -131,19 +102,19 @@ public: ...@@ -131,19 +102,19 @@ public:
/// \param len size of buffer of packet content. /// \param len size of buffer of packet content.
/// \param transid_offset transaction id offset in a message. /// \param transid_offset transaction id offset in a message.
PerfPkt6(const uint8_t* buf, PerfPkt6(const uint8_t* buf,
uint32_t len, size_t len,
const Offset& transid_offset); size_t transid_offset);
/// \brief Returns transaction id offset in packet buffer /// \brief Returns transaction id offset in packet buffer
/// ///
/// return transaction id offset in packet buffer /// return transaction id offset in packet buffer
size_t getTransIdOffset() const { return transid_offset_; }; size_t getTransIdOffset() const { return transid_offset_; };
/// \brief Prepares on-wire format from raw buffer /// \brief Prepares on-wire format from raw buffer.
/// ///
/// The method copies user buffer to output buffer and /// The method copies buffer provided in constructor to
/// extracts transaction id from it based on transaction id /// output buffer and replaces transaction id and selected
/// offset provided in constructor. /// options with new data.
/// ///
/// \note: Use this method to prepare on-wire DHCPv6 message /// \note: Use this method to prepare on-wire DHCPv6 message
/// when you use template packets that require replacement /// when you use template packets that require replacement
...@@ -155,52 +126,17 @@ public: ...@@ -155,52 +126,17 @@ public:
/// \brief Handles limited binary packet parsing for packets with /// \brief Handles limited binary packet parsing for packets with
/// custom offsets of options and transaction id /// custom offsets of options and transaction id
/// ///
/// Function handles reception of packets that have non-default values /// Function handles parsing of packets that have custom offsets
/// of options or transaction id offsets. Use /// of options or transaction id. Use
/// \ref isc::dhcp::Pkt6::addOption to specify which options to parse. /// \ref isc::dhcp::Pkt4::addOption to specify which options to parse.
/// Each option should be of the: isc::perfdhcp::LocalizedOption /// Options should be of the: isc::perfdhcp::LocalizedOption
/// type with offset value indicated. /// type with offset values provided. Each added option will
/// be updated with actual data read from the binary packet buffer.
/// ///
/// \return false, if unpack operation failed. /// \return false, if unpack operation failed.
bool rawUnpack(); bool rawUnpack();
/// \brief Update packet timestamp with current time
///
/// \throw isc::Unexpected if timestamp update failed
void updateTimestamp();
private: private:
/// \brief Updates options in the output buffer
///
/// The method uses options collection added to object
/// of this class with \ref dhcp::Pkt6::addOption to
/// on-wire data. Option objects has to be of
/// \ref perfdhcp::LocalizedOption type and should
/// have non-zero values of offsets specified.
/// This method will use these offsets to seek to
/// given position in output buffer and update option
/// on-wire data with contents of option's buffer.
///
/// \throw isc::Unexpected if options update failed.
void rawPackOptions();
/// \brief Reads contents of specified options from buffer
///
/// The method reads options data from the copy of the buffer
/// provided in constructor and stores data in options
/// objects that belong to options collection.
/// Client class that constructs this object has to create
/// options collection prior to calling \ref rawUnpack
/// method that in turn calls this method.
/// If option is not added to options collection, it will
/// not be added by this method. This method will rather
/// skip update of such an option even if it is present
/// in packet's buffer.
///
/// \throw isc::Unexpected if options unpack failed.
void rawUnpackOptions();
size_t transid_offset_; ///< transaction id offset size_t transid_offset_; ///< transaction id offset
}; };
......
...@@ -77,8 +77,7 @@ public: ...@@ -77,8 +77,7 @@ public:
data[93] = 6; data[94] = 0; data[95] = 2; data[96] = 0; data[93] = 6; data[94] = 0; data[95] = 2; data[96] = 0;
data[97] = 23; data[97] = 23;
PerfPkt6* pkt = new PerfPkt6(data, sizeof(data), PerfPkt6* pkt = new PerfPkt6(data, sizeof(data));
0x1, PerfPkt6::Offset());
return (pkt); return (pkt);
} }
...@@ -97,8 +96,7 @@ public: ...@@ -97,8 +96,7 @@ public:
data[9] = 1; data[10] = 0; data[11] = 1; data[12] = 21; data[9] = 1; data[10] = 0; data[11] = 1; data[12] = 21;
data[13] = 158; data[14] = 60; data[15] = 22; data[16] = 0; data[13] = 158; data[14] = 60; data[15] = 22; data[16] = 0;
PerfPkt6* pkt = new PerfPkt6(data, sizeof(data), PerfPkt6* pkt = new PerfPkt6(data, sizeof(data));
0x1, PerfPkt6::Offset());
return (pkt); return (pkt);
} }
...@@ -110,28 +108,17 @@ TEST_F(PerfPkt6Test, Constructor) { ...@@ -110,28 +108,17 @@ TEST_F(PerfPkt6Test, Constructor) {
// Data to be used to create packet. // Data to be used to create packet.
uint8_t data[] = { 0, 1, 2, 3, 4, 5 }; uint8_t data[] = { 0, 1, 2, 3, 4, 5 };
// Test constructors of Offset class.
PerfPkt6::Offset of1(0);
EXPECT_EQ(0, of1.get());
PerfPkt6::Offset of2;
EXPECT_EQ(1, of2.get());
PerfPkt6::Offset of3(10);
EXPECT_EQ(10, of3.get());
// Test constructor to be used for incoming messages. // Test constructor to be used for incoming messages.
// Use default (1) offset value and don't specify transaction id. // Use default (1) offset value and don't specify transaction id.
boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data, sizeof(data), boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data, sizeof(data)));
PerfPkt6::Offset()));
EXPECT_EQ(6, pkt1->getData().size()); EXPECT_EQ(6, pkt1->getData().size());
EXPECT_EQ(0, memcmp(&pkt1->getData()[0], data, sizeof(data))); EXPECT_EQ(0, memcmp(&pkt1->getData()[0], data, sizeof(data)));
EXPECT_EQ(1, pkt1->getTransIdOffset()); EXPECT_EQ(1, pkt1->getTransIdOffset());
// Test constructor to be used for outgoing messages. // Test constructor to be used for outgoing messages.
// Use non-zero offset and specify transaction id. // Use non-zero offset and specify transaction id.
boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data, sizeof(data), 0x010203, boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data, sizeof(data),
PerfPkt6::Offset(10))); 10, 0x010203));
EXPECT_EQ(6, pkt2->getData().size()); EXPECT_EQ(6, pkt2->getData().size());
EXPECT_EQ(0, memcmp(&pkt2->getData()[0], data, sizeof(data))); EXPECT_EQ(0, memcmp(&pkt2->getData()[0], data, sizeof(data)));
EXPECT_EQ(0x010203, pkt2->getTransid()); EXPECT_EQ(0x010203, pkt2->getTransid());
...@@ -175,8 +162,7 @@ TEST_F(PerfPkt6Test, RawPackUnpack) { ...@@ -175,8 +162,7 @@ TEST_F(PerfPkt6Test, RawPackUnpack) {
const uint8_t* pkt1_output_data = static_cast<const uint8_t*> const uint8_t* pkt1_output_data = static_cast<const uint8_t*>
(pkt1_output.getData()); (pkt1_output.getData());
boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(pkt1_output_data, boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(pkt1_output_data,
pkt1_output.getLength(), pkt1_output.getLength()));
PerfPkt6::Offset()));
// Create objects specifying options offset in a packet. // Create objects specifying options offset in a packet.
// Offsets will inform pkt2 object where to read data from. // Offsets will inform pkt2 object where to read data from.
...@@ -268,8 +254,8 @@ TEST_F(PerfPkt6Test, PackTransactionId) { ...@@ -268,8 +254,8 @@ TEST_F(PerfPkt6Test, PackTransactionId) {
// Create dummy packet that is simply filled with zeros. // Create dummy packet that is simply filled with zeros.
boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data, boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data,
sizeof(data), sizeof(data),
0x010203, 50,
PerfPkt6::Offset(50))); 0x010203));
// Reference data are non zero so we can detect them in dummy packet. // Reference data are non zero so we can detect them in dummy packet.
uint8_t ref_data[3] = { 1, 2, 3 }; uint8_t ref_data[3] = { 1, 2, 3 };
...@@ -290,8 +276,8 @@ TEST_F(PerfPkt6Test, PackTransactionId) { ...@@ -290,8 +276,8 @@ TEST_F(PerfPkt6Test, PackTransactionId) {
// Out of bounds transaction id offset. // Out of bounds transaction id offset.
boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data, boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data,
sizeof(data), sizeof(data),
0x010202, 100,
PerfPkt6::Offset(100))); 0x010202));
cout << "Testing out of bounds offset. " cout << "Testing out of bounds offset. "
"This may produce spurious errors ..." << endl; "This may produce spurious errors ..." << endl;
EXPECT_FALSE(pkt2->rawPack()); EXPECT_FALSE(pkt2->rawPack());
...@@ -308,7 +294,7 @@ TEST_F(PerfPkt6Test, UnpackTransactionId) { ...@@ -308,7 +294,7 @@ TEST_F(PerfPkt6Test, UnpackTransactionId) {
// Create packet and point out that transaction id is at offset 50. // Create packet and point out that transaction id is at offset 50.
boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data, boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data,
sizeof(data), sizeof(data),
PerfPkt6::Offset(50))); 50));
// Get transaction id out of buffer and store in class member. // Get transaction id out of buffer and store in class member.
ASSERT_TRUE(pkt1->rawUnpack()); ASSERT_TRUE(pkt1->rawUnpack());
...@@ -318,7 +304,7 @@ TEST_F(PerfPkt6Test, UnpackTransactionId) { ...@@ -318,7 +304,7 @@ TEST_F(PerfPkt6Test, UnpackTransactionId) {
// Out of bounds transaction id offset. // Out of bounds transaction id offset.
boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data, boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data,
sizeof(data), sizeof(data),
PerfPkt6::Offset(300))); 300));
cout << "Testing out of bounds offset. " cout << "Testing out of bounds offset. "
"This may produce spurious errors ..." << endl; "This may produce spurious errors ..." << endl;
EXPECT_FALSE(pkt2->rawUnpack()); EXPECT_FALSE(pkt2->rawUnpack());
......
Markdown is supported
0% or