option_custom_unittest.cc 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407
  1. // Copyright (C) 2012 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 <asiolink/io_address.h>
  16. #include <dhcp/option_custom.h>
  17. #include <boost/scoped_ptr.hpp>
  18. #include <gtest/gtest.h>
  19. using namespace isc;
  20. using namespace isc::asiolink;
  21. using namespace isc::dhcp;
  22. namespace {
  23. /// @brief OptionCustomTest test class.
  24. class OptionCustomTest : public ::testing::Test {
  25. public:
  26. /// @brief Constructor.
  27. OptionCustomTest() { }
  28. /// @brief Write IP address into a buffer.
  29. ///
  30. /// @param address address to be written.
  31. /// @param [out] buf output buffer.
  32. void writeAddress(const asiolink::IOAddress& address,
  33. std::vector<uint8_t>& buf) {
  34. const std::vector<uint8_t>& vec = address.toBytes();
  35. buf.insert(buf.end(), vec.begin(), vec.end());
  36. }
  37. /// @brief Write integer (signed or unsigned) into a buffer.
  38. ///
  39. /// @param value integer value.
  40. /// @param [out] buf output buffer.
  41. /// @tparam integer type.
  42. template<typename T>
  43. void writeInt(T value, std::vector<uint8_t>& buf) {
  44. for (int i = 0; i < sizeof(T); ++i) {
  45. buf.push_back(value >> ((sizeof(T) - i - 1) * 8) & 0xFF);
  46. }
  47. }
  48. /// @brief Write a string into a buffer.
  49. ///
  50. /// @param value string to be written into a buffer.
  51. /// @param buf output buffer.
  52. void writeString(const std::string& value,
  53. std::vector<uint8_t>& buf) {
  54. buf.resize(buf.size() + value.size());
  55. std::copy_backward(value.c_str(), value.c_str() + value.size(),
  56. buf.end());
  57. }
  58. };
  59. // The purpose of this test is to check that parameters passed to
  60. // a custom option's constructor are used to initialize class
  61. // members.
  62. TEST_F(OptionCustomTest, constructor) {
  63. // Create option definition for a DHCPv6 option.
  64. OptionDefinition opt_def1("OPTION_FOO", 1000, "boolean", true);
  65. // Initialize some dummy buffer that holds single boolean value.
  66. OptionBuffer buf;
  67. buf.push_back(1);
  68. // Create DHCPv6 option.
  69. boost::scoped_ptr<OptionCustom> option;
  70. ASSERT_NO_THROW(
  71. option.reset(new OptionCustom(opt_def1, Option::V6, buf));
  72. );
  73. ASSERT_TRUE(option);
  74. // Check if constructor initialized the universe and type correctly.
  75. EXPECT_EQ(Option::V6, option->getUniverse());
  76. EXPECT_EQ(1000, option->getType());
  77. // Do another round of testing for DHCPv4 option.
  78. OptionDefinition opt_def2("OPTION_FOO", 232, "boolean");
  79. ASSERT_NO_THROW(
  80. option.reset(new OptionCustom(opt_def2, Option::V4, buf.begin(), buf.end()));
  81. );
  82. ASSERT_TRUE(option);
  83. EXPECT_EQ(Option::V4, option->getUniverse());
  84. EXPECT_EQ(232, option->getType());
  85. // Try to create an option using 'empty data' constructor
  86. OptionDefinition opt_def3("OPTION_FOO", 1000, "uint32");
  87. ASSERT_NO_THROW(
  88. option.reset(new OptionCustom(opt_def3, Option::V6));
  89. );
  90. ASSERT_TRUE(option);
  91. EXPECT_EQ(Option::V6, option->getUniverse());
  92. EXPECT_EQ(1000, option->getType());
  93. }
  94. // The purpose of this test is to verify that 'empty' option definition can
  95. // be used to create an instance of custom option.
  96. TEST_F(OptionCustomTest, emptyData) {
  97. OptionDefinition opt_def("OPTION_FOO", 232, "empty");
  98. OptionBuffer buf;
  99. boost::scoped_ptr<OptionCustom> option;
  100. ASSERT_NO_THROW(
  101. option.reset(new OptionCustom(opt_def, Option::V4, buf.begin(), buf.end()));
  102. );
  103. ASSERT_TRUE(option);
  104. // Option is 'empty' so no data fields are expected.
  105. EXPECT_EQ(0, option->getDataFieldsNum());
  106. }
  107. // The purpose of this test is to verify that the option definition comprising
  108. // a binary value can be used to create an instance of custom option.
  109. TEST_F(OptionCustomTest, binaryData) {
  110. OptionDefinition opt_def("OPTION_FOO", 231, "binary");
  111. // Create a buffer holding some binary data. This data will be
  112. // used as reference when we read back the data from a created
  113. // option.
  114. OptionBuffer buf_in(14);
  115. for (int i = 0; i < 14; ++i) {
  116. buf_in[i] = i;
  117. }
  118. // Use scoped pointer because it allows to declare the option
  119. // in the function scope and initialize it under ASSERT.
  120. boost::scoped_ptr<OptionCustom> option;
  121. // Custom option may throw exception if the provided buffer is
  122. // malformed.
  123. ASSERT_NO_THROW(
  124. option.reset(new OptionCustom(opt_def, Option::V4, buf_in));
  125. );
  126. ASSERT_TRUE(option);
  127. // We should have just one data field.
  128. ASSERT_EQ(1, option->getDataFieldsNum());
  129. // The custom option should hold just one buffer that can be
  130. // accessed using index 0.
  131. OptionBuffer buf_out;
  132. ASSERT_NO_THROW(buf_out = option->readBinary(0));
  133. // Read buffer must match exactly with the buffer used to
  134. // create option instance.
  135. ASSERT_EQ(buf_in.size(), buf_out.size());
  136. EXPECT_TRUE(std::equal(buf_in.begin(), buf_in.end(), buf_out.begin()));
  137. // Check that option with "no data" is rejected.
  138. buf_in.clear();
  139. EXPECT_THROW(
  140. option.reset(new OptionCustom(opt_def, Option::V4, buf_in.begin(),
  141. buf_in.end())),
  142. isc::OutOfRange
  143. );
  144. }
  145. // The purpose of this test is to verify that an option definition comprising
  146. // a single boolean value can be used to create an instance of custom option.
  147. TEST_F(OptionCustomTest, booleanData) {
  148. OptionDefinition opt_def("OPTION_FOO", 1000, "boolean");
  149. OptionBuffer buf;
  150. // Push back the value that represents 'false'.
  151. buf.push_back(0);
  152. // Push back the 'true' value. Note that this value should
  153. // be ignored by custom option because it holds single boolean
  154. // value (according to option definition).
  155. buf.push_back(1);
  156. boost::scoped_ptr<OptionCustom> option;
  157. ASSERT_NO_THROW(
  158. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  159. );
  160. ASSERT_TRUE(option);
  161. // We should have just one data field.
  162. ASSERT_EQ(1, option->getDataFieldsNum());
  163. // Initialize the value to true because we want to make sure
  164. // that it is modified to 'false' by readBoolean below.
  165. bool value = true;
  166. // Read the boolean value from only one available buffer indexed
  167. // with 0. It is expected to be 'false'.
  168. ASSERT_NO_THROW(value = option->readBoolean(0));
  169. EXPECT_FALSE(value);
  170. // Check that the option with "no data" is rejected.
  171. buf.clear();
  172. EXPECT_THROW(
  173. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.end())),
  174. isc::OutOfRange
  175. );
  176. }
  177. // The purpose of this test is to verify that the data from a buffer
  178. // can be read as FQDN.
  179. TEST_F(OptionCustomTest, fqdnData) {
  180. OptionDefinition opt_def("OPTION_FOO", 1000, "fqdn");
  181. const char data[] = {
  182. 8, 109, 121, 100, 111, 109, 97, 105, 110, // "mydomain"
  183. 7, 101, 120, 97, 109, 112, 108, 101, // "example"
  184. 3, 99, 111, 109, // "com"
  185. 0,
  186. };
  187. std::vector<uint8_t> buf(data, data + sizeof(data));
  188. boost::scoped_ptr<OptionCustom> option;
  189. ASSERT_NO_THROW(
  190. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.end()));
  191. );
  192. ASSERT_TRUE(option);
  193. ASSERT_EQ(1, option->getDataFieldsNum());
  194. std::string domain0 = option->readFqdn(0);
  195. EXPECT_EQ("mydomain.example.com.", domain0);
  196. // Check that the option with truncated data can't be created.
  197. EXPECT_THROW(
  198. option.reset(new OptionCustom(opt_def, Option::V6,
  199. buf.begin(), buf.begin() + 4)),
  200. isc::dhcp::BadDataTypeCast
  201. );
  202. }
  203. // The purpose of this test is to verify that the option definition comprising
  204. // 16-bit signed integer value can be used to create an instance of custom option.
  205. TEST_F(OptionCustomTest, int16Data) {
  206. OptionDefinition opt_def("OPTION_FOO", 1000, "int16");
  207. OptionBuffer buf;
  208. // Store signed integer value in the input buffer.
  209. writeInt<int16_t>(-234, buf);
  210. // Create custom option.
  211. boost::scoped_ptr<OptionCustom> option;
  212. ASSERT_NO_THROW(
  213. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  214. );
  215. ASSERT_TRUE(option);
  216. // We should have just one data field.
  217. ASSERT_EQ(1, option->getDataFieldsNum());
  218. // Initialize value to 0 explicitely to make sure that is
  219. // modified by readInteger function to expected -234.
  220. int16_t value = 0;
  221. ASSERT_NO_THROW(value = option->readInteger<int16_t>(0));
  222. EXPECT_EQ(-234, value);
  223. // Check that the option is not created when a buffer is
  224. // too short (1 byte instead of 2 bytes).
  225. EXPECT_THROW(
  226. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.begin() + 1)),
  227. isc::OutOfRange
  228. );
  229. }
  230. // The purpose of this test is to verify that the option definition comprising
  231. // 32-bit signed integer value can be used to create an instance of custom option.
  232. TEST_F(OptionCustomTest, int32Data) {
  233. OptionDefinition opt_def("OPTION_FOO", 1000, "int32");
  234. OptionBuffer buf;
  235. writeInt<int32_t>(-234, buf);
  236. writeInt<int32_t>(100, buf);
  237. // Create custom option.
  238. boost::scoped_ptr<OptionCustom> option;
  239. ASSERT_NO_THROW(
  240. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  241. );
  242. ASSERT_TRUE(option);
  243. // We should have just one data field.
  244. ASSERT_EQ(1, option->getDataFieldsNum());
  245. // Initialize value to 0 explicitely to make sure that is
  246. // modified by readInteger function to expected -234.
  247. int32_t value = 0;
  248. ASSERT_NO_THROW(value = option->readInteger<int32_t>(0));
  249. EXPECT_EQ(-234, value);
  250. // Check that the option is not created when a buffer is
  251. // too short (3 bytes instead of 4 bytes).
  252. EXPECT_THROW(
  253. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.begin() + 3)),
  254. isc::OutOfRange
  255. );
  256. }
  257. // The purpose of this test is to verify that the option definition comprising
  258. // single IPv4 addres can be used to create an instance of custom option.
  259. TEST_F(OptionCustomTest, ipv4AddressData) {
  260. OptionDefinition opt_def("OPTION_FOO", 231, "ipv4-address");
  261. // Create input buffer.
  262. OptionBuffer buf;
  263. writeAddress(IOAddress("192.168.100.50"), buf);
  264. // Create custom option.
  265. boost::scoped_ptr<OptionCustom> option;
  266. ASSERT_NO_THROW(
  267. option.reset(new OptionCustom(opt_def, Option::V4, buf));
  268. );
  269. ASSERT_TRUE(option);
  270. // We should have just one data field.
  271. ASSERT_EQ(1, option->getDataFieldsNum());
  272. IOAddress address("127.0.0.1");
  273. // Read IPv4 address from using index 0.
  274. ASSERT_NO_THROW(address = option->readAddress(0));
  275. EXPECT_EQ("192.168.100.50", address.toText());
  276. // Check that option is not created if the provided buffer is
  277. // too short (use 3 bytes instead of 4).
  278. EXPECT_THROW(
  279. option.reset(new OptionCustom(opt_def, Option::V4, buf.begin(), buf.begin() + 3)),
  280. isc::OutOfRange
  281. );
  282. }
  283. // The purpose of this test is to verify that the option definition comprising
  284. // single IPv6 addres can be used to create an instance of custom option.
  285. TEST_F(OptionCustomTest, ipv6AddressData) {
  286. OptionDefinition opt_def("OPTION_FOO", 1000, "ipv6-address");
  287. // Initialize input buffer.
  288. OptionBuffer buf;
  289. writeAddress(IOAddress("2001:db8:1::100"), buf);
  290. // Create custom option using input buffer.
  291. boost::scoped_ptr<OptionCustom> option;
  292. ASSERT_NO_THROW(
  293. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  294. );
  295. ASSERT_TRUE(option);
  296. // We should have just one data field.
  297. ASSERT_EQ(1, option->getDataFieldsNum());
  298. // Custom option should comprise exactly one buffer that represents
  299. // IPv6 address.
  300. IOAddress address("::1");
  301. // Read an address from buffer #0.
  302. ASSERT_NO_THROW(address = option->readAddress(0));
  303. EXPECT_EQ("2001:db8:1::100", address.toText());
  304. // Check that option is not created if the provided buffer is
  305. // too short (use 15 bytes instead of 16).
  306. EXPECT_THROW(
  307. option.reset(new OptionCustom(opt_def, Option::V4, buf.begin(),
  308. buf.begin() + 15)),
  309. isc::OutOfRange
  310. );
  311. }
  312. // The purpose of this test is to verify that the option definition comprising
  313. // string value can be used to create an instance of custom option.
  314. TEST_F(OptionCustomTest, stringData) {
  315. OptionDefinition opt_def("OPTION_FOO", 1000, "string");
  316. // Create an input buffer holding some string value.
  317. OptionBuffer buf;
  318. writeString("hello world!", buf);
  319. // Create custom option using input buffer.
  320. boost::scoped_ptr<OptionCustom> option;
  321. ASSERT_NO_THROW(
  322. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.end()));
  323. );
  324. ASSERT_TRUE(option);
  325. // We should have just one data field.
  326. ASSERT_EQ(1, option->getDataFieldsNum());
  327. // Custom option should now comprise single string value that
  328. // can be accessed using index 0.
  329. std::string value;
  330. ASSERT_NO_THROW(value = option->readString(0));
  331. EXPECT_EQ("hello world!", value);
  332. // Check that option will not be created if empty buffer is provided.
  333. buf.clear();
  334. EXPECT_THROW(
  335. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.end())),
  336. isc::OutOfRange
  337. );
  338. }
  339. // The purpose of this test is to verify that the option definition comprising
  340. // an array of boolean values can be used to create an instance of custom option.
  341. TEST_F(OptionCustomTest, booleanDataArray) {
  342. OptionDefinition opt_def("OPTION_FOO", 1000, "boolean", true);
  343. // Create a buffer with 5 values that represent array of
  344. // booleans.
  345. OptionBuffer buf(5);
  346. buf[0] = 1; // true
  347. buf[1] = 0; // false
  348. buf[2] = 0; // false
  349. buf[3] = 1; // true
  350. buf[4] = 1; // true
  351. // Use the input buffer to create custom option.
  352. boost::scoped_ptr<OptionCustom> option;
  353. ASSERT_NO_THROW(
  354. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.end()));
  355. );
  356. ASSERT_TRUE(option);
  357. // We should have 5 data fields.
  358. ASSERT_EQ(5, option->getDataFieldsNum());
  359. // Read values from custom option using indexes 0..4 and
  360. // check that they are valid.
  361. bool value0 = false;
  362. ASSERT_NO_THROW(value0 = option->readBoolean(0));
  363. EXPECT_TRUE(value0);
  364. bool value1 = true;
  365. ASSERT_NO_THROW(value1 = option->readBoolean(1));
  366. EXPECT_FALSE(value1);
  367. bool value2 = true;
  368. ASSERT_NO_THROW(value2 = option->readBoolean(2));
  369. EXPECT_FALSE(value2);
  370. bool value3 = false;
  371. ASSERT_NO_THROW(value3 = option->readBoolean(3));
  372. EXPECT_TRUE(value3);
  373. bool value4 = false;
  374. ASSERT_NO_THROW(value4 = option->readBoolean(4));
  375. EXPECT_TRUE(value4);
  376. // Check that empty buffer can't be used to create option holding
  377. // array of boolean values.
  378. buf.clear();
  379. EXPECT_THROW(
  380. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.end())),
  381. isc::OutOfRange
  382. );
  383. }
  384. // The purpose of this test is to verify that the option definition comprising
  385. // an array of 32-bit signed integer values can be used to create an instance
  386. // of custom option.
  387. TEST_F(OptionCustomTest, uint32DataArray) {
  388. OptionDefinition opt_def("OPTION_FOO", 1000, "uint32", true);
  389. // Create an input buffer that holds 4 uint32 values that
  390. // represent an array.
  391. std::vector<uint32_t> values;
  392. values.push_back(71234);
  393. values.push_back(12234);
  394. values.push_back(54362);
  395. values.push_back(1234);
  396. // Store these values in a buffer.
  397. OptionBuffer buf;
  398. for (int i = 0; i < values.size(); ++i) {
  399. writeInt<uint32_t>(values[i], buf);
  400. }
  401. // Create custom option using the input buffer.
  402. boost::scoped_ptr<OptionCustom> option;
  403. ASSERT_NO_THROW(
  404. // Note that we just use a part of the whole buffer here: 13 bytes. We want to
  405. // check that buffer length which is non-divisible by 4 (size of uint32_t) is
  406. // accepted and only 3 (instead of 4) elements will be stored in a custom option.
  407. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.begin() + 13));
  408. );
  409. ASSERT_TRUE(option);
  410. // We should have 3 data fields.
  411. ASSERT_EQ(3, option->getDataFieldsNum());
  412. // Expect only 3 values.
  413. for (int i = 0; i < 3; ++i) {
  414. uint32_t value = 0;
  415. ASSERT_NO_THROW(value = option->readInteger<uint32_t>(i));
  416. EXPECT_EQ(values[i], value);
  417. }
  418. // Check that too short buffer can't be used to create the option.
  419. // Using buffer having length of 3 bytes. The length of 4 bytes is
  420. // a minimal length to create the option with single uint32_t value.
  421. EXPECT_THROW(
  422. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(),
  423. buf.begin() + 3)),
  424. isc::OutOfRange
  425. );
  426. }
  427. // The purpose of this test is to verify that the option definition comprising
  428. // an array of IPv4 addresses can be used to create an instance of custom option.
  429. TEST_F(OptionCustomTest, ipv4AddressDataArray) {
  430. OptionDefinition opt_def("OPTION_FOO", 231, "ipv4-address", true);
  431. // Initialize reference data.
  432. std::vector<IOAddress> addresses;
  433. addresses.push_back(IOAddress("192.168.0.1"));
  434. addresses.push_back(IOAddress("127.0.0.1"));
  435. addresses.push_back(IOAddress("10.10.1.2"));
  436. // Store the collection of IPv4 addresses into the buffer.
  437. OptionBuffer buf;
  438. for (int i = 0; i < addresses.size(); ++i) {
  439. writeAddress(addresses[i], buf);
  440. }
  441. // Use the input buffer to create custom option.
  442. boost::scoped_ptr<OptionCustom> option;
  443. ASSERT_NO_THROW(
  444. option.reset(new OptionCustom(opt_def, Option::V4, buf));
  445. );
  446. ASSERT_TRUE(option);
  447. // We should have 3 data fields.
  448. ASSERT_EQ(3, option->getDataFieldsNum());
  449. // We expect 3 IPv4 addresses being stored in the option.
  450. for (int i = 0; i < 3; ++i) {
  451. IOAddress address("10.10.10.10");
  452. ASSERT_NO_THROW(address = option->readAddress(i));
  453. EXPECT_EQ(addresses[i].toText(), address.toText());
  454. }
  455. // Check that it is ok if buffer length is not a multiple of IPv4
  456. // address length. Resize it by two bytes.
  457. buf.resize(buf.size() + 2);
  458. EXPECT_NO_THROW(
  459. option.reset(new OptionCustom(opt_def, Option::V4, buf));
  460. );
  461. // Check that option is not created when the provided buffer
  462. // is too short. At least a buffer length of 4 bytes is needed.
  463. EXPECT_THROW(
  464. option.reset(new OptionCustom(opt_def, Option::V4, buf.begin(),
  465. buf.begin() + 2)),
  466. isc::OutOfRange
  467. );
  468. }
  469. // The purpose of this test is to verify that the option definition comprising
  470. // an array of IPv6 addresses can be used to create an instance of custom option.
  471. TEST_F(OptionCustomTest, ipv6AddressDataArray) {
  472. OptionDefinition opt_def("OPTION_FOO", 1000, "ipv6-address", true);
  473. // Initialize reference data.
  474. std::vector<IOAddress> addresses;
  475. addresses.push_back(IOAddress("2001:db8:1::3"));
  476. addresses.push_back(IOAddress("::1"));
  477. addresses.push_back(IOAddress("fe80::3"));
  478. // Store the collection of IPv6 addresses into the buffer.
  479. OptionBuffer buf;
  480. for (int i = 0; i < addresses.size(); ++i) {
  481. writeAddress(addresses[i], buf);
  482. }
  483. // Use the input buffer to create custom option.
  484. boost::scoped_ptr<OptionCustom> option;
  485. ASSERT_NO_THROW(
  486. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  487. );
  488. ASSERT_TRUE(option);
  489. // We should have 3 data fields.
  490. ASSERT_EQ(3, option->getDataFieldsNum());
  491. // We expect 3 IPv6 addresses being stored in the option.
  492. for (int i = 0; i < 3; ++i) {
  493. IOAddress address("fe80::4");
  494. ASSERT_NO_THROW(address = option->readAddress(i));
  495. EXPECT_EQ(addresses[i].toText(), address.toText());
  496. }
  497. // Check that it is ok if buffer length is not a multiple of IPv6
  498. // address length. Resize it by two bytes.
  499. buf.resize(buf.size() + 2);
  500. EXPECT_NO_THROW(
  501. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  502. );
  503. // Check that option is not created when the provided buffer
  504. // is too short. At least a buffer length of 16 bytes is needed.
  505. EXPECT_THROW(
  506. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(),
  507. buf.begin() + 15)),
  508. isc::OutOfRange
  509. );
  510. }
  511. // The purpose of this test is to verify that the option comprising
  512. // an array of FQDN values can be created from a buffer which holds
  513. // multiple FQDN values encoded as described in the RFC1035, section
  514. // 3.1
  515. TEST_F(OptionCustomTest, fqdnDataArray) {
  516. OptionDefinition opt_def("OPTION_FOO", 1000, "fqdn", true);
  517. const char data[] = {
  518. 8, 109, 121, 100, 111, 109, 97, 105, 110, // "mydomain"
  519. 7, 101, 120, 97, 109, 112, 108, 101, // "example"
  520. 3, 99, 111, 109, // "com"
  521. 0,
  522. 7, 101, 120, 97, 109, 112, 108, 101, // "example"
  523. 3, 99, 111, 109, // "com"
  524. 0
  525. };
  526. // Create a buffer that holds two FQDNs.
  527. std::vector<uint8_t> buf(data, data + sizeof(data));
  528. // Create an option from using a buffer.
  529. boost::scoped_ptr<OptionCustom> option;
  530. ASSERT_NO_THROW(
  531. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  532. );
  533. ASSERT_TRUE(option);
  534. // We expect that two FQDN values have been extracted
  535. // from a buffer.
  536. ASSERT_EQ(2, option->getDataFieldsNum());
  537. // Validate both values.
  538. std::string domain0 = option->readFqdn(0);
  539. EXPECT_EQ("mydomain.example.com.", domain0);
  540. std::string domain1 = option->readFqdn(1);
  541. EXPECT_EQ("example.com.", domain1);
  542. }
  543. // The purpose of this test is to verify that the option definition comprising
  544. // a record of various data fields can be used to create an instance of
  545. // custom option.
  546. TEST_F(OptionCustomTest, recordData) {
  547. // Create the definition of an option which comprises
  548. // a record of fields of different types.
  549. OptionDefinition opt_def("OPTION_FOO", 1000, "record");
  550. ASSERT_NO_THROW(opt_def.addRecordField("uint16"));
  551. ASSERT_NO_THROW(opt_def.addRecordField("boolean"));
  552. ASSERT_NO_THROW(opt_def.addRecordField("fqdn"));
  553. ASSERT_NO_THROW(opt_def.addRecordField("ipv4-address"));
  554. ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  555. ASSERT_NO_THROW(opt_def.addRecordField("string"));
  556. const char fqdn_data[] = {
  557. 8, 109, 121, 100, 111, 109, 97, 105, 110, // "mydomain"
  558. 7, 101, 120, 97, 109, 112, 108, 101, // "example"
  559. 3, 99, 111, 109, // "com"
  560. 0,
  561. };
  562. OptionBuffer buf;
  563. // Initialize field 0 to 8712.
  564. writeInt<uint16_t>(8712, buf);
  565. // Initialize field 1 to 'true'
  566. buf.push_back(static_cast<unsigned short>(1));
  567. // Initialize field 2 to 'mydomain.example.com'.
  568. buf.insert(buf.end(), fqdn_data, fqdn_data + sizeof(fqdn_data));
  569. // Initialize field 3 to IPv4 address.
  570. writeAddress(IOAddress("192.168.0.1"), buf);
  571. // Initialize field 4 to IPv6 address.
  572. writeAddress(IOAddress("2001:db8:1::1"), buf);
  573. // Initialize field 5 to string value.
  574. writeString("ABCD", buf);
  575. boost::scoped_ptr<OptionCustom> option;
  576. ASSERT_NO_THROW(
  577. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.end()));
  578. );
  579. ASSERT_TRUE(option);
  580. // We should have 6 data fields.
  581. ASSERT_EQ(6, option->getDataFieldsNum());
  582. // Verify value in the field 0.
  583. uint16_t value0 = 0;
  584. ASSERT_NO_THROW(value0 = option->readInteger<uint16_t>(0));
  585. EXPECT_EQ(8712, value0);
  586. // Verify value in the field 1.
  587. bool value1 = false;
  588. ASSERT_NO_THROW(value1 = option->readBoolean(1));
  589. EXPECT_TRUE(value1);
  590. // Verify value in the field 2.
  591. std::string value2 = "";
  592. ASSERT_NO_THROW(value2 = option->readFqdn(2));
  593. EXPECT_EQ("mydomain.example.com.", value2);
  594. // Verify value in the field 3.
  595. IOAddress value3("127.0.0.1");
  596. ASSERT_NO_THROW(value3 = option->readAddress(3));
  597. EXPECT_EQ("192.168.0.1", value3.toText());
  598. // Verify value in the field 4.
  599. IOAddress value4("::1");
  600. ASSERT_NO_THROW(value4 = option->readAddress(4));
  601. EXPECT_EQ("2001:db8:1::1", value4.toText());
  602. // Verify value in the field 5.
  603. std::string value5;
  604. ASSERT_NO_THROW(value5 = option->readString(5));
  605. EXPECT_EQ("ABCD", value5);
  606. }
  607. // The purpose of this test is to verify that truncated buffer
  608. // can't be used to create an option being a record of value of
  609. // different types.
  610. TEST_F(OptionCustomTest, recordDataTruncated) {
  611. // Create the definition of an option which comprises
  612. // a record of fields of different types.
  613. OptionDefinition opt_def("OPTION_FOO", 1000, "record");
  614. ASSERT_NO_THROW(opt_def.addRecordField("uint16"));
  615. ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  616. ASSERT_NO_THROW(opt_def.addRecordField("string"));
  617. OptionBuffer buf;
  618. // Initialize field 0.
  619. writeInt<uint16_t>(8712, buf);
  620. // Initialize field 1 to IPv6 address.
  621. writeAddress(IOAddress("2001:db8:1::1"), buf);
  622. // Initialize field 2 to string value.
  623. writeString("ABCD", buf);
  624. boost::scoped_ptr<OptionCustom> option;
  625. // Constructor should not throw exception here because the length of the
  626. // buffer meets the minimum length. The first 19 bytes hold data for
  627. // all option fields: uint16, IPv4 address and first letter of string.
  628. // Note that string will be truncated but this is acceptable because
  629. // constructor have no way to determine the length of the original string.
  630. EXPECT_NO_THROW(
  631. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.begin() + 19));
  632. );
  633. // Reduce the buffer length by one byte should cause the constructor
  634. // to fail. This is because 18 bytes can only hold first two data fields:
  635. // 2 bytes of uint16_t value and IPv6 address. Option definitions specifies
  636. // 3 data fields for this option but the length of the data is insufficient
  637. // to initialize 3 data field.
  638. EXPECT_THROW(
  639. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.begin() + 18)),
  640. isc::OutOfRange
  641. );
  642. // Try to further reduce the length of the buffer to make it insufficient
  643. // to even initialize the second data field.
  644. EXPECT_THROW(
  645. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.begin() + 17)),
  646. isc::OutOfRange
  647. );
  648. }
  649. // The purpose of this test is to verify that an option comprising
  650. // single data field with binary data can be used and that this
  651. // binary data is properly initialized to a default value. This
  652. // test also checks that it is possible to override this default
  653. // value.
  654. TEST_F(OptionCustomTest, setBinaryData) {
  655. OptionDefinition opt_def("OPTION_FOO", 1000, "binary");
  656. // Create an option and let the data field be initialized
  657. // to default value (do not provide any data buffer).
  658. boost::scoped_ptr<OptionCustom> option;
  659. ASSERT_NO_THROW(
  660. option.reset(new OptionCustom(opt_def, Option::V6));
  661. );
  662. ASSERT_TRUE(option);
  663. // Get the default binary value.
  664. OptionBuffer buf;
  665. ASSERT_NO_THROW(option->readBinary());
  666. // The buffer is by default empty.
  667. EXPECT_TRUE(buf.empty());
  668. // Prepare input buffer with some dummy data.
  669. OptionBuffer buf_in(10);
  670. for (int i = 0; i < buf_in.size(); ++i) {
  671. buf_in[i] = i;
  672. }
  673. // Try to override the default binary buffer.
  674. ASSERT_NO_THROW(option->writeBinary(buf_in));
  675. // And check that it has been actually overriden.
  676. ASSERT_NO_THROW(buf = option->readBinary());
  677. ASSERT_EQ(buf_in.size(), buf.size());
  678. EXPECT_TRUE(std::equal(buf_in.begin(), buf_in.end(), buf.begin()));
  679. }
  680. // The purpose of this test is to verify that an option comprising
  681. // single boolean data field can be created and that its default
  682. // value can be overriden by a new value.
  683. TEST_F(OptionCustomTest, setBooleanData) {
  684. OptionDefinition opt_def("OPTION_FOO", 1000, "boolean");
  685. // Create an option and let the data field be initialized
  686. // to default value (do not provide any data buffer).
  687. boost::scoped_ptr<OptionCustom> option;
  688. ASSERT_NO_THROW(
  689. option.reset(new OptionCustom(opt_def, Option::V6));
  690. );
  691. ASSERT_TRUE(option);
  692. // Check that the default boolean value is false.
  693. bool value = false;
  694. ASSERT_NO_THROW(value = option->readBoolean());
  695. EXPECT_FALSE(value);
  696. // Check that we can override the default value.
  697. ASSERT_NO_THROW(option->writeBoolean(true));
  698. // Finally, check that it has been actually overriden.
  699. ASSERT_NO_THROW(value = option->readBoolean());
  700. EXPECT_TRUE(value);
  701. }
  702. /// The purpose of this test is to verify that the data field value
  703. /// can be overriden by a new value.
  704. TEST_F(OptionCustomTest, setUint32Data) {
  705. // Create a definition of an option that holds single
  706. // uint32 value.
  707. OptionDefinition opt_def("OPTION_FOO", 1000, "uint32");
  708. // Create an option and let the data field be initialized
  709. // to default value (do not provide any data buffer).
  710. boost::scoped_ptr<OptionCustom> option;
  711. ASSERT_NO_THROW(
  712. option.reset(new OptionCustom(opt_def, Option::V6));
  713. );
  714. ASSERT_TRUE(option);
  715. // The default value for integer data fields is 0.
  716. uint32_t value = 0;
  717. ASSERT_NO_THROW(option->readInteger<uint32_t>());
  718. EXPECT_EQ(0, value);
  719. // Try to set the data field value to something different
  720. // than 0.
  721. ASSERT_NO_THROW(option->writeInteger<uint32_t>(1234));
  722. // Verify that it has been set.
  723. ASSERT_NO_THROW(value = option->readInteger<uint32_t>());
  724. EXPECT_EQ(1234, value);
  725. }
  726. // The purpose of this test is to verify that an option comprising
  727. // single IPv4 address can be created and that this address can
  728. // be overriden by a new value.
  729. TEST_F(OptionCustomTest, setIpv4AddressData) {
  730. OptionDefinition opt_def("OPTION_FOO", 232, "ipv4-address");
  731. // Create an option and let the data field be initialized
  732. // to default value (do not provide any data buffer).
  733. boost::scoped_ptr<OptionCustom> option;
  734. ASSERT_NO_THROW(
  735. option.reset(new OptionCustom(opt_def, Option::V4));
  736. );
  737. ASSERT_TRUE(option);
  738. asiolink::IOAddress address("127.0.0.1");
  739. ASSERT_NO_THROW(address = option->readAddress());
  740. EXPECT_EQ("0.0.0.0", address.toText());
  741. EXPECT_NO_THROW(option->writeAddress(IOAddress("192.168.0.1")));
  742. EXPECT_NO_THROW(address = option->readAddress());
  743. EXPECT_EQ("192.168.0.1", address.toText());
  744. }
  745. // The purpose of this test is to verify that an opton comprising
  746. // single IPv6 address can be created and that this address can
  747. // be overriden by a new value.
  748. TEST_F(OptionCustomTest, setIpv6AddressData) {
  749. OptionDefinition opt_def("OPTION_FOO", 1000, "ipv6-address");
  750. // Create an option and let the data field be initialized
  751. // to default value (do not provide any data buffer).
  752. boost::scoped_ptr<OptionCustom> option;
  753. ASSERT_NO_THROW(
  754. option.reset(new OptionCustom(opt_def, Option::V6));
  755. );
  756. ASSERT_TRUE(option);
  757. asiolink::IOAddress address("::1");
  758. ASSERT_NO_THROW(address = option->readAddress());
  759. EXPECT_EQ("::", address.toText());
  760. EXPECT_NO_THROW(option->writeAddress(IOAddress("2001:db8:1::1")));
  761. EXPECT_NO_THROW(address = option->readAddress());
  762. EXPECT_EQ("2001:db8:1::1", address.toText());
  763. }
  764. // The purpose of this test is to verify that an option comprising
  765. // single string value can be created and that this value
  766. // is initialized to the default value. Also, this test checks that
  767. // this value can be overwritten by a new value.
  768. TEST_F(OptionCustomTest, setStringData) {
  769. OptionDefinition opt_def("OPTION_FOO", 1000, "string");
  770. // Create an option and let the data field be initialized
  771. // to default value (do not provide any data buffer).
  772. boost::scoped_ptr<OptionCustom> option;
  773. ASSERT_NO_THROW(
  774. option.reset(new OptionCustom(opt_def, Option::V6));
  775. );
  776. ASSERT_TRUE(option);
  777. // Get the default value of the option.
  778. std::string value;
  779. ASSERT_NO_THROW(value = option->readString());
  780. // By default the string data field is empty.
  781. EXPECT_TRUE(value.empty());
  782. // Write some text to this field.
  783. ASSERT_NO_THROW(option->writeString("hello world"));
  784. // Check that it has been actually written.
  785. EXPECT_NO_THROW(value = option->readString());
  786. EXPECT_EQ("hello world", value);
  787. }
  788. /// The purpose of this test is to verify that an option comprising
  789. /// a default FQDN value can be created and that this value can be
  790. /// overriden after the option has been created.
  791. TEST_F(OptionCustomTest, setFqdnData) {
  792. OptionDefinition opt_def("OPTION_FOO", 1000, "fqdn");
  793. // Create an option and let the data field be initialized
  794. // to default value (do not provide any data buffer).
  795. boost::scoped_ptr<OptionCustom> option;
  796. ASSERT_NO_THROW(
  797. option.reset(new OptionCustom(opt_def, Option::V6));
  798. );
  799. ASSERT_TRUE(option);
  800. // Read a default FQDN value from the option.
  801. std::string fqdn;
  802. ASSERT_NO_THROW(fqdn = option->readFqdn());
  803. EXPECT_EQ(".", fqdn);
  804. // Try override the default FQDN value.
  805. ASSERT_NO_THROW(option->writeFqdn("example.com"));
  806. // Check that the value has been actually overriden.
  807. ASSERT_NO_THROW(fqdn = option->readFqdn());
  808. EXPECT_EQ("example.com.", fqdn);
  809. }
  810. // The purpose of this test is to verify that an option carrying
  811. // an array of boolean values can be created with no values
  812. // initially and that values can be later added to it.
  813. TEST_F(OptionCustomTest, setBooleanDataArray) {
  814. OptionDefinition opt_def("OPTION_FOO", 1000, "boolean", true);
  815. // Create an option and let the data field be initialized
  816. // to default value (do not provide any data buffer).
  817. boost::scoped_ptr<OptionCustom> option;
  818. ASSERT_NO_THROW(
  819. option.reset(new OptionCustom(opt_def, Option::V6));
  820. );
  821. ASSERT_TRUE(option);
  822. // Initially, the array should contain no values.
  823. ASSERT_EQ(0, option->getDataFieldsNum());
  824. // Add some boolean values to it.
  825. ASSERT_NO_THROW(option->addArrayDataField(true));
  826. ASSERT_NO_THROW(option->addArrayDataField(false));
  827. ASSERT_NO_THROW(option->addArrayDataField(true));
  828. // Verify that the new data fields can be added.
  829. bool value0 = false;
  830. ASSERT_NO_THROW(value0 = option->readBoolean(0));
  831. EXPECT_TRUE(value0);
  832. bool value1 = true;
  833. ASSERT_NO_THROW(value1 = option->readBoolean(1));
  834. EXPECT_FALSE(value1);
  835. bool value2 = false;
  836. ASSERT_NO_THROW(value2 = option->readBoolean(2));
  837. EXPECT_TRUE(value2);
  838. }
  839. // The purpose of this test is to verify that am option carying
  840. // an array of 16-bit signed integer values can be created with
  841. // no values initially and that the values can be later added to it.
  842. TEST_F(OptionCustomTest, setUint16DataArray) {
  843. OptionDefinition opt_def("OPTION_FOO", 1000, "uint16", true);
  844. // Create an option and let the data field be initialized
  845. // to default value (do not provide any data buffer).
  846. boost::scoped_ptr<OptionCustom> option;
  847. ASSERT_NO_THROW(
  848. option.reset(new OptionCustom(opt_def, Option::V6));
  849. );
  850. ASSERT_TRUE(option);
  851. // Initially, the array should contain no values.
  852. ASSERT_EQ(0, option->getDataFieldsNum());
  853. // Add 3 new data fields holding integer values.
  854. ASSERT_NO_THROW(option->addArrayDataField<uint16_t>(67));
  855. ASSERT_NO_THROW(option->addArrayDataField<uint16_t>(876));
  856. ASSERT_NO_THROW(option->addArrayDataField<uint16_t>(32222));
  857. // We should now have 3 data fields.
  858. ASSERT_EQ(3, option->getDataFieldsNum());
  859. // Check that the values have been correctly set.
  860. uint16_t value0;
  861. ASSERT_NO_THROW(value0 = option->readInteger<uint16_t>(0));
  862. EXPECT_EQ(67, value0);
  863. uint16_t value1;
  864. ASSERT_NO_THROW(value1 = option->readInteger<uint16_t>(1));
  865. EXPECT_EQ(876, value1);
  866. uint16_t value2;
  867. ASSERT_NO_THROW(value2 = option->readInteger<uint16_t>(2));
  868. EXPECT_EQ(32222, value2);
  869. }
  870. /// The purpose of this test is to verify that an option comprising
  871. /// array of IPv4 address can be created with no addresses and that
  872. /// multiple IPv4 addresses can be added to it after creation.
  873. TEST_F(OptionCustomTest, setIpv4AddressDataArray) {
  874. OptionDefinition opt_def("OPTION_FOO", 232, "ipv4-address", true);
  875. // Create an option and let the data field be initialized
  876. // to default value (do not provide any data buffer).
  877. boost::scoped_ptr<OptionCustom> option;
  878. ASSERT_NO_THROW(
  879. option.reset(new OptionCustom(opt_def, Option::V4));
  880. );
  881. ASSERT_TRUE(option);
  882. // Expect that the array does not contain any data fields yet.
  883. ASSERT_EQ(0, option->getDataFieldsNum());
  884. // Add 3 IPv4 addresses.
  885. ASSERT_NO_THROW(option->addArrayDataField(IOAddress("192.168.0.1")));
  886. ASSERT_NO_THROW(option->addArrayDataField(IOAddress("192.168.0.2")));
  887. ASSERT_NO_THROW(option->addArrayDataField(IOAddress("192.168.0.3")));
  888. ASSERT_EQ(3, option->getDataFieldsNum());
  889. // Check that all IP addresses have been set correctly.
  890. IOAddress address0("127.0.0.1");
  891. ASSERT_NO_THROW(address0 = option->readAddress(0));
  892. EXPECT_EQ("192.168.0.1", address0.toText());
  893. IOAddress address1("127.0.0.1");
  894. ASSERT_NO_THROW(address1 = option->readAddress(1));
  895. EXPECT_EQ("192.168.0.2", address1.toText());
  896. IOAddress address2("127.0.0.1");
  897. ASSERT_NO_THROW(address2 = option->readAddress(2));
  898. EXPECT_EQ("192.168.0.3", address2.toText());
  899. // Add invalid address (IPv6 instead of IPv4).
  900. EXPECT_THROW(
  901. option->addArrayDataField(IOAddress("2001:db8:1::1")),
  902. isc::dhcp::BadDataTypeCast
  903. );
  904. }
  905. /// The purpose of this test is to verify that an option comprising
  906. /// array of IPv6 address can be created with no addresses and that
  907. /// multiple IPv6 addresses can be added to it after creation.
  908. TEST_F(OptionCustomTest, setIpv6AddressDataArray) {
  909. OptionDefinition opt_def("OPTION_FOO", 1000, "ipv6-address", true);
  910. // Create an option and let the data field be initialized
  911. // to default value (do not provide any data buffer).
  912. boost::scoped_ptr<OptionCustom> option;
  913. ASSERT_NO_THROW(
  914. option.reset(new OptionCustom(opt_def, Option::V6));
  915. );
  916. ASSERT_TRUE(option);
  917. // Initially, the array does not contain any data fields.
  918. ASSERT_EQ(0, option->getDataFieldsNum());
  919. // Add 3 new IPv6 addresses into the array.
  920. ASSERT_NO_THROW(option->addArrayDataField(IOAddress("2001:db8:1::1")));
  921. ASSERT_NO_THROW(option->addArrayDataField(IOAddress("2001:db8:1::2")));
  922. ASSERT_NO_THROW(option->addArrayDataField(IOAddress("2001:db8:1::3")));
  923. // We should have now 3 addresses added.
  924. ASSERT_EQ(3, option->getDataFieldsNum());
  925. // Check that they have correct values set.
  926. IOAddress address0("::1");
  927. ASSERT_NO_THROW(address0 = option->readAddress(0));
  928. EXPECT_EQ("2001:db8:1::1", address0.toText());
  929. IOAddress address1("::1");
  930. ASSERT_NO_THROW(address1 = option->readAddress(1));
  931. EXPECT_EQ("2001:db8:1::2", address1.toText());
  932. IOAddress address2("::1");
  933. ASSERT_NO_THROW(address2 = option->readAddress(2));
  934. EXPECT_EQ("2001:db8:1::3", address2.toText());
  935. // Add invalid address (IPv4 instead of IPv6).
  936. EXPECT_THROW(
  937. option->addArrayDataField(IOAddress("192.168.0.1")),
  938. isc::dhcp::BadDataTypeCast
  939. );
  940. }
  941. TEST_F(OptionCustomTest, setRecordData) {
  942. OptionDefinition opt_def("OPTION_FOO", 1000, "record");
  943. ASSERT_NO_THROW(opt_def.addRecordField("uint16"));
  944. ASSERT_NO_THROW(opt_def.addRecordField("boolean"));
  945. ASSERT_NO_THROW(opt_def.addRecordField("fqdn"));
  946. ASSERT_NO_THROW(opt_def.addRecordField("ipv4-address"));
  947. ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  948. ASSERT_NO_THROW(opt_def.addRecordField("string"));
  949. // Create an option and let the data field be initialized
  950. // to default value (do not provide any data buffer).
  951. boost::scoped_ptr<OptionCustom> option;
  952. ASSERT_NO_THROW(
  953. option.reset(new OptionCustom(opt_def, Option::V6));
  954. );
  955. ASSERT_TRUE(option);
  956. // The number of elements should be equal to number of elements
  957. // in the record.
  958. ASSERT_EQ(6, option->getDataFieldsNum());
  959. // Check that the default values have been correctly set.
  960. uint16_t value0;
  961. ASSERT_NO_THROW(value0 = option->readInteger<uint16_t>(0));
  962. EXPECT_EQ(0, value0);
  963. bool value1 = true;
  964. ASSERT_NO_THROW(value1 = option->readBoolean(1));
  965. EXPECT_FALSE(value1);
  966. std::string value2;
  967. ASSERT_NO_THROW(value2 = option->readFqdn(2));
  968. EXPECT_EQ(".", value2);
  969. IOAddress value3("127.0.0.1");
  970. ASSERT_NO_THROW(value3 = option->readAddress(3));
  971. EXPECT_EQ("0.0.0.0", value3.toText());
  972. IOAddress value4("2001:db8:1::1");
  973. ASSERT_NO_THROW(value4 = option->readAddress(4));
  974. EXPECT_EQ("::", value4.toText());
  975. std::string value5 = "xyz";
  976. ASSERT_NO_THROW(value5 = option->readString(5));
  977. EXPECT_TRUE(value5.empty());
  978. // Override each value with a new value.
  979. ASSERT_NO_THROW(option->writeInteger<uint16_t>(1234, 0));
  980. ASSERT_NO_THROW(option->writeBoolean(true, 1));
  981. ASSERT_NO_THROW(option->writeFqdn("example.com", 2));
  982. ASSERT_NO_THROW(option->writeAddress(IOAddress("192.168.0.1"), 3));
  983. ASSERT_NO_THROW(option->writeAddress(IOAddress("2001:db8:1::100"), 4));
  984. ASSERT_NO_THROW(option->writeString("hello world", 5));
  985. // Check that the new values have been correctly set.
  986. ASSERT_NO_THROW(value0 = option->readInteger<uint16_t>(0));
  987. EXPECT_EQ(1234, value0);
  988. ASSERT_NO_THROW(value1 = option->readBoolean(1));
  989. EXPECT_TRUE(value1);
  990. ASSERT_NO_THROW(value2 = option->readFqdn(2));
  991. EXPECT_EQ("example.com.", value2);
  992. ASSERT_NO_THROW(value3 = option->readAddress(3));
  993. EXPECT_EQ("192.168.0.1", value3.toText());
  994. ASSERT_NO_THROW(value4 = option->readAddress(4));
  995. EXPECT_EQ("2001:db8:1::100", value4.toText());
  996. ASSERT_NO_THROW(value5 = option->readString(5));
  997. EXPECT_EQ(value5, "hello world");
  998. }
  999. // The purpose of this test is to verify that pack function for
  1000. // DHCPv4 custom option works correctly.
  1001. TEST_F(OptionCustomTest, pack4) {
  1002. OptionDefinition opt_def("OPTION_FOO", 234, "record");
  1003. ASSERT_NO_THROW(opt_def.addRecordField("uint8"));
  1004. ASSERT_NO_THROW(opt_def.addRecordField("uint16"));
  1005. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  1006. OptionBuffer buf;
  1007. writeInt<uint8_t>(1, buf);
  1008. writeInt<uint16_t>(1000, buf);
  1009. writeInt<uint32_t>(100000, buf);
  1010. boost::scoped_ptr<OptionCustom> option;
  1011. ASSERT_NO_THROW(
  1012. option.reset(new OptionCustom(opt_def, Option::V4, buf));
  1013. );
  1014. ASSERT_TRUE(option);
  1015. util::OutputBuffer buf_out(7);
  1016. ASSERT_NO_THROW(option->pack(buf_out));
  1017. ASSERT_EQ(9, buf_out.getLength());
  1018. // The original buffer holds the option data but it lacks a header.
  1019. // We append data length and option code so as it can be directly
  1020. // compared with the output buffer that holds whole option.
  1021. buf.insert(buf.begin(), 7);
  1022. buf.insert(buf.begin(), 234);
  1023. // Validate the buffer.
  1024. EXPECT_EQ(0, memcmp(&buf[0], buf_out.getData(), 7));
  1025. }
  1026. // The purpose of this test is to verify that pack function for
  1027. // DHCPv6 custom option works correctly.
  1028. TEST_F(OptionCustomTest, pack6) {
  1029. OptionDefinition opt_def("OPTION_FOO", 1000, "record");
  1030. ASSERT_NO_THROW(opt_def.addRecordField("boolean"));
  1031. ASSERT_NO_THROW(opt_def.addRecordField("uint16"));
  1032. ASSERT_NO_THROW(opt_def.addRecordField("string"));
  1033. OptionBuffer buf;
  1034. buf.push_back(1);
  1035. writeInt<uint16_t>(1000, buf);
  1036. writeString("hello world", buf);
  1037. boost::scoped_ptr<OptionCustom> option;
  1038. ASSERT_NO_THROW(
  1039. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  1040. );
  1041. ASSERT_TRUE(option);
  1042. util::OutputBuffer buf_out(buf.size() + option->getHeaderLen());
  1043. ASSERT_NO_THROW(option->pack(buf_out));
  1044. ASSERT_EQ(buf.size() + option->getHeaderLen(), buf_out.getLength());
  1045. // The original buffer holds the option data but it lacks a header.
  1046. // We append data length and option code so as it can be directly
  1047. // compared with the output buffer that holds whole option.
  1048. OptionBuffer tmp;
  1049. writeInt<uint16_t>(1000, tmp);
  1050. writeInt<uint16_t>(buf.size(), tmp);
  1051. buf.insert(buf.begin(), tmp.begin(), tmp.end());
  1052. // Validate the buffer.
  1053. EXPECT_EQ(0, memcmp(&buf[0], buf_out.getData(), 7));
  1054. }
  1055. // The purpose of this test is to verify that unpack function works
  1056. // correctly for a custom option.
  1057. TEST_F(OptionCustomTest, unpack) {
  1058. OptionDefinition opt_def("OPTION_FOO", 231, "ipv4-address", true);
  1059. // Initialize reference data.
  1060. std::vector<IOAddress> addresses;
  1061. addresses.push_back(IOAddress("192.168.0.1"));
  1062. addresses.push_back(IOAddress("127.0.0.1"));
  1063. addresses.push_back(IOAddress("10.10.1.2"));
  1064. // Store the collection of IPv4 addresses into the buffer.
  1065. OptionBuffer buf;
  1066. for (int i = 0; i < addresses.size(); ++i) {
  1067. writeAddress(addresses[i], buf);
  1068. }
  1069. // Use the input buffer to create custom option.
  1070. boost::scoped_ptr<OptionCustom> option;
  1071. ASSERT_NO_THROW(
  1072. option.reset(new OptionCustom(opt_def, Option::V4, buf.begin(), buf.end()));
  1073. );
  1074. ASSERT_TRUE(option);
  1075. // We should have 3 data fields.
  1076. ASSERT_EQ(3, option->getDataFieldsNum());
  1077. // We expect 3 IPv4 addresses being stored in the option.
  1078. for (int i = 0; i < 3; ++i) {
  1079. IOAddress address("10.10.10.10");
  1080. ASSERT_NO_THROW(address = option->readAddress(i));
  1081. EXPECT_EQ(addresses[i].toText(), address.toText());
  1082. }
  1083. // Remove all addresses we had added. We are going to replace
  1084. // them with a new set of addresses.
  1085. addresses.clear();
  1086. // Add new addresses.
  1087. addresses.push_back(IOAddress("10.1.2.3"));
  1088. addresses.push_back(IOAddress("85.26.43.234"));
  1089. // Clear the buffer as we need to store new addresses in it.
  1090. buf.clear();
  1091. for (int i = 0; i < addresses.size(); ++i) {
  1092. writeAddress(addresses[i], buf);
  1093. }
  1094. // Perform 'unpack'.
  1095. ASSERT_NO_THROW(option->unpack(buf.begin(), buf.end()));
  1096. // Now we should have only 2 data fields.
  1097. ASSERT_EQ(2, option->getDataFieldsNum());
  1098. // Verify that the addresses have been overwritten.
  1099. for (int i = 0; i < 2; ++i) {
  1100. IOAddress address("10.10.10.10");
  1101. ASSERT_NO_THROW(address = option->readAddress(i));
  1102. EXPECT_EQ(addresses[i].toText(), address.toText());
  1103. }
  1104. }
  1105. // The purpose of this test is to verify that new data can be set for
  1106. // a custom option.
  1107. TEST_F(OptionCustomTest, setData) {
  1108. OptionDefinition opt_def("OPTION_FOO", 1000, "ipv6-address", true);
  1109. // Initialize reference data.
  1110. std::vector<IOAddress> addresses;
  1111. addresses.push_back(IOAddress("2001:db8:1::3"));
  1112. addresses.push_back(IOAddress("::1"));
  1113. addresses.push_back(IOAddress("fe80::3"));
  1114. // Store the collection of IPv6 addresses into the buffer.
  1115. OptionBuffer buf;
  1116. for (int i = 0; i < addresses.size(); ++i) {
  1117. writeAddress(addresses[i], buf);
  1118. }
  1119. // Use the input buffer to create custom option.
  1120. boost::scoped_ptr<OptionCustom> option;
  1121. ASSERT_NO_THROW(
  1122. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.end()));
  1123. );
  1124. ASSERT_TRUE(option);
  1125. // We should have 3 data fields.
  1126. ASSERT_EQ(3, option->getDataFieldsNum());
  1127. // We expect 3 IPv6 addresses being stored in the option.
  1128. for (int i = 0; i < 3; ++i) {
  1129. IOAddress address("fe80::4");
  1130. ASSERT_NO_THROW(address = option->readAddress(i));
  1131. EXPECT_EQ(addresses[i].toText(), address.toText());
  1132. }
  1133. // Clear addresses we had previously added.
  1134. addresses.clear();
  1135. // Store new addresses.
  1136. addresses.push_back(IOAddress("::1"));
  1137. addresses.push_back(IOAddress("fe80::10"));
  1138. // Clear the buffer as we need to store new addresses in it.
  1139. buf.clear();
  1140. for (int i = 0; i < addresses.size(); ++i) {
  1141. writeAddress(addresses[i], buf);
  1142. }
  1143. // Replace the option data.
  1144. ASSERT_NO_THROW(option->setData(buf.begin(), buf.end()));
  1145. // Now we should have only 2 data fields.
  1146. ASSERT_EQ(2, option->getDataFieldsNum());
  1147. // Check that it has been replaced.
  1148. for (int i = 0; i < 2; ++i) {
  1149. IOAddress address("10.10.10.10");
  1150. ASSERT_NO_THROW(address = option->readAddress(i));
  1151. EXPECT_EQ(addresses[i].toText(), address.toText());
  1152. }
  1153. }
  1154. // The purpose of this test is to verify that an invalid index
  1155. // value can't be used to access option data fields.
  1156. TEST_F(OptionCustomTest, invalidIndex) {
  1157. OptionDefinition opt_def("OPTION_FOO", 999, "uint32", true);
  1158. OptionBuffer buf;
  1159. for (int i = 0; i < 10; ++i) {
  1160. writeInt<uint32_t>(i, buf);
  1161. }
  1162. // Use the input buffer to create custom option.
  1163. boost::scoped_ptr<OptionCustom> option;
  1164. ASSERT_NO_THROW(
  1165. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  1166. );
  1167. ASSERT_TRUE(option);
  1168. // We expect that there are 10 uint32_t values stored in
  1169. // the option. The 10th element is accessed by index eq 9.
  1170. // Check that 9 is accepted.
  1171. EXPECT_NO_THROW(option->readInteger<uint32_t>(9));
  1172. // Check that index value beyond 9 is not accepted.
  1173. EXPECT_THROW(option->readInteger<uint32_t>(10), isc::OutOfRange);
  1174. EXPECT_THROW(option->readInteger<uint32_t>(11), isc::OutOfRange);
  1175. }
  1176. } // anonymous namespace