Commit b01c1814 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[1228] Initial changes for supporting options in DHCPv4

- getData() now returns const vector<uint8_t>&
- several skeleton tests added
- implemented Option::getUniverse()
- Internally Option uses vector<uint8_t> to keep data. However, to avoid
  refactoring of all DHCPv6 code at this stage, API still uses
  share_array<uint8_t>. There is separate ticket for fixing this.
parent 41f528a9
......@@ -37,14 +37,27 @@ Option::Option(Universe u, unsigned short type)
Option::Option(Universe u, unsigned short type,
const boost::shared_array<uint8_t>& buf,
unsigned int offset, unsigned int len)
:universe_(u), type_(type), data_(buf),
:universe_(u), type_(type),
data_len_(len), offset_(offset)
{
{
if (u==V4 && (type>255)) {
isc_throw(BadValue, "Can't create V4 option of type "
<< type << ", V4 options are in range 0..255");
}
uint8_t* ptr = &buf[offset];
data_ = std::vector<uint8_t>(ptr, ptr+len);
// sanity checks
// TODO: universe must be in V4 and V6
}
Option::Option(Universe u, unsigned short type, std::vector<uint8_t>& data)
:universe_(u), type_(type), data_(data) {
}
unsigned int
Option::pack(boost::shared_array<uint8_t>& buf,
unsigned int buf_len,
......@@ -72,7 +85,7 @@ Option::pack4(boost::shared_array<uint8_t>& buf,
ptr[0] = type_;
ptr[1] = data_len_;
ptr += 2;
memcpy(ptr, &data_[0], data_len_);
memcpy(ptr, &data_[0], data_.size());
return offset + len();
}
......@@ -93,7 +106,7 @@ Option::pack6(boost::shared_array<uint8_t>& buf,
ptr = writeUint16(len() - getHeaderLen(), ptr);
if (data_len_)
memcpy(ptr, &data_[offset_], data_len_);
memcpy(ptr, &data_[0], data_.size());
// end of fixed part of this option
offset += OPTION6_HDR_LEN + data_len_;
......@@ -140,12 +153,16 @@ Option::unpack6(const boost::shared_array<uint8_t>& buf,
<< "): too small buffer.");
}
data_ = buf;
uint8_t* ptr = &buf[offset];
data_ = std::vector<uint8_t>(ptr, ptr+parse_len);
offset_ = offset;
data_len_ = buf_len;
return LibDHCP::unpackOptions6(buf, buf_len, offset, parse_len,
options_);
return (offset+parse_len);
//return LibDHCP::unpackOptions6(buf, buf_len, offset, parse_len,
// options_);
}
unsigned short
......@@ -218,7 +235,7 @@ std::string Option::toText(int indent /* =0 */ ) {
tmp << ":";
}
tmp << setfill('0') << setw(2) << hex
<< static_cast<unsigned short>(data_[offset_+i]);
<< static_cast<unsigned short>(data_[i]);
}
// print suboptions
......@@ -235,13 +252,9 @@ Option::getType() {
return type_;
}
uint8_t*
const std::vector<uint8_t>&
Option::getData() {
if (data_len_) {
return (&data_[offset_]);
} else {
return (NULL);
}
return (data_);
}
unsigned short
......
......@@ -17,6 +17,7 @@
#include <string>
#include <map>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/shared_array.hpp>
......@@ -80,6 +81,24 @@ public:
const boost::shared_array<uint8_t>& buf, unsigned int offset,
unsigned int len);
/// @brief Constructor, used for received options.
///
/// This constructor takes vector<uint8_t>& which is used in cases
/// when content of the option will be copied and stored within
/// option object. V4 Options follow that approach already.
/// TODO Migrate V6 options to that approach.
///
/// @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
Option(Universe u, unsigned short type, std::vector<uint8_t>& data);
/// @brief returns option universe (V4 or V6)
///
/// @return universe type
Universe
getUniverse() { return universe_; };
/// @brief writes option in wire-format to buf
///
/// Writes option in wire-format to buffer, returns pointer to first unused
......@@ -150,7 +169,7 @@ public:
/// Returns pointer to actual data.
///
/// @return pointer to actual data (or NULL if there is no data)
virtual uint8_t*
virtual const std::vector<uint8_t>&
getData();
/// Adds a sub-option.
......@@ -248,8 +267,8 @@ protected:
/// option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
unsigned short type_;
/// shared pointer to a buffer (usually a part of packet)
boost::shared_array<uint8_t> data_;
/// contains content of this data
std::vector<uint8_t> data_;
/// length of data only. Use len() if you want to
/// know proper length with option header overhead
......
......@@ -95,31 +95,31 @@ TEST(LibDhcpTest, unpackOptions6) {
ASSERT_FALSE(x == options.end()); // option 1 should exist
EXPECT_EQ(12, x->second->getType()); // this should be option 12
ASSERT_EQ(9, x->second->len()); // it should be of length 9
EXPECT_EQ(0, memcmp(x->second->getData(), packed+4, 5)); // data len=5
EXPECT_EQ(0, memcmp(&x->second->getData()[0], packed+4, 5)); // data len=5
x = options.find(13);
ASSERT_FALSE(x == options.end()); // option 13 should exist
EXPECT_EQ(13, x->second->getType()); // this should be option 13
ASSERT_EQ(7, x->second->len()); // it should be of length 7
EXPECT_EQ(0, memcmp(x->second->getData(), packed+13, 3)); // data len=3
EXPECT_EQ(0, memcmp(&x->second->getData()[0], packed+13, 3)); // data len=3
x = options.find(14);
ASSERT_FALSE(x == options.end()); // option 3 should exist
EXPECT_EQ(14, x->second->getType()); // this should be option 14
ASSERT_EQ(6, x->second->len()); // it should be of length 6
EXPECT_EQ(0, memcmp(x->second->getData(), packed+20, 2)); // data len=2
EXPECT_EQ(0, memcmp(&x->second->getData()[0], packed+20, 2)); // data len=2
x = options.find(256);
ASSERT_FALSE(x == options.end()); // option 256 should exist
EXPECT_EQ(256, x->second->getType()); // this should be option 256
ASSERT_EQ(8, x->second->len()); // it should be of length 7
EXPECT_EQ(0, memcmp(x->second->getData(), packed+26, 4)); // data len=4
EXPECT_EQ(0, memcmp(&x->second->getData()[0], packed+26, 4)); // data len=4
x = options.find(257);
ASSERT_FALSE(x == options.end()); // option 257 should exist
EXPECT_EQ(257, x->second->getType()); // this should be option 257
ASSERT_EQ(5, x->second->len()); // it should be of length 5
EXPECT_EQ(0, memcmp(x->second->getData(), packed+34, 1)); // data len=1
EXPECT_EQ(0, memcmp(&x->second->getData()[0], packed+34, 1)); // data len=1
x = options.find(0);
EXPECT_TRUE(x == options.end()); // option 0 not found
......
......@@ -111,6 +111,8 @@ TEST_F(Option6AddrLstTest, basic) {
opt1 = new Option6AddrLst(D6O_NAME_SERVERS, buf, 128, 0, 16);
);
EXPECT_EQ(Option::V6, opt1->getUniverse());
EXPECT_EQ(D6O_NAME_SERVERS, opt1->getType());
EXPECT_EQ(20, opt1->len());
Option6AddrLst::AddressContainer addrs = opt1->getAddresses();
......@@ -178,6 +180,7 @@ TEST_F(Option6AddrLstTest, constructors) {
EXPECT_NO_THROW(
opt1 = new Option6AddrLst(1234, IOAddress("::1"));
);
EXPECT_EQ(Option::V6, opt1->getUniverse());
EXPECT_EQ(1234, opt1->getType());
Option6AddrLst::AddressContainer addrs = opt1->getAddresses();
......
......@@ -67,6 +67,7 @@ TEST_F(Option6IATest, basic) {
0,
12);
EXPECT_EQ(Option::V6, opt->getUniverse());
EXPECT_EQ(D6O_IA_NA, opt->getType());
EXPECT_EQ(0xa1a2a3a4, opt->getIAID());
EXPECT_EQ(0x81020304, opt->getT1());
......@@ -121,6 +122,7 @@ TEST_F(Option6IATest, simple) {
ia->setT1(2345);
ia->setT2(3456);
EXPECT_EQ(Option::V6, ia->getUniverse());
EXPECT_EQ(D6O_IA_NA, ia->getType());
EXPECT_EQ(1234, ia->getIAID());
EXPECT_EQ(2345, ia->getT1());
......@@ -251,7 +253,7 @@ TEST_F(Option6IATest, suboptions_unpack) {
EXPECT_EQ(0xcafe, subopt->getType());
EXPECT_EQ(4, subopt->len());
// there should be no data at all
EXPECT_EQ(static_cast<void*>(NULL), subopt->getData());
EXPECT_EQ(0, subopt->getData().size());
subopt = ia->getOption(1); // get option 1
ASSERT_FALSE(subopt); // should be NULL
......
......@@ -75,6 +75,8 @@ TEST_F(Option6IAAddrTest, basic) {
EXPECT_EQ(78, offset);
EXPECT_EQ(Option::V6, opt->getUniverse());
// 4 bytes header + 4 bytes content
EXPECT_EQ("2001:db8:1::dead:beef", opt->getAddress().toText());
EXPECT_EQ(1000, opt->getPreferred());
......
......@@ -19,6 +19,7 @@
#include <arpa/inet.h>
#include <gtest/gtest.h>
#include <boost/shared_ptr.hpp>
#include <exceptions/exceptions.h>
#include "dhcp/dhcp6.h"
#include "dhcp/option.h"
......@@ -37,18 +38,52 @@ public:
// v4 is not really implemented yet. A simple test will do for now
TEST_F(OptionTest, v4_basic) {
Option* opt = new Option(Option::V4, 17);
Option* opt = 0;
EXPECT_NO_THROW(
opt = new Option(Option::V4, 17);
);
EXPECT_EQ(Option::V4, opt->getUniverse());
EXPECT_EQ(17, opt->getType());
EXPECT_EQ(static_cast<uint8_t*>(NULL), opt->getData());
EXPECT_EQ(0, opt->getData().size());
EXPECT_EQ(2, opt->len()); // just v4 header
EXPECT_NO_THROW(
delete opt;
);
opt = 0;
// V4 options have type 0...255
EXPECT_THROW(
opt = new Option(Option::V4, 256),
BadValue
);
if (opt) {
delete opt;
opt = 0;
}
}
const uint8_t dummyPayload[] =
{ 1, 2, 3, 4};
TEST_F(OptionTest, v4_data) {
vector<uint8_t> data(dummyPayload, dummyPayload + sizeof(dummyPayload));
Option* opt = 0;
ASSERT_NO_THROW(
opt= new Option(Option::V4,
123, // type
data);
);
EXPECT_EQ(123, opt->getType());
vector<uint8_t> optData = opt->getData();
ASSERT_EQ(optData.size(), data.size());
EXPECT_EQ(optData, data);
// TODO
ASSERT_TRUE(false);
}
......@@ -68,8 +103,9 @@ TEST_F(OptionTest, v6_basic) {
Option* opt = new Option(Option::V6, 1);
EXPECT_EQ(Option::V6, opt->getUniverse());
EXPECT_EQ(1, opt->getType());
EXPECT_EQ(static_cast<uint8_t*>(NULL), opt->getData());
EXPECT_EQ(0, opt->getData().size());
EXPECT_EQ(4, opt->len()); // just v6 header
EXPECT_NO_THROW(
......@@ -88,9 +124,10 @@ TEST_F(OptionTest, v6_data1) {
3, // offset
7); // 7 bytes of data
EXPECT_EQ(333, opt->getType());
ASSERT_EQ(&buf[3], opt->getData());
ASSERT_EQ(11, opt->len());
EXPECT_EQ(0, memcmp(&buf[3], opt->getData(), 7) );
ASSERT_EQ(11, opt->getData().size());
EXPECT_EQ(0, memcmp(&buf[3], &opt->getData()[0], 7) );
int offset = opt->pack(buf, 32, 20);
EXPECT_EQ(31, offset);
......
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