From: Marcin Siodelski Date: Thu, 31 May 2012 16:39:11 +0000 (+0200) Subject: [1956] PerfPkt6 class code improvements. X-Git-Tag: trac2351_base~226^2~58^2~6^2~20 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ff1617fd13a786d41439b7d653e798352e3789b7;p=thirdparty%2Fkea.git [1956] PerfPkt6 class code improvements. Improved error checks, comments, additional unit tests added. --- diff --git a/tests/tools/perfdhcp/Makefile.am b/tests/tools/perfdhcp/Makefile.am index c1fa58240f..31a75e14a6 100644 --- a/tests/tools/perfdhcp/Makefile.am +++ b/tests/tools/perfdhcp/Makefile.am @@ -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 diff --git a/tests/tools/perfdhcp/localized_option.h b/tests/tools/perfdhcp/localized_option.h index a69c560594..19d74cdcbe 100644 --- a/tests/tools/perfdhcp/localized_option.h +++ b/tests/tools/perfdhcp/localized_option.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, 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) { diff --git a/tests/tools/perfdhcp/perf_pkt6.cc b/tests/tools/perfdhcp/perf_pkt6.cc index 1f1aefd62f..de3983c2a1 100644 --- a/tests/tools/perfdhcp/perf_pkt6.cc +++ b/tests/tools/perfdhcp/perf_pkt6.cc @@ -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(&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 option = boost::dynamic_pointer_cast(it->second); - uint32_t position = option->getOffset(); - if (position > 0) { - bufferOut_.clear(); - bufferOut_.skip(position); + boost::shared_ptr option = + boost::dynamic_pointer_cast(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(it->second); + LocalizedOptionPtr option = + boost::dynamic_pointer_cast(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); } } diff --git a/tests/tools/perfdhcp/perf_pkt6.h b/tests/tools/perfdhcp/perf_pkt6.h index b98044c57c..590fb9e3b6 100644 --- a/tests/tools/perfdhcp/perf_pkt6.h +++ b/tests/tools/perfdhcp/perf_pkt6.h @@ -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 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 }; diff --git a/tests/tools/perfdhcp/tests/perf_pkt6_unittest.cc b/tests/tools/perfdhcp/tests/perf_pkt6_unittest.cc index 0acda00f6e..8a23a5136c 100644 --- a/tests/tools/perfdhcp/tests/perf_pkt6_unittest.cc +++ b/tests/tools/perfdhcp/tests/perf_pkt6_unittest.cc @@ -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 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 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 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 pkt1(capture1()); + boost::scoped_ptr 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 pkt2(new PerfPkt6(static_cast(pkt1_output.getData()), - pkt1_output.getLength(), 1)); + const uint8_t* pkt1_output_data = static_cast + (pkt1_output.getData()); + boost::scoped_ptr 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(pkt2->getOption(D6O_ELAPSED_TIME)); - pkt2_duid = boost::dynamic_pointer_cast(pkt2->getOption(D6O_CLIENTID)); + pkt2_elapsed_time = boost::dynamic_pointer_cast + (pkt2->getOption(D6O_ELAPSED_TIME)); + pkt2_duid = boost::dynamic_pointer_cast + (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 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 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 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 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 + (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 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 pkt1(new PerfPkt6(data, + sizeof(data), + PerfPkt6::Offset(50))); + + // Get transaction id out of buffer and store in class member. + ASSERT_TRUE(pkt1->rawUnpack()); + // Test value of transaction id. + EXPECT_EQ(0x010203, pkt1->getTransid()); + + // Out of bounds transaction id offset. + boost::scoped_ptr pkt2(new PerfPkt6(data, + sizeof(data), + PerfPkt6::Offset(300))); + cout << "Testing out of bounds offset. " + "This may produce spurious errors ..." << endl; + EXPECT_FALSE(pkt2->rawUnpack()); + } }