Commit ff1617fd authored by Marcin Siodelski's avatar Marcin Siodelski

[1956] PerfPkt6 class code improvements.

Improved error checks, comments, additional unit tests added.
parent 9cd5b8d8
......@@ -25,6 +25,7 @@ endif
pkglibexec_PROGRAMS = perfdhcp
perfdhcp_SOURCES = perfdhcp.cc
perfdhcp_SOURCES += localized_option.h
perfdhcp_SOURCES += command_options.cc command_options.h
perfdhcp_SOURCES += perf_pkt6.cc perf_pkt6.h
......
......@@ -22,13 +22,13 @@ namespace perfdhcp {
/// \brief DHCP option at specific offset
///
/// This class represents DHCP option at specified
/// This class represents DHCP option with data placed at specified
/// offset in DHCP message.
/// Objects of this type are intended to be used when DHCP packets
/// are created from templates (e.g. read from template file).
/// Such packets have number of that have to be replaced before
/// sending: e.g. DUID can be randomized. If option of this type
/// is added to \ref PerfPkt6 options collection,
/// Such packets have number of options with contents that have to be
/// replaced before sending: e.g. DUID can be randomized.
/// If option of this type is added to \ref PerfPkt6 options collection,
/// \ref perfdhcp::PerfPkt6 will call \ref getOffset on this object
/// to retrieve user-defined option position and replace contents of
/// the output buffer at this offset before packet is sent to the server.
......@@ -47,7 +47,9 @@ public:
/// \param u specifies universe (V4 or V6)
/// \param type option type (0-255 for V4 and 0-65535 for V6)
/// \param data content of the option
LocalizedOption(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& data) :
LocalizedOption(dhcp::Option::Universe u,
uint16_t type,
const dhcp::OptionBuffer& data) :
dhcp::Option(u, type, data),
offset_(0) {
}
......@@ -59,7 +61,9 @@ public:
/// \param type option type (0-255 for V4 and 0-65535 for V6)
/// \param data content of the option
/// \param offset location of option in a packet (zero is default)
LocalizedOption(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& data,
LocalizedOption(dhcp::Option::Universe u,
uint16_t type,
const dhcp::OptionBuffer& data,
const size_t offset) :
dhcp::Option(u, type, data),
offset_(offset) {
......@@ -75,14 +79,16 @@ public:
/// \param first iterator to the first element that should be copied
/// \param last iterator to the next element after the last one
/// to be copied.
LocalizedOption(dhcp::Option::Universe u, uint16_t type, dhcp::OptionBufferConstIter first,
LocalizedOption(dhcp::Option::Universe u,
uint16_t type,
dhcp::OptionBufferConstIter first,
dhcp::OptionBufferConstIter last) :
dhcp::Option(u, type, first, last),
offset_(0) {
}
/// \brief Constructor, used to create positioned option from buffer iterators
/// \brief Constructor, used to create option from buffer iterators
///
/// This contructor is similar to the previous one, but it does not take
/// the whole vector<uint8_t>, but rather subset of it.
......@@ -93,7 +99,9 @@ public:
/// \param last iterator to the next element after the last one
/// to be copied.
/// \param offset offset of option in a packet (zero is default)
LocalizedOption(dhcp::Option::Universe u, uint16_t type, dhcp::OptionBufferConstIter first,
LocalizedOption(dhcp::Option::Universe u,
uint16_t type,
dhcp::OptionBufferConstIter first,
dhcp::OptionBufferConstIter last, const size_t offset) :
dhcp::Option(u, type, first, last),
offset_(offset) {
......
......@@ -21,31 +21,62 @@
using namespace std;
using namespace isc;
using namespace dhcp;
namespace isc {
namespace perfdhcp {
PerfPkt6::PerfPkt6(const uint8_t* buf, uint32_t len, size_t transid_offset) :
Pkt6(buf, len, dhcp::Pkt6::UDP),
transid_offset_(transid_offset) {
PerfPkt6::PerfPkt6(const uint8_t* buf, uint32_t len,
uint32_t transid, const Offset& transid_offset) :
Pkt6(buf, len, Pkt6::UDP),
transid_offset_(transid_offset.get()) {
transid_ = transid;
}
// Let's reset timestamp of the packet
memset(static_cast<void*>(&time_stamp_), 0, sizeof(time_stamp_));
PerfPkt6::PerfPkt6(const uint8_t* buf,
uint32_t len,
const Offset&
transid_offset) :
Pkt6(buf, len, Pkt6::UDP),
transid_offset_(transid_offset.get()) {
}
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 {
// Always override the packet if function is called.
bufferOut_.clear();
// Write whole buffer to output buffer.
bufferOut_.writeData(&data_[0], data_.size());
// We already have packet template stored in out buffer
// 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 (isc::Unexpected& e) {
cout << "Failed to build packet: " << e.what() << endl;
} catch (isc::BadValue& e) {
cout << "Building packet failed: " << e.what() << endl;
return (false);
}
return (true);
......@@ -53,6 +84,15 @@ PerfPkt6::rawPack() {
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]);
......@@ -62,7 +102,7 @@ PerfPkt6::rawUnpack() {
msg_type_ = data_[0];
try {
rawUnpackOptions();
} catch (isc::Unexpected& e) {
} catch (isc::BadValue& e) {
cout << "Packet parsing failed: " << e.what() << endl;
return (false);
}
......@@ -73,66 +113,77 @@ PerfPkt6::rawUnpack() {
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 (dhcp::Option::OptionCollection::const_iterator it = options_.begin();
// 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 position = option->getOffset();
if (position > 0) {
bufferOut_.clear();
bufferOut_.skip(position);
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 size is correct.
// 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::Unexpected, "Failed to build packet (Option build failed");
isc_throw(isc::BadValue, "failed to pack options into buffer.");
}
}
void
PerfPkt6::rawUnpackOptions() {
for (dhcp::Option::OptionCollection::const_iterator it = options_.begin();
for (Option::OptionCollection::const_iterator it = options_.begin();
it != options_.end(); ++it) {
LocalizedOptionPtr option = boost::dynamic_pointer_cast<LocalizedOption>(it->second);
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 "
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 "
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)");
"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];
offset += 2;
if (offset + opt_len > data_.size()) {
isc_throw(isc::BadValue,
"Failed to unpack option from raw buffer (Option truncated)");
"failed to unpack option from raw buffer "
"(option truncated)");
}
option->setData(data_.begin() + offset, data_.begin() + offset + opt_len);
}
}
void
PerfPkt6::updateTimestamp() {
if (clock_gettime(CLOCK_REALTIME, &time_stamp_) < 0) {
isc_throw(isc::Unexpected, "Failed to get timestamp for packet");
// Seek to actual option data and replace it.
offset += 2;
option->setData(data_.begin() + offset,
data_.begin() + offset + opt_len);
}
}
......
......@@ -52,10 +52,63 @@ 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;
/// Constructor, used in message transmission
/// \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
/// 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).
///
/// \param buf buffer holiding 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.
PerfPkt6(const uint8_t* buf,
uint32_t len,
uint32_t transid,
const Offset& transid_offset);
/// 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
......@@ -64,33 +117,28 @@ public:
/// offsets has to be provided - see
/// \ref isc::perfdhcp::LocalizedOption for details.
///
/// Transaction id is not considered DHCP option so
/// we pass it to constructor as extra argument. This is
/// required if transaction id offset differs from the
/// default one for DHCPv6 messages (ocets 2-4).
/// Transaction id offset point to location of raw data where
/// transaction id field is stored. The transaction id will
/// be read from this location when PerfPkt6::rawUnpack is
/// called. The transid_ class member will be updated accordingly.
///
/// \note use this constructor only in case you want to create
/// DHCPv6 message (incoming or outgoing) from the raw buffer
/// incoming DHCPv6 object from the raw buffer
/// and you know options offsets. Options offsets are
/// specified from perfdhcp command line by the user.
///
/// \param buf pointer to a buffer of received packet content
/// \param len size of buffer of packet content
/// \param xid_off transaction id offset in a packet
/// \param buf pointer to a buffer of received packet content.
/// \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,
size_t transid_offset_);
const Offset& 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 Returns current packet timestamp
///
/// \return current packet timestamp
timespec getTimestamp() const { return time_stamp_; }
/// \brief Prepares on-wire format from raw buffer
///
/// The method copies user buffer to output buffer and
......@@ -154,7 +202,6 @@ private:
void rawUnpackOptions();
size_t transid_offset_; ///< transaction id offset
timespec time_stamp_; ///< time stamp of last pack or unpack
};
......
......@@ -33,20 +33,22 @@ using namespace isc::perfdhcp;
typedef PerfPkt6::LocalizedOptionPtr LocalizedOptionPtr;
namespace {
class PerfPkt6Test : public ::testing::Test {
public:
PerfPkt6Test() {
}
/// @brief returns captured actual SOLICIT packet
/// \brief Returns captured SOLICIT packet.
///
/// Captured SOLICIT packet with transid=0x3d79fb and options: client-id,
/// in_na, dns-server, elapsed-time, option-request
/// This code was autogenerated (see src/bin/dhcp6/tests/iface_mgr_unittest.c),
/// This code was autogenerated
/// (see src/bin/dhcp6/tests/iface_mgr_unittest.c),
/// but we spent some time to make is less ugly than it used to be.
///
/// @return pointer to Pkt6 that represents received SOLICIT
PerfPkt6* capture1() {
/// \return pointer to Pkt6 that represents received SOLICIT
PerfPkt6* capture() {
uint8_t data[98];
data[0] = 1;
data[1] = 1; data[2] = 2; data[3] = 3; data[4] = 0;
......@@ -75,40 +77,86 @@ public:
data[93] = 6; data[94] = 0; data[95] = 2; data[96] = 0;
data[97] = 23;
PerfPkt6* pkt = new PerfPkt6(data, sizeof(data), 0);
PerfPkt6* pkt = new PerfPkt6(data, sizeof(data),
0x1, PerfPkt6::Offset());
return (pkt);
}
/// \brief Returns truncated SOLICIT packet.
///
/// Returns truncated SOLICIT packet which will be used for
/// negative tests: e.g. pack options out of packet.
///
/// \return pointer to Pkt6 that represents truncated SOLICIT
PerfPkt6* captureTruncated() {
uint8_t data[17];
data[0] = 1;
data[1] = 1; data[2] = 2; data[3] = 3; data[4] = 0;
data[5] = 1; data[6] = 0; data[7] = 14; data[8] = 0;
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());
return (pkt);
}
};
TEST_F(PerfPkt6Test, Constructor) {
// Data to be used to create packet.
uint8_t data[] = { 0, 1, 2, 3, 4, 5 };
timespec zero_t_spec;
memset(&zero_t_spec, 0, sizeof(zero_t_spec));
boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data, sizeof(data), 1));
timespec packet_t_spec = pkt1->getTimestamp();
// 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()));
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(0, memcmp(&packet_t_spec, &zero_t_spec, sizeof(zero_t_spec)));
// 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)));
EXPECT_EQ(6, pkt2->getData().size());
EXPECT_EQ(0, memcmp(&pkt2->getData()[0], data, sizeof(data)));
EXPECT_EQ(0x010203, pkt2->getTransid());
EXPECT_EQ(10, pkt2->getTransIdOffset());
}
TEST_F(PerfPkt6Test, RawPackUnpack) {
// Create first packet.
boost::scoped_ptr<PerfPkt6> pkt1(capture1());
boost::scoped_ptr<PerfPkt6> pkt1(capture());
// Create some input buffers to initialize options.
uint8_t buf_elapsed_time[] = { 1, 1 };
uint8_t buf_duid[14] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
// Create options.
dhcp::OptionBuffer vec_elapsed_time(buf_elapsed_time, buf_elapsed_time + 2);
dhcp::OptionBuffer vec_duid(buf_duid, buf_duid + 14);
LocalizedOptionPtr pkt1_elapsed_time(new LocalizedOption(Option::V6, 8, vec_elapsed_time, 86));
LocalizedOptionPtr pkt1_duid(new LocalizedOption(Option::V6, D6O_CLIENTID, vec_duid, 4));
OptionBuffer vec_elapsed_time(buf_elapsed_time, buf_elapsed_time + 2);
OptionBuffer vec_duid(buf_duid, buf_duid + 14);
LocalizedOptionPtr pkt1_elapsed_time(new LocalizedOption(Option::V6,
D6O_ELAPSED_TIME,
vec_elapsed_time,
86));
LocalizedOptionPtr pkt1_duid(new LocalizedOption(Option::V6,
D6O_CLIENTID,
vec_duid,
4));
// Add option to packet and create on-wire format from added options.
// Contents of options will override contents of packet buffer.
......@@ -120,17 +168,26 @@ TEST_F(PerfPkt6Test, RawPackUnpack) {
vec_elapsed_time.clear();
vec_duid.clear();
// Get output buffer from packet 1 to create new packet
// Get output buffer from packet 1 to create new packet
// that will be later validated.
isc::util::OutputBuffer pkt1_output = pkt1->getBuffer();
util::OutputBuffer pkt1_output = pkt1->getBuffer();
ASSERT_EQ(pkt1_output.getLength(), pkt1->getData().size());
boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(static_cast<const uint8_t*>(pkt1_output.getData()),
pkt1_output.getLength(), 1));
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()));
// 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.
LocalizedOptionPtr pkt2_elapsed_time(new LocalizedOption(Option::V6, D6O_ELAPSED_TIME, vec_elapsed_time, 86));
LocalizedOptionPtr pkt2_duid(new LocalizedOption(Option::V6, D6O_CLIENTID, vec_duid, 4));
LocalizedOptionPtr pkt2_elapsed_time(new LocalizedOption(Option::V6,
D6O_ELAPSED_TIME,
vec_elapsed_time,
86));
LocalizedOptionPtr pkt2_duid(new LocalizedOption(Option::V6,
D6O_CLIENTID,
vec_duid,
4));
// Add options to packet to pass their offsets.
pkt2->addOption(pkt2_elapsed_time);
pkt2->addOption(pkt2_duid);
......@@ -139,8 +196,10 @@ TEST_F(PerfPkt6Test, RawPackUnpack) {
ASSERT_TRUE(pkt2->rawUnpack());
// Once option data is stored in options objects we pull it out.
pkt2_elapsed_time = boost::dynamic_pointer_cast<LocalizedOption>(pkt2->getOption(D6O_ELAPSED_TIME));
pkt2_duid = boost::dynamic_pointer_cast<LocalizedOption>(pkt2->getOption(D6O_CLIENTID));
pkt2_elapsed_time = boost::dynamic_pointer_cast<LocalizedOption>
(pkt2->getOption(D6O_ELAPSED_TIME));
pkt2_duid = boost::dynamic_pointer_cast<LocalizedOption>
(pkt2->getOption(D6O_CLIENTID));
// Check if options are present. They have to be there since
// we have added them ourselfs.
......@@ -151,7 +210,119 @@ TEST_F(PerfPkt6Test, RawPackUnpack) {
OptionBuffer pkt2_elapsed_time_data = pkt2_elapsed_time->getData();
OptionBuffer pkt2_duid_data = pkt2_duid->getData();
EXPECT_EQ(0x0101, pkt2_elapsed_time->getUint16());
EXPECT_TRUE(std::equal(pkt2_duid_data.begin(), pkt2_duid_data.end(), buf_duid));
EXPECT_TRUE(std::equal(pkt2_duid_data.begin(),
pkt2_duid_data.end(),
buf_duid));
}
TEST_F(PerfPkt6Test, InvalidOptions) {
// Create packet.
boost::scoped_ptr<PerfPkt6> pkt1(capture());
OptionBuffer vec_server_id;
vec_server_id.resize(10);
// Testing invalid offset of the option (greater than packet size)
LocalizedOptionPtr pkt1_serverid(new LocalizedOption(Option::V6,
D6O_SERVERID,
vec_server_id,
150));
pkt1->addOption(pkt1_serverid);
// Pack has to fail due to invalid offset.
EXPECT_FALSE(pkt1->rawPack());
// Create packet.
boost::scoped_ptr<PerfPkt6> pkt2(capture());
// Testing offset of the option (lower than pakcet size but
// tail of the option out of bounds).
LocalizedOptionPtr pkt2_serverid(new LocalizedOption(Option::V6,
D6O_SERVERID,
vec_server_id,
85));
pkt2->addOption(pkt2_serverid);
// Pack must fail due to invalid offset.
EXPECT_FALSE(pkt2->rawPack());
}
TEST_F(PerfPkt6Test, TruncatedPacket) {
cout << "Testing parsing options from truncated packet."
<< "This may produce spurious errors" << endl;
// Create truncated (in the middle of duid options)
boost::scoped_ptr<PerfPkt6> pkt1(captureTruncated());
OptionBuffer vec_duid;
vec_duid.resize(30);
LocalizedOptionPtr pkt1_duid(new LocalizedOption(Option::V6,
D6O_CLIENTID,
vec_duid,
4));
pkt1->addOption(pkt1_duid);
// Pack/unpack must fail because length of the option read from buffer
// will extend over the actual packet length.
EXPECT_FALSE(pkt1->rawUnpack());
EXPECT_FALSE(pkt1->rawPack());
}
TEST_F(PerfPkt6Test, PackTransactionId) {
uint8_t data[100] = { 0 };
// Create dummy packet that is simply filled with zeros.
boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data,
sizeof(data),
0x010203,
PerfPkt6::Offset(50)));
// Reference data are non zero so we can detect them in dummy packet.
uint8_t ref_data[3] = { 1, 2, 3 };
// This will store given transaction id in the packet data at
// offset of 50.
ASSERT_TRUE(pkt1->rawPack());
// Get the output buffer so we can validate it.
util::OutputBuffer out_buf = pkt1->getBuffer();
ASSERT_EQ(sizeof(data), out_buf.getLength());
const uint8_t *out_buf_data = static_cast<const uint8_t*>
(out_buf.getData());
// Validate transaction id.
EXPECT_EQ(0, memcmp(out_buf_data + 50, ref_data, 3));
// Out of bounds transaction id offset.
boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data,
sizeof(data),
0x010202,
PerfPkt6::Offset(100)));
cout << "Testing out of bounds offset. "
"This may produce spurious errors ..." << endl;
EXPECT_FALSE(pkt2->rawPack());
}
TEST_F(PerfPkt6Test, UnpackTransactionId) {
// Initialize data for dummy packet (zeros only).
uint8_t data[100] = { 0 };
// Generate transaction id = 0x010203 and inject at offset = 50.
for (int i = 50; i < 53; ++i) {
data[i] = i - 49;
}
// Create packet and point out that transaction id is at offset 50.
boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data,