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

[1955] Use PktTransform class for v6 packets.

parent d16a4ec3
......@@ -136,11 +136,6 @@ public:
/// \return false, if unpack operation failed.
bool rawUnpack();
/// \brief Update packet timestamp with current time
///
/// \throw isc::Unexpected if timestamp update failed
void updateTimestamp();
private:
size_t transid_offset_; ///< transaction id offset
......
......@@ -18,6 +18,7 @@
#include <dhcp/dhcp6.h>
#include "perf_pkt6.h"
#include "pkt_transform.h"
using namespace std;
using namespace isc;
......@@ -26,165 +27,44 @@ using namespace dhcp;
namespace isc {
namespace perfdhcp {
PerfPkt6::PerfPkt6(const uint8_t* buf, uint32_t len,
uint32_t transid, const Offset& transid_offset) :
PerfPkt6::PerfPkt6(const uint8_t* buf, size_t len) :
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),
transid_offset_(transid_offset.get()) {
transid_offset_(transid_offset) {
transid_ = transid;
}
PerfPkt6::PerfPkt6(const uint8_t* buf,
uint32_t len,
const Offset&
transid_offset) :
size_t len,
size_t transid_offset) :
Pkt6(buf, len, Pkt6::UDP),
transid_offset_(transid_offset.get()) {
transid_offset_(transid_offset) {
}
bool
PerfPkt6::rawPack() {
// Always override the packet if function is called.
bufferOut_.clear();
// Write whole buffer to output buffer.
bufferOut_.writeData(&data_[0], data_.size());
if ((transid_offset_ + 4 > data_.size()) ||
(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);
return (PktTransform::pack(dhcp::Option::V6,
data_,
options_,
transid_offset_,
transid_,
bufferOut_));
}
bool
PerfPkt6::rawUnpack() {
// Validate transaction id offset.
if ((transid_offset_ + 4 > data_.size()) ||
(transid_offset_ == 0)) {
cout << "Failed to parse packet: provided transaction id offset: "
<< transid_offset_ << " is out of bounds (expected 1.."
<< 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);
}
return (PktTransform::unpack(dhcp::Option::V6,
data_,
options_,
transid_offset_,
transid_));
}
} // namespace perfdhcp
......
......@@ -28,24 +28,18 @@ namespace perfdhcp {
///
/// This class extends functionality of \ref isc::dhcp::Pkt6 by
/// adding ability to specify options offset in DHCP message
/// and override options' contents with new option.
/// This approach is useful when we create paket object from
/// raw template buffer from file and we want to use it as
/// a base to create test packets to be sent to DHCP server.
///
/// Some of the contents of such a template packets always
/// have to be replaced e.g. transaction id, IA_NA. Other
/// contents (options) may be changed e.g. elapsed time,
/// server id.
///
/// In order to create packet from raw template buffer
/// we have to pass this buffer along with transaction id
/// 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.
/// and override options' contents.
/// This is in particular useful when we create packet object using
/// template file (do not build it dynamically). Client class
/// should read data from template file and pass data to this class
/// as buffer.
/// Contents of such packet can be later partially replaced: preciselly
/// selected options and transaction id can be replaced.
/// Transaction id and its offset in template file is passed via
/// constructor.
/// In order to replace contents of options client class has to
/// create collection of \ref LocalizedOption by adding them using
/// \ref dhcp::Pkt6::addOption.
///
/// \note: if you don't use template files simply use constructors
/// inherited from parent class and isc::dhcp::Option type instead
......@@ -53,77 +47,54 @@ namespace perfdhcp {
class PerfPkt6 : public dhcp::Pkt6 {
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.
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.
///
/// Creates new DHCPv6 message using provided buffer.
/// Transaction id and its offset are specified through this
/// constructor so as they are stored in outgoing message
/// Transaction id and its offset are specified via this
/// constructor. Transaction id is stored in outgoing message
/// when client class calls \ref PerfPkt6::rawPack.
///
/// \note This constructor should be used only for outgoing
/// messages that are created from raw buffer (e.g. read from
/// template files).
/// messages that are created from 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).
/// \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 transaction id to be stored in outgoing message.
PerfPkt6(const uint8_t* buf,
uint32_t len,
uint32_t transid,
const Offset& transid_offset);
size_t len,
size_t transid_offset,
uint32_t transid);
/// Constructor, used for incoming DHCP messages.
///
/// Creates new DHCPv6 message using provided buffer. New object
/// will keep copy of contents of provided buffer. If buffer contains
/// options at custom offsets (e.g. if packet was read from
/// template file) additional information about options'
/// offsets has to be provided - see
/// \ref isc::perfdhcp::LocalizedOption for details.
/// Creates new DHCPv6 message using provided buffer.
/// Client class may indicate which options are to be read
/// from the buffer. Such options should be added to
/// options collection using dhcp::Pkt4::addOption. Such
/// options should be of \ref LocalizedOption class.
///
/// 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
/// 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.
///
/// \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
/// specified from perfdhcp command line by the user.
///
......@@ -131,19 +102,19 @@ public:
/// \param len size of buffer of packet content.
/// \param transid_offset transaction id offset in a message.
PerfPkt6(const uint8_t* buf,
uint32_t len,
const Offset& transid_offset);
size_t len,
size_t transid_offset);
/// \brief Returns transaction id offset in packet buffer
///
/// return transaction id offset in packet buffer
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
/// extracts transaction id from it based on transaction id
/// offset provided in constructor.
/// The method copies buffer provided in constructor to
/// output buffer and replaces transaction id and selected
/// options with new data.
///
/// \note: Use this method to prepare on-wire DHCPv6 message
/// when you use template packets that require replacement
......@@ -155,52 +126,17 @@ public:
/// \brief Handles limited binary packet parsing for packets with
/// custom offsets of options and transaction id
///
/// Function handles reception of packets that have non-default values
/// of options or transaction id offsets. Use
/// \ref isc::dhcp::Pkt6::addOption to specify which options to parse.
/// Each option should be of the: isc::perfdhcp::LocalizedOption
/// type with offset value indicated.
/// Function handles parsing of packets that have custom offsets
/// of options or transaction id. Use
/// \ref isc::dhcp::Pkt4::addOption to specify which options to parse.
/// Options should be of the: isc::perfdhcp::LocalizedOption
/// 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.
bool rawUnpack();
/// \brief Update packet timestamp with current time
///
/// \throw isc::Unexpected if timestamp update failed
void updateTimestamp();
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
};
......
......@@ -77,8 +77,7 @@ public:
data[93] = 6; data[94] = 0; data[95] = 2; data[96] = 0;
data[97] = 23;
PerfPkt6* pkt = new PerfPkt6(data, sizeof(data),
0x1, PerfPkt6::Offset());
PerfPkt6* pkt = new PerfPkt6(data, sizeof(data));
return (pkt);
}
......@@ -97,8 +96,7 @@ public:
data[9] = 1; data[10] = 0; data[11] = 1; data[12] = 21;
data[13] = 158; data[14] = 60; data[15] = 22; data[16] = 0;
PerfPkt6* pkt = new PerfPkt6(data, sizeof(data),
0x1, PerfPkt6::Offset());
PerfPkt6* pkt = new PerfPkt6(data, sizeof(data));
return (pkt);
}
......@@ -110,28 +108,17 @@ TEST_F(PerfPkt6Test, Constructor) {
// Data to be used to create packet.
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.
// Use default (1) offset value and don't specify transaction id.
boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data, sizeof(data),
PerfPkt6::Offset()));
boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data, sizeof(data)));
EXPECT_EQ(6, pkt1->getData().size());
EXPECT_EQ(0, memcmp(&pkt1->getData()[0], data, sizeof(data)));
EXPECT_EQ(1, pkt1->getTransIdOffset());
// Test constructor to be used for outgoing messages.
// Use non-zero offset and specify transaction id.
boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data, sizeof(data), 0x010203,
PerfPkt6::Offset(10)));
boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data, sizeof(data),
10, 0x010203));
EXPECT_EQ(6, pkt2->getData().size());
EXPECT_EQ(0, memcmp(&pkt2->getData()[0], data, sizeof(data)));
EXPECT_EQ(0x010203, pkt2->getTransid());
......@@ -175,8 +162,7 @@ TEST_F(PerfPkt6Test, RawPackUnpack) {
const uint8_t* pkt1_output_data = static_cast<const uint8_t*>
(pkt1_output.getData());
boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(pkt1_output_data,
pkt1_output.getLength(),
PerfPkt6::Offset()));
pkt1_output.getLength()));
// Create objects specifying options offset in a packet.
// Offsets will inform pkt2 object where to read data from.
......@@ -268,8 +254,8 @@ TEST_F(PerfPkt6Test, PackTransactionId) {
// Create dummy packet that is simply filled with zeros.
boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data,
sizeof(data),
0x010203,
PerfPkt6::Offset(50)));
50,
0x010203));
// Reference data are non zero so we can detect them in dummy packet.
uint8_t ref_data[3] = { 1, 2, 3 };
......@@ -290,8 +276,8 @@ TEST_F(PerfPkt6Test, PackTransactionId) {
// Out of bounds transaction id offset.
boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data,
sizeof(data),
0x010202,
PerfPkt6::Offset(100)));
100,
0x010202));
cout << "Testing out of bounds offset. "
"This may produce spurious errors ..." << endl;
EXPECT_FALSE(pkt2->rawPack());
......@@ -308,7 +294,7 @@ TEST_F(PerfPkt6Test, UnpackTransactionId) {
// Create packet and point out that transaction id is at offset 50.
boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data,
sizeof(data),
PerfPkt6::Offset(50)));
50));
// Get transaction id out of buffer and store in class member.
ASSERT_TRUE(pkt1->rawUnpack());
......@@ -318,7 +304,7 @@ TEST_F(PerfPkt6Test, UnpackTransactionId) {
// Out of bounds transaction id offset.
boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data,
sizeof(data),
PerfPkt6::Offset(300)));
300));
cout << "Testing out of bounds offset. "
"This may produce spurious errors ..." << endl;
EXPECT_FALSE(pkt2->rawUnpack());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment