srv_33.cc 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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 <iostream>
  15. #include <sstream>
  16. #include <boost/lexical_cast.hpp>
  17. #include <util/buffer.h>
  18. #include <dns/messagerenderer.h>
  19. #include <dns/name.h>
  20. #include <dns/rdata.h>
  21. #include <dns/rdataclass.h>
  22. using namespace std;
  23. using namespace isc::util;
  24. // BEGIN_ISC_NAMESPACE
  25. // BEGIN_RDATA_NAMESPACE
  26. struct SRVImpl {
  27. // straightforward representation of SRV RDATA fields
  28. SRVImpl(uint16_t priority, uint16_t weight, uint16_t port,
  29. const Name& target) :
  30. priority_(priority), weight_(weight), port_(port),
  31. target_(target)
  32. {}
  33. uint16_t priority_;
  34. uint16_t weight_;
  35. uint16_t port_;
  36. Name target_;
  37. };
  38. namespace {
  39. string
  40. getToken(istringstream& iss, const string& full_input) {
  41. string token;
  42. iss >> token;
  43. if (iss.bad() || iss.fail()) {
  44. isc_throw(InvalidRdataText, "Invalid SRV text: parse error " <<
  45. full_input);
  46. }
  47. return (token);
  48. }
  49. // This helper function converts a string token to an *unsigned* integer.
  50. // NumType is a *signed* integral type (e.g. int32_t) that is sufficiently
  51. // wide to store resulting integers.
  52. template <typename NumType, int BitSize>
  53. NumType
  54. tokenToNum(const string& num_token) {
  55. NumType num;
  56. try {
  57. num = lexical_cast<NumType>(num_token);
  58. } catch (const boost::bad_lexical_cast& ex) {
  59. isc_throw(InvalidRdataText, "Invalid SRV numeric parameter: " <<
  60. num_token);
  61. }
  62. if (num < 0 || num >= (static_cast<NumType>(1) << BitSize)) {
  63. isc_throw(InvalidRdataText, "Numeric SRV parameter out of range: " <<
  64. num);
  65. }
  66. return (num);
  67. }
  68. }
  69. /// \brief Constructor from string.
  70. ///
  71. /// \c srv_str must be formatted as follows:
  72. /// \code <Priority> <Weight> <Port> <Target>
  73. /// \endcode
  74. /// where
  75. /// - <Priority>, <Weight>, and <Port> are an unsigned 16-bit decimal
  76. /// integer.
  77. /// - <Target> is a valid textual representation of domain name.
  78. ///
  79. /// An example of valid string is:
  80. /// \code "1 5 1500 example.com." \endcode
  81. ///
  82. /// <b>Exceptions</b>
  83. ///
  84. /// If <Target> is not a valid domain name, a corresponding exception from
  85. /// the \c Name class will be thrown;
  86. /// if %any of the other bullet points above is not met, an exception of
  87. /// class \c InvalidRdataText will be thrown.
  88. /// This constructor internally involves resource allocation, and if it fails
  89. /// a corresponding standard exception will be thrown.
  90. SRV::SRV(const string& srv_str) :
  91. impl_(NULL)
  92. {
  93. istringstream iss(srv_str);
  94. const int32_t priority = tokenToNum<int32_t, 16>(getToken(iss, srv_str));
  95. const int32_t weight = tokenToNum<int32_t, 16>(getToken(iss, srv_str));
  96. const int32_t port = tokenToNum<int32_t, 16>(getToken(iss, srv_str));
  97. const Name targetname(getToken(iss, srv_str));
  98. if (!iss.eof()) {
  99. isc_throw(InvalidRdataText, "Unexpected input for SRV RDATA: " <<
  100. srv_str);
  101. }
  102. impl_ = new SRVImpl(priority, weight, port, targetname);
  103. }
  104. /// \brief Constructor from wire-format data.
  105. ///
  106. /// When a read operation on \c buffer fails (e.g., due to a corrupted
  107. /// message) a corresponding exception from the \c InputBuffer class will
  108. /// be thrown.
  109. /// If the wire-format data does not begin with a valid domain name,
  110. /// a corresponding exception from the \c Name class will be thrown.
  111. /// In addition, this constructor internally involves resource allocation,
  112. /// and if it fails a corresponding standard exception will be thrown.
  113. ///
  114. /// According to RFC2782, the Target field must be a non compressed form
  115. /// of domain name. But this implementation accepts a %SRV RR even if that
  116. /// field is compressed.
  117. ///
  118. /// \param buffer A buffer storing the wire format data.
  119. /// \param rdata_len The length of the RDATA in bytes, normally expected
  120. /// to be the value of the RDLENGTH field of the corresponding RR.
  121. SRV::SRV(InputBuffer& buffer, size_t rdata_len) {
  122. if (rdata_len < 6) {
  123. isc_throw(InvalidRdataLength, "SRV too short");
  124. }
  125. uint16_t priority = buffer.readUint16();
  126. uint16_t weight = buffer.readUint16();
  127. uint16_t port = buffer.readUint16();
  128. const Name targetname(buffer);
  129. impl_ = new SRVImpl(priority, weight, port, targetname);
  130. }
  131. /// \brief The copy constructor.
  132. ///
  133. /// It internally allocates a resource, and if it fails a corresponding
  134. /// standard exception will be thrown.
  135. /// This constructor never throws an exception otherwise.
  136. SRV::SRV(const SRV& source) :
  137. Rdata(), impl_(new SRVImpl(*source.impl_))
  138. {}
  139. SRV&
  140. SRV::operator=(const SRV& source) {
  141. if (impl_ == source.impl_) {
  142. return (*this);
  143. }
  144. SRVImpl* newimpl = new SRVImpl(*source.impl_);
  145. delete impl_;
  146. impl_ = newimpl;
  147. return (*this);
  148. }
  149. SRV::~SRV() {
  150. delete impl_;
  151. }
  152. /// \brief Convert the \c SRV to a string.
  153. ///
  154. /// The output of this method is formatted as described in the "from string"
  155. /// constructor (\c SRV(const std::string&))).
  156. ///
  157. /// If internal resource allocation fails, a corresponding
  158. /// standard exception will be thrown.
  159. ///
  160. /// \return A \c string object that represents the \c SRV object.
  161. string
  162. SRV::toText() const {
  163. using namespace boost;
  164. return (lexical_cast<string>(impl_->priority_) +
  165. " " + lexical_cast<string>(impl_->weight_) +
  166. " " + lexical_cast<string>(impl_->port_) +
  167. " " + impl_->target_.toText());
  168. }
  169. /// \brief Render the \c SRV in the wire format without name compression.
  170. ///
  171. /// If internal resource allocation fails, a corresponding
  172. /// standard exception will be thrown.
  173. /// This method never throws an exception otherwise.
  174. ///
  175. /// \param buffer An output buffer to store the wire data.
  176. void
  177. SRV::toWire(OutputBuffer& buffer) const {
  178. buffer.writeUint16(impl_->priority_);
  179. buffer.writeUint16(impl_->weight_);
  180. buffer.writeUint16(impl_->port_);
  181. impl_->target_.toWire(buffer);
  182. }
  183. /// \brief Render the \c SRV in the wire format with taking into account
  184. /// compression.
  185. ///
  186. /// As specified in RFC2782, the Target field (a domain name) will not be
  187. /// compressed. However, the domain name could be a target of compression
  188. /// of other compressible names (though pretty unlikely), the offset
  189. /// information of the algorithm name may be recorded in \c renderer.
  190. ///
  191. /// If internal resource allocation fails, a corresponding
  192. /// standard exception will be thrown.
  193. /// This method never throws an exception otherwise.
  194. ///
  195. /// \param renderer DNS message rendering context that encapsulates the
  196. /// output buffer and name compression information.
  197. void
  198. SRV::toWire(AbstractMessageRenderer& renderer) const {
  199. renderer.writeUint16(impl_->priority_);
  200. renderer.writeUint16(impl_->weight_);
  201. renderer.writeUint16(impl_->port_);
  202. renderer.writeName(impl_->target_, false);
  203. }
  204. /// \brief Compare two instances of \c SRV RDATA.
  205. ///
  206. /// See documentation in \c Rdata.
  207. int
  208. SRV::compare(const Rdata& other) const {
  209. const SRV& other_srv = dynamic_cast<const SRV&>(other);
  210. if (impl_->priority_ != other_srv.impl_->priority_) {
  211. return (impl_->priority_ < other_srv.impl_->priority_ ? -1 : 1);
  212. }
  213. if (impl_->weight_ != other_srv.impl_->weight_) {
  214. return (impl_->weight_ < other_srv.impl_->weight_ ? -1 : 1);
  215. }
  216. if (impl_->port_ != other_srv.impl_->port_) {
  217. return (impl_->port_ < other_srv.impl_->port_ ? -1 : 1);
  218. }
  219. return (compareNames(impl_->target_, other_srv.impl_->target_));
  220. }
  221. uint16_t
  222. SRV::getPriority() const {
  223. return (impl_->priority_);
  224. }
  225. uint16_t
  226. SRV::getWeight() const {
  227. return (impl_->weight_);
  228. }
  229. uint16_t
  230. SRV::getPort() const {
  231. return (impl_->port_);
  232. }
  233. const Name&
  234. SRV::getTarget() const {
  235. return (impl_->target_);
  236. }
  237. // END_RDATA_NAMESPACE
  238. // END_ISC_NAMESPACE