Commit a6a3d1b1 authored by Marcin Siodelski's avatar Marcin Siodelski

[1956] Basic unit tests added for PerfPkt6 class.

parent 908b273b
......@@ -270,6 +270,18 @@ void Option::setUint32(uint32_t value) {
writeUint32(value, &data_[0]);
}
void Option::setData(const OptionBufferConstIter first,
const OptionBufferConstIter last) {
// We will copy entire option buffer, so we have to resize data_.
data_.resize(last - first);
OptionBufferConstIter x = first;
while (x != last) {
data_[x - first] = *x;
++x;
}
}
Option::~Option() {
}
......
......@@ -244,6 +244,15 @@ public:
/// @param value value to be set
void setUint32(uint32_t value);
/// @brief Sets content of this option from buffer.
///
/// Option will be resized to length of buffer.
///
/// @param first iterator pointing begining of buffer to copy.
/// @param last iterator pointing to end of buffer to copy.
void setData(OptionBufferConstIter first,
OptionBufferConstIter last);
/// just to force that every option has virtual dtor
virtual ~Option();
......
......@@ -12,8 +12,7 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <boost/shared_ptr.hpp>
#include <exceptions/exceptions.h>
#include <dhcp/libdhcp++.h>
#include <dhcp/dhcp6.h>
......@@ -26,24 +25,39 @@ namespace isc {
namespace perfdhcp {
PerfPkt6::PositionedOption::PositionedOption(dhcp::Option::Universe u,
uint16_t type,
const dhcp::OptionBuffer& data) :
dhcp::Option(u, type, data),
position_(0) {
}
PerfPkt6::PositionedOption::PositionedOption(dhcp::Option::Universe u,
uint16_t type,
const dhcp::OptionBuffer& data,
const OptionPosition& position) :
const size_t position) :
dhcp::Option(u, type, data),
position_(position) {
}
PerfPkt6::PositionedOption::PositionedOption(dhcp::Option::Universe u,
uint16_t type,
dhcp::OptionBufferConstIter first,
dhcp::OptionBufferConstIter last) :
dhcp::Option(u, type, first, last),
position_(0) {
}
PerfPkt6::PositionedOption::PositionedOption(dhcp::Option::Universe u,
uint16_t type,
dhcp::OptionBufferConstIter first,
dhcp::OptionBufferConstIter last,
const OptionPosition& position) :
const size_t position) :
dhcp::Option(u, type, first, last),
position_(position) {
}
PerfPkt6::PerfPkt6(const uint8_t* buf, uint32_t len, const OptionPosition& transid_offset) :
PerfPkt6::PerfPkt6(const uint8_t* buf, uint32_t len, size_t transid_offset) :
Pkt6(buf, len, dhcp::Pkt6::UDP),
transid_offset_(transid_offset) {
......@@ -98,17 +112,18 @@ PerfPkt6::stampedRawUnpack() {
// Update packet timestamp for RTT calculations but do not include unpack time.
updateTimestamp();
// Get transaction id offset.
int transid_offset = transid_offset_.get();
// 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_ = ( (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];
rawUnpackOptions();
}
void
PerfPkt6::updateOptions() {
try {
......@@ -133,6 +148,36 @@ PerfPkt6::updateOptions() {
}
}
void
PerfPkt6::rawUnpackOptions() {
for (dhcp::Option::OptionCollection::const_iterator it = options_.begin();
it != options_.end(); ++it) {
PositionedOptionPtr option = boost::dynamic_pointer_cast<PositionedOption>(it->second);
size_t opt_pos = option->getOptionPosition();
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;
// uint16_t opt_type = data_[offset] * 256 + data_[offset + 1];
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)");
}
option->setData(data_.begin() + offset, data_.begin() + offset + opt_len);
}
}
void
PerfPkt6::updateTimestamp() {
if (clock_gettime(CLOCK_REALTIME, &time_stamp_) < 0) {
......
......@@ -16,7 +16,7 @@
#define __PERF_PKT6_H
#include <time.h>
#include <boost/shared_ptr.hpp>
#include <dhcp/pkt6.h>
namespace isc {
......@@ -55,28 +55,6 @@ namespace perfdhcp {
class PerfPkt6 : public dhcp::Pkt6 {
public:
/// \brief Class represents position of DHCP option in a packet
class OptionPosition {
public:
/// \brief Class constructor
///
/// Applies default value of option position
explicit OptionPosition() : position_(0) { };
/// \brief Class constructor
///
/// \param position position of option in DHCP packet
explicit OptionPosition(size_t position) : position_(position) { };
/// \brief Returns position of DHCP option in a packet
///
/// \return position of DHCP option in packet
size_t get() const { return position_; }
private:
size_t position_; ///< position of option in a packet
///< Zero is default position
};
/// \brief DHCPv6 option at specific offset
///
/// This class represents DHCPv6 option at specified
......@@ -84,6 +62,16 @@ public:
///
class PositionedOption : public dhcp::Option {
public:
/// \brief Constructor, sets default (0) option position
///
///
/// \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
PositionedOption(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& data);
/// \brief Constructor, used to create positioned option from buffer
///
///
......@@ -92,7 +80,21 @@ public:
/// \param data content of the option
/// \param position absolute position of option in a packet (zero is default)
PositionedOption(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& data,
const OptionPosition& position);
const size_t position);
/// \brief Constructor, sets default (0) option position
///
/// This contructor is similar to the previous one, but it does not take
/// the whole vector<uint8_t>, but rather subset of it.
///
/// \param u specifies universe (V4 or V6)
/// \param type option type (0-255 for V4 and 0-65535 for V6)
/// \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.
/// \param position absolute position of option in a packet (zero is default)
PositionedOption(dhcp::Option::Universe u, uint16_t type, dhcp::OptionBufferConstIter first,
dhcp::OptionBufferConstIter last);
/// \brief Constructor, used to create positioned option from buffer iterators
///
......@@ -106,19 +108,21 @@ public:
/// to be copied.
/// \param position absolute position of option in a packet (zero is default)
PositionedOption(dhcp::Option::Universe u, uint16_t type, dhcp::OptionBufferConstIter first,
dhcp::OptionBufferConstIter last, const OptionPosition& position);
dhcp::OptionBufferConstIter last, const size_t position);
/// \brief Returns absolute position (offset) of an option in a
/// DHCPv6 packet.
///
/// \return absolute position (offset) of an option in a packet
size_t getOptionPosition() const { return position_.get(); };
size_t getOptionPosition() const { return position_; };
private:
OptionPosition position_; ///< Absolute position of DHCPv6 option in a packet
size_t position_; ///< Absolute position of DHCPv6 option in a packet
};
typedef boost::shared_ptr<PositionedOption> PositionedOptionPtr;
/// Constructor, used in message transmission
///
/// Creates new DHCPv6 message using provided buffer. New object
......@@ -143,7 +147,17 @@ public:
/// \param xid_off transaction id offset in a packet
PerfPkt6(const uint8_t* buf,
uint32_t len,
const OptionPosition& transid_offset);
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 Returns current packet timestamp
///
/// \return current packet timestamp
timespec getTimestamp() const { return time_stamp_; }
/// \brief Prepare on-wire packet format and record timestamp
///
......@@ -208,13 +222,15 @@ private:
/// throw isc::Unexpected if options update fails
void updateOptions();
void rawUnpackOptions();
/// \brief Update packet timestamp with current time
///
/// \throw isc::Unexpected if timestamp update failed
void updateTimestamp();
OptionPosition transid_offset_; ///< transaction id offset
timespec time_stamp_; ///< time stamp of last pack or unpack
size_t transid_offset_; ///< transaction id offset
timespec time_stamp_; ///< time stamp of last pack or unpack
};
......
......@@ -4,8 +4,9 @@ AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CXXFLAGS = $(B10_CXXFLAGS)
AM_LDFLAGS = $(CLOCK_GETTIME_LDFLAGS)
if USE_STATIC_LINK
AM_LDFLAGS = -static
AM_LDFLAGS += -static
endif
CLEANFILES = *.gcno *.gcda
......@@ -15,7 +16,9 @@ if HAVE_GTEST
TESTS += run_unittests
run_unittests_SOURCES = run_unittests.cc
run_unittests_SOURCES += command_options_unittest.cc
run_unittests_SOURCES += perf_pkt6_unittest.cc
run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/command_options.cc
run_unittests_SOURCES += $(top_builddir)/tests/tools/perfdhcp/perf_pkt6.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
......@@ -23,6 +26,7 @@ run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
run_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libdhcp++.la
run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
endif
......
// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
#include <iostream>
#include <sstream>
#include <arpa/inet.h>
#include <gtest/gtest.h>
#include <asiolink/io_address.h>
#include <dhcp/option.h>
#include <dhcp/dhcp6.h>
#include "../perf_pkt6.h"
using namespace std;
using namespace isc;
using namespace isc::dhcp;
using namespace isc::perfdhcp;
typedef PerfPkt6::PositionedOptionPtr PositionedOptionPtr;
typedef PerfPkt6::PositionedOption PositionedOption;
namespace {
class PerfPkt6Test : public ::testing::Test {
public:
PerfPkt6Test() {
}
/// @brief returns captured actual 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),
/// 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() {
uint8_t data[98];
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;
data[17] = 30; data[18] = 140; data[19] = 155; data[20] = 115;
data[21] = 73; data[22] = 0; data[23] = 3; data[24] = 0;
data[25] = 40; data[26] = 0; data[27] = 0; data[28] = 0;
data[29] = 1; data[30] = 255; data[31] = 255; data[32] = 255;
data[33] = 255; data[34] = 255; data[35] = 255; data[36] = 255;
data[37] = 255; data[38] = 0; data[39] = 5; data[40] = 0;
data[41] = 24; data[42] = 32; data[43] = 1; data[44] = 13;
data[45] = 184; data[46] = 0; data[47] = 1; data[48] = 0;
data[49] = 0; data[50] = 0; data[51] = 0; data[52] = 0;
data[53] = 0; data[54] = 0; data[55] = 0; data[56] = 18;
data[57] = 52; data[58] = 255; data[59] = 255; data[60] = 255;
data[61] = 255; data[62] = 255; data[63] = 255; data[64] = 255;
data[65] = 255; data[66] = 0; data[67] = 23; data[68] = 0;
data[69] = 16; data[70] = 32; data[71] = 1; data[72] = 13;
data[73] = 184; data[74] = 0; data[75] = 1; data[76] = 0;
data[77] = 0; data[78] = 0; data[79] = 0; data[80] = 0;
data[81] = 0; data[82] = 0; data[83] = 0; data[84] = 221;
data[85] = 221; data[86] = 0; data[87] = 8; data[88] = 0;
data[89] = 2; data[90] = 0; data[91] = 100; data[92] = 0;
data[93] = 6; data[94] = 0; data[95] = 2; data[96] = 0;
data[97] = 23;
PerfPkt6* pkt = new PerfPkt6(data, sizeof(data), 0);
/* pkt->setRemotePort(546);
pkt->setRemoteAddr(IOAddress("fe80::21e:8cff:fe9b:7349"));
pkt->setLocalPort(0);
pkt->setLocalAddr(IOAddress("ff02::1:2"));
pkt->setIndex(2);
pkt->setIface("eth0");*/
return (pkt);
}
};
TEST_F(PerfPkt6Test, constructor) {
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();
EXPECT_EQ(6, pkt1->getData().size());
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_F(PerfPkt6Test, UnpackRawSolicit) {
// Create packetPositionedOptionPtr
boost::scoped_ptr<PerfPkt6> pkt1(capture1());
// Create some input buffer to initialize options.
uint8_t buf_elapsed_time[] = { 8, 2, 4, 5 };
// Create options.
dhcp::OptionBuffer buf(buf_elapsed_time, buf_elapsed_time + 4);
PositionedOptionPtr pkt1_elapsed_time(new PositionedOption(Option::V6, 8, buf, 86));
// Add option to packet and create on-wire format from added options.
// Contents of options will override contents of packet buffer.
ASSERT_NO_THROW(pkt1->addOption(pkt1_elapsed_time));
ASSERT_NO_THROW(pkt1->stampedRawPack());
// Let's create another packet using packed data stored in first packet.
// We will try to unpack data into option objects.
buf.clear();
OptionBuffer pkt1_output = pkt1->getData();
boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(&pkt1_output[0], pkt1_output.size(), 1));
// Create partial options to specify offsets of certain options in packet.
PositionedOptionPtr pkt2_elapsed_time(new PositionedOption(Option::V6, D6O_ELAPSED_TIME, buf, 86));
// Add partial options.
pkt2->addOption(pkt2_elapsed_time);
// Get relevant parts of buffer data into option objects.
ASSERT_NO_THROW(pkt2->stampedRawUnpack());
// Once option data is updated we pull it out.
pkt2_elapsed_time = boost::dynamic_pointer_cast<PositionedOption>(pkt2->getOption(D6O_ELAPSED_TIME));
ASSERT_TRUE(pkt2_elapsed_time);
// Expecting option contents be the same as original.
OptionBuffer pkt2_elapsed_time_data = pkt2_elapsed_time->getData();
ASSERT_EQ(100, pkt2_elapsed_time->getUint16());
}
}
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