option_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <iostream>
  16. #include <sstream>
  17. #include <arpa/inet.h>
  18. #include <gtest/gtest.h>
  19. #include <boost/shared_ptr.hpp>
  20. #include <exceptions/exceptions.h>
  21. #include <util/buffer.h>
  22. #include "dhcp/dhcp6.h"
  23. #include "dhcp/option.h"
  24. using namespace std;
  25. using namespace isc;
  26. using namespace isc::dhcp;
  27. using namespace isc::util;
  28. namespace {
  29. class OptionTest : public ::testing::Test {
  30. public:
  31. OptionTest() {
  32. }
  33. };
  34. // v4 is not really implemented yet. A simple test will do for now
  35. TEST_F(OptionTest, v4_basic) {
  36. Option* opt = 0;
  37. EXPECT_NO_THROW(
  38. opt = new Option(Option::V4, 17);
  39. );
  40. EXPECT_EQ(Option::V4, opt->getUniverse());
  41. EXPECT_EQ(17, opt->getType());
  42. EXPECT_EQ(0, opt->getData().size());
  43. EXPECT_EQ(2, opt->len()); // just v4 header
  44. EXPECT_NO_THROW(
  45. delete opt;
  46. );
  47. opt = 0;
  48. // V4 options have type 0...255
  49. EXPECT_THROW(
  50. opt = new Option(Option::V4, 256),
  51. BadValue
  52. );
  53. if (opt) {
  54. delete opt;
  55. opt = 0;
  56. }
  57. }
  58. const uint8_t dummyPayload[] =
  59. { 1, 2, 3, 4};
  60. TEST_F(OptionTest, v4_data1) {
  61. vector<uint8_t> data(dummyPayload, dummyPayload + sizeof(dummyPayload));
  62. Option* opt = 0;
  63. // create DHCPv4 option of type 123
  64. // that contains 4 bytes of data
  65. ASSERT_NO_THROW(
  66. opt= new Option(Option::V4,
  67. 123, // type
  68. data);
  69. );
  70. // check that content is reported properly
  71. EXPECT_EQ(123, opt->getType());
  72. vector<uint8_t> optData = opt->getData();
  73. ASSERT_EQ(optData.size(), data.size());
  74. EXPECT_TRUE(optData == data);
  75. EXPECT_EQ(2, opt->getHeaderLen());
  76. EXPECT_EQ(6, opt->len());
  77. // now store that option into a buffer
  78. OutputBuffer buf(100);
  79. EXPECT_NO_THROW(
  80. opt->pack4(buf);
  81. );
  82. // check content of that buffer
  83. // 2 byte header + 4 bytes data
  84. ASSERT_EQ(6, buf.getLength());
  85. // that's how this option is supposed to look like
  86. uint8_t exp[] = { 123, 4, 1, 2, 3, 4 };
  87. /// TODO: use vector<uint8_t> getData() when it will be implemented
  88. EXPECT_EQ(0, memcmp(exp, buf.getData(), 6));
  89. // check that we can destroy that option
  90. EXPECT_NO_THROW(
  91. delete opt;
  92. );
  93. }
  94. // this is almost the same test as v4_data1, but it uses
  95. // different constructor
  96. TEST_F(OptionTest, v4_data2) {
  97. vector<uint8_t> data(dummyPayload, dummyPayload + sizeof(dummyPayload));
  98. vector<uint8_t> expData = data;
  99. // Add fake data in front and end. Main purpose of this test is to check
  100. // that only subset of the whole vector can be used for creating option.
  101. data.insert(data.begin(), 56);
  102. data.push_back(67);
  103. // Data contains extra garbage at beginning and at the end. It should be
  104. // ignored, as we pass interators to proper data. Only subset (limited by
  105. // iterators) of the vector should be used.
  106. // expData contains expected content (just valid data, without garbage).
  107. Option* opt = 0;
  108. // Create DHCPv4 option of type 123 that contains
  109. // 4 bytes (sizeof(dummyPayload).
  110. ASSERT_NO_THROW(
  111. opt= new Option(Option::V4,
  112. 123, // type
  113. data.begin() + 1,
  114. data.end() - 1);
  115. );
  116. // check that content is reported properly
  117. EXPECT_EQ(123, opt->getType());
  118. vector<uint8_t> optData = opt->getData();
  119. ASSERT_EQ(optData.size(), expData.size());
  120. EXPECT_TRUE(optData == expData);
  121. EXPECT_EQ(2, opt->getHeaderLen());
  122. EXPECT_EQ(6, opt->len());
  123. // now store that option into a buffer
  124. OutputBuffer buf(100);
  125. EXPECT_NO_THROW(
  126. opt->pack4(buf);
  127. );
  128. // check content of that buffer
  129. // 2 byte header + 4 bytes data
  130. ASSERT_EQ(6, buf.getLength());
  131. // that's how this option is supposed to look like
  132. uint8_t exp[] = { 123, 4, 1, 2, 3, 4 };
  133. /// TODO: use vector<uint8_t> getData() when it will be implemented
  134. EXPECT_EQ(0, memcmp(exp, buf.getData(), 6));
  135. // check that we can destroy that option
  136. EXPECT_NO_THROW(
  137. delete opt;
  138. );
  139. }
  140. TEST_F(OptionTest, v4_toText) {
  141. vector<uint8_t> buf(3);
  142. buf[0] = 0;
  143. buf[1] = 0xf;
  144. buf[2] = 0xff;
  145. Option opt(Option::V4, 253, buf);
  146. EXPECT_EQ("type=253, len=3: 00:0f:ff", opt.toText());
  147. }
  148. // tests simple constructor
  149. TEST_F(OptionTest, v6_basic) {
  150. Option* opt = new Option(Option::V6, 1);
  151. EXPECT_EQ(Option::V6, opt->getUniverse());
  152. EXPECT_EQ(1, opt->getType());
  153. EXPECT_EQ(0, opt->getData().size());
  154. EXPECT_EQ(4, opt->len()); // just v6 header
  155. EXPECT_NO_THROW(
  156. delete opt;
  157. );
  158. }
  159. // tests contructor used in pkt reception
  160. // option contains actual data
  161. TEST_F(OptionTest, v6_data1) {
  162. boost::shared_array<uint8_t> buf(new uint8_t[32]);
  163. for (int i = 0; i < 32; i++)
  164. buf[i] = 100+i;
  165. Option* opt = new Option(Option::V6, 333, //type
  166. buf,
  167. 3, // offset
  168. 7); // 7 bytes of data
  169. EXPECT_EQ(333, opt->getType());
  170. ASSERT_EQ(11, opt->len());
  171. ASSERT_EQ(7, opt->getData().size());
  172. EXPECT_EQ(0, memcmp(&buf[3], &opt->getData()[0], 7) );
  173. int offset = opt->pack(buf, 32, 20);
  174. EXPECT_EQ(31, offset);
  175. EXPECT_EQ(buf[20], 333/256); // type
  176. EXPECT_EQ(buf[21], 333%256);
  177. EXPECT_EQ(buf[22], 0); // len
  178. EXPECT_EQ(buf[23], 7);
  179. // payload
  180. EXPECT_EQ(0, memcmp(&buf[3], &buf[24], 7) );
  181. EXPECT_NO_THROW(
  182. delete opt;
  183. );
  184. }
  185. // another text that tests the same thing, just
  186. // with different input parameters
  187. TEST_F(OptionTest, v6_data2) {
  188. boost::shared_array<uint8_t> simple_buf(new uint8_t[128]);
  189. for (int i = 0; i < 128; i++)
  190. simple_buf[i] = 0;
  191. simple_buf[0] = 0xa1;
  192. simple_buf[1] = 0xa2;
  193. simple_buf[2] = 0xa3;
  194. simple_buf[3] = 0xa4;
  195. // create an option (unpack content)
  196. Option* opt = new Option(Option::V6,
  197. D6O_CLIENTID,
  198. simple_buf,
  199. 0,
  200. 4);
  201. // pack this option again in the same buffer, but in
  202. // different place
  203. int offset18 = opt->pack(simple_buf, 128, 10);
  204. // 4 bytes header + 4 bytes content
  205. EXPECT_EQ(8, opt->len());
  206. EXPECT_EQ(D6O_CLIENTID, opt->getType());
  207. EXPECT_EQ(offset18, 18);
  208. // check if pack worked properly:
  209. // if option type is correct
  210. EXPECT_EQ(D6O_CLIENTID, simple_buf[10]*256 + simple_buf[11]);
  211. // if option length is correct
  212. EXPECT_EQ(4, simple_buf[12]*256 + simple_buf[13]);
  213. // if option content is correct
  214. EXPECT_EQ(0, memcmp(&simple_buf[0], &simple_buf[14],4));
  215. EXPECT_NO_THROW(
  216. delete opt;
  217. );
  218. }
  219. // check that an option can contain 2 suboptions:
  220. // opt1
  221. // +----opt2
  222. // |
  223. // +----opt3
  224. //
  225. TEST_F(OptionTest, v6_suboptions1) {
  226. boost::shared_array<uint8_t> buf(new uint8_t[128]);
  227. for (int i=0; i<128; i++)
  228. buf[i] = 100+i;
  229. Option* opt1 = new Option(Option::V6, 65535, //type
  230. buf,
  231. 0, // offset
  232. 3); // 3 bytes of data
  233. boost::shared_ptr<Option> opt2(new Option(Option::V6, 13));
  234. boost::shared_ptr<Option> opt3(new Option(Option::V6, 7,
  235. buf,
  236. 3, // offset
  237. 5)); // 5 bytes of data
  238. opt1->addOption(opt2);
  239. opt1->addOption(opt3);
  240. // opt2 len = 4 (just header)
  241. // opt3 len = 9 4(header)+5(data)
  242. // opt1 len = 7 + suboptions() = 7 + 4 + 9 = 20
  243. EXPECT_EQ(4, opt2->len());
  244. EXPECT_EQ(9, opt3->len());
  245. EXPECT_EQ(20, opt1->len());
  246. uint8_t expected[] = {
  247. 0xff, 0xff, 0, 16, 100, 101, 102,
  248. 0, 7, 0, 5, 103, 104, 105, 106, 107,
  249. 0, 13, 0, 0 // no data at all
  250. };
  251. int offset = opt1->pack(buf, 128, 20);
  252. EXPECT_EQ(40, offset);
  253. // payload
  254. EXPECT_EQ(0, memcmp(&buf[20], expected, 20) );
  255. EXPECT_NO_THROW(
  256. delete opt1;
  257. );
  258. }
  259. // check that an option can contain nested suboptions:
  260. // opt1
  261. // +----opt2
  262. // |
  263. // +----opt3
  264. //
  265. TEST_F(OptionTest, v6_suboptions2) {
  266. boost::shared_array<uint8_t> buf(new uint8_t[128]);
  267. for (int i=0; i<128; i++)
  268. buf[i] = 100+i;
  269. Option* opt1 = new Option(Option::V6, 65535, //type
  270. buf,
  271. 0, // offset
  272. 3); // 3 bytes of data
  273. boost::shared_ptr<Option> opt2(new Option(Option::V6, 13));
  274. boost::shared_ptr<Option> opt3(new Option(Option::V6, 7,
  275. buf,
  276. 3, // offset
  277. 5)); // 5 bytes of data
  278. opt1->addOption(opt2);
  279. opt2->addOption(opt3);
  280. // opt3 len = 9 4(header)+5(data)
  281. // opt2 len = 4 (just header) + len(opt3)
  282. // opt1 len = 7 + len(opt2)
  283. uint8_t expected[] = {
  284. 0xff, 0xff, 0, 16, 100, 101, 102,
  285. 0, 13, 0, 9,
  286. 0, 7, 0, 5, 103, 104, 105, 106, 107,
  287. };
  288. int offset = opt1->pack(buf, 128, 20);
  289. EXPECT_EQ(40, offset);
  290. // payload
  291. EXPECT_EQ(0, memcmp(&buf[20], expected, 20) );
  292. EXPECT_NO_THROW(
  293. delete opt1;
  294. );
  295. }
  296. TEST_F(OptionTest, v6_addgetdel) {
  297. boost::shared_array<uint8_t> buf(new uint8_t[128]);
  298. for (int i=0; i<128; i++)
  299. buf[i] = 100+i;
  300. Option* parent = new Option(Option::V6, 65535); //type
  301. boost::shared_ptr<Option> opt1(new Option(Option::V6, 1));
  302. boost::shared_ptr<Option> opt2(new Option(Option::V6, 2));
  303. boost::shared_ptr<Option> opt3(new Option(Option::V6, 2));
  304. parent->addOption(opt1);
  305. parent->addOption(opt2);
  306. // getOption() test
  307. EXPECT_EQ(opt1, parent->getOption(1));
  308. EXPECT_EQ(opt2, parent->getOption(2));
  309. // expect NULL
  310. EXPECT_EQ(boost::shared_ptr<Option>(), parent->getOption(4));
  311. // now there are 2 options of type 2
  312. parent->addOption(opt3);
  313. // let's delete one of them
  314. EXPECT_EQ(true, parent->delOption(2));
  315. // there still should be the other option 2
  316. EXPECT_NE(boost::shared_ptr<Option>(), parent->getOption(2));
  317. // let's delete the other option 2
  318. EXPECT_EQ(true, parent->delOption(2));
  319. // no more options with type=2
  320. EXPECT_EQ(boost::shared_ptr<Option>(), parent->getOption(2));
  321. // let's try to delete - should fail
  322. EXPECT_TRUE(false == parent->delOption(2));
  323. }
  324. }
  325. TEST_F(OptionTest, v6_toText) {
  326. boost::shared_array<uint8_t> buf(new uint8_t[3]);
  327. buf[0] = 0;
  328. buf[1] = 0xf;
  329. buf[2] = 0xff;
  330. boost::shared_ptr<Option> opt(new Option(Option::V6, 258,
  331. buf, 0, 3));
  332. EXPECT_EQ("type=258, len=3: 00:0f:ff", opt->toText());
  333. }