duid.cc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // Copyright (C) 2012-2014 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 <dhcp/duid.h>
  15. #include <exceptions/exceptions.h>
  16. #include <util/encode/hex.h>
  17. #include <util/io_utilities.h>
  18. #include <boost/algorithm/string/classification.hpp>
  19. #include <boost/algorithm/string/constants.hpp>
  20. #include <boost/algorithm/string/split.hpp>
  21. #include <iomanip>
  22. #include <sstream>
  23. #include <vector>
  24. #include <stdint.h>
  25. namespace isc {
  26. namespace dhcp {
  27. DUID::DUID(const std::vector<uint8_t>& duid) {
  28. if (duid.size() > MAX_DUID_LEN) {
  29. isc_throw(OutOfRange, "DUID too large");
  30. }
  31. if (duid.empty()) {
  32. isc_throw(OutOfRange, "Empty DUIDs are not allowed");
  33. }
  34. duid_ = duid;
  35. }
  36. DUID::DUID(const uint8_t* data, size_t len) {
  37. if (len > MAX_DUID_LEN) {
  38. isc_throw(OutOfRange, "DUID too large");
  39. }
  40. if (len == 0) {
  41. isc_throw(OutOfRange, "Empty DUIDs/Client-ids not allowed");
  42. }
  43. duid_ = std::vector<uint8_t>(data, data + len);
  44. }
  45. const std::vector<uint8_t>& DUID::getDuid() const {
  46. return (duid_);
  47. }
  48. DUID::DUIDType DUID::getType() const {
  49. if (duid_.size() < 2) {
  50. return (DUID_UNKNOWN);
  51. }
  52. uint16_t type = (duid_[0] << 8) + duid_[1];
  53. if (type < DUID_MAX) {
  54. return (static_cast<DUID::DUIDType>(type));
  55. } else {
  56. return (DUID_UNKNOWN);
  57. }
  58. }
  59. DUID
  60. DUID::fromText(const std::string& text) {
  61. /// @todo optimize stream operations here.
  62. std::vector<std::string> split_text;
  63. boost::split(split_text, text, boost::is_any_of(":"),
  64. boost::algorithm::token_compress_on);
  65. std::ostringstream s;
  66. for (size_t i = 0; i < split_text.size(); ++i) {
  67. if (split_text[i].size() == 1) {
  68. s << "0";
  69. } else if (split_text[i].size() > 2) {
  70. isc_throw(isc::BadValue, "invalid DUID '" << text << "'");
  71. }
  72. s << split_text[i];
  73. }
  74. if (s.str().empty()) {
  75. isc_throw(isc::BadValue, "empty DUID is not allowed");
  76. }
  77. std::vector<uint8_t> binary;
  78. try {
  79. util::encode::decodeHex(s.str(), binary);
  80. } catch (const Exception& ex) {
  81. isc_throw(isc::BadValue, "failed to create DUID from text '"
  82. << text << "': " << ex.what());
  83. }
  84. return DUID(&binary[0], binary.size());
  85. }
  86. std::string DUID::toText() const {
  87. std::stringstream tmp;
  88. tmp << std::hex;
  89. bool delim = false;
  90. for (std::vector<uint8_t>::const_iterator it = duid_.begin();
  91. it != duid_.end(); ++it) {
  92. if (delim) {
  93. tmp << ":";
  94. }
  95. tmp << std::setw(2) << std::setfill('0') << static_cast<unsigned int>(*it);
  96. delim = true;
  97. }
  98. return (tmp.str());
  99. }
  100. bool DUID::operator==(const DUID& other) const {
  101. return (this->duid_ == other.duid_);
  102. }
  103. bool DUID::operator!=(const DUID& other) const {
  104. return (this->duid_ != other.duid_);
  105. }
  106. // Constructor based on vector<uint8_t>
  107. ClientId::ClientId(const std::vector<uint8_t>& clientid)
  108. : DUID(clientid) {
  109. if (clientid.size() < MIN_CLIENT_ID_LEN) {
  110. isc_throw(OutOfRange, "client-id is too short (" << clientid.size()
  111. << "), at least 2 is required");
  112. }
  113. }
  114. // Constructor based on C-style data
  115. ClientId::ClientId(const uint8_t *clientid, size_t len)
  116. : DUID(clientid, len) {
  117. if (len < MIN_CLIENT_ID_LEN) {
  118. isc_throw(OutOfRange, "client-id is too short (" << len
  119. << "), at least 2 is required");
  120. }
  121. }
  122. // Returns a copy of client-id data
  123. const std::vector<uint8_t>& ClientId::getClientId() const {
  124. return (duid_);
  125. }
  126. // Returns the Client ID in text form
  127. std::string ClientId::toText() const {
  128. // As DUID is a private base class of ClientId, we can't access
  129. // its public toText() method through inheritance: instead we
  130. // need the interface of a ClientId::toText() that calls the
  131. // equivalent method in the base class.
  132. return (DUID::toText());
  133. }
  134. // Compares two client-ids
  135. bool ClientId::operator==(const ClientId& other) const {
  136. return (this->duid_ == other.duid_);
  137. }
  138. // Compares two client-ids
  139. bool ClientId::operator!=(const ClientId& other) const {
  140. return (this->duid_ != other.duid_);
  141. }
  142. }; // end of isc::dhcp namespace
  143. }; // end of isc namespace