Commit c8710633 authored by chenzhengzhang's avatar chenzhengzhang
Browse files

[trac1128] Add more comments, avoid including useless header, and some

minor fixes.
parent d42d232a
......@@ -13,9 +13,7 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <boost/lexical_cast.hpp>
......@@ -46,30 +44,95 @@ struct SRVImpl {
Name target_;
};
namespace {
string
getToken(istringstream& iss, const string& full_input) {
string token;
iss >> token;
if (iss.bad() || iss.fail()) {
isc_throw(InvalidRdataText, "Invalid SRV text: parse error " <<
full_input);
}
return (token);
}
// This helper function converts a string token to an *unsigned* integer.
// NumType is a *signed* integral type (e.g. int32_t) that is sufficiently
// wide to store resulting integers.
template <typename NumType, int BitSize>
NumType
tokenToNum(const string& num_token) {
NumType num;
try {
num = lexical_cast<NumType>(num_token);
} catch (const boost::bad_lexical_cast& ex) {
isc_throw(InvalidRdataText, "Invalid SRV numeric parameter: " <<
num_token);
}
if (num < 0 || num >= (static_cast<NumType>(1) << BitSize)) {
isc_throw(InvalidRdataText, "Numeric SRV parameter out of range: " <<
num);
}
return (num);
}
}
/// \brief Constructor from string.
///
/// \c srv_str must be formatted as follows:
/// \code <Priority> <Weight> <Port> <Target>
/// \endcode
/// where
/// - <Priority>, <Weight>, and <Port> are an unsigned 16-bit decimal
/// integer.
/// - <Target> is a valid textual representation of domain name.
///
/// An example of valid string is:
/// \code "1 5 1500 example.com." \endcode
///
/// <b>Exceptions</b>
///
/// If <Target> is not a valid domain name, a corresponding exception from
/// the \c Name class will be thrown;
/// if %any of the other bullet points above is not met, an exception of
/// class \c InvalidRdataText will be thrown.
/// This constructor internally involves resource allocation, and if it fails
/// a corresponding standard exception will be thrown.
SRV::SRV(const string& srv_str) :
impl_(NULL)
{
istringstream iss(srv_str);
string targetname;
unsigned int priority, weight, port;
iss >> priority >> weight >> port >> targetname;
if (iss.bad() || iss.fail()) {
isc_throw(InvalidRdataText, "Invalid SRV text");
}
if (priority > 0xffff) {
isc_throw(InvalidRdataText, "SRV priority out of range");
}
if (weight > 0xffff) {
isc_throw(InvalidRdataText, "SRV weight out of range");
}
if (port > 0xffff) {
isc_throw(InvalidRdataText, "SRV port out of range");
const int32_t priority = tokenToNum<int32_t, 16>(getToken(iss, srv_str));
const int32_t weight = tokenToNum<int32_t, 16>(getToken(iss, srv_str));
const int32_t port = tokenToNum<int32_t, 16>(getToken(iss, srv_str));
const Name targetname(getToken(iss, srv_str));
if (!iss.eof()) {
isc_throw(InvalidRdataText, "Unexpected input for SRV RDATA: " <<
srv_str);
}
impl_ = new SRVImpl(priority, weight, port, Name(targetname));
impl_ = new SRVImpl(priority, weight, port, targetname);
}
/// \brief Constructor from wire-format data.
///
/// When a read operation on \c buffer fails (e.g., due to a corrupted
/// message) a corresponding exception from the \c InputBuffer class will
/// be thrown.
/// If the wire-format data does not begin with a valid domain name,
/// a corresponding exception from the \c Name class will be thrown.
/// In addition, this constructor internally involves resource allocation,
/// and if it fails a corresponding standard exception will be thrown.
///
/// According to RFC2782, the Target field must be a non compressed form
/// of domain name. But this implementation accepts a %SRV RR even if that
/// field is compressed.
///
/// \param buffer A buffer storing the wire format data.
/// \param rdata_len The length of the RDATA in bytes, normally expected
/// to be the value of the RDLENGTH field of the corresponding RR.
SRV::SRV(InputBuffer& buffer, size_t rdata_len) {
if (rdata_len < 6) {
isc_throw(InvalidRdataLength, "SRV too short");
......@@ -83,6 +146,11 @@ SRV::SRV(InputBuffer& buffer, size_t rdata_len) {
impl_ = new SRVImpl(priority, weight, port, targetname);
}
/// \brief The copy constructor.
///
/// It internally allocates a resource, and if it fails a corresponding
/// standard exception will be thrown.
/// This constructor never throws an exception otherwise.
SRV::SRV(const SRV& source) :
Rdata(), impl_(new SRVImpl(*source.impl_))
{}
......@@ -104,15 +172,31 @@ SRV::~SRV() {
delete impl_;
}
/// \brief Convert the \c SRV to a string.
///
/// The output of this method is formatted as described in the "from string"
/// constructor (\c SRV(const std::string&))).
///
/// If internal resource allocation fails, a corresponding
/// standard exception will be thrown.
///
/// \return A \c string object that represents the \c SRV object.
string
SRV::toText() const {
using namespace boost;
return (lexical_cast<string>(static_cast<int>(impl_->priority_)) +
" " + lexical_cast<string>(static_cast<int>(impl_->weight_)) +
" " + lexical_cast<string>(static_cast<int>(impl_->port_)) +
return (lexical_cast<string>(impl_->priority_) +
" " + lexical_cast<string>(impl_->weight_) +
" " + lexical_cast<string>(impl_->port_) +
" " + impl_->target_.toText());
}
/// \brief Render the \c SRV in the wire format without name compression.
///
/// If internal resource allocation fails, a corresponding
/// standard exception will be thrown.
/// This method never throws an exception otherwise.
///
/// \param buffer An output buffer to store the wire data.
void
SRV::toWire(OutputBuffer& buffer) const {
buffer.writeUint16(impl_->priority_);
......@@ -121,16 +205,31 @@ SRV::toWire(OutputBuffer& buffer) const {
impl_->target_.toWire(buffer);
}
/// \brief Render the \c SRV in the wire format with taking into account
/// compression.
///
/// As specified in RFC2782, the Target field (a domain name) will not be
/// compressed. However, the domain name could be a target of compression
/// of other compressible names (though pretty unlikely), the offset
/// information of the algorithm name may be recorded in \c renderer.
///
/// If internal resource allocation fails, a corresponding
/// standard exception will be thrown.
/// This method never throws an exception otherwise.
///
/// \param renderer DNS message rendering context that encapsulates the
/// output buffer and name compression information.
void
SRV::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeUint16(impl_->priority_);
renderer.writeUint16(impl_->weight_);
renderer.writeUint16(impl_->port_);
// According to RFC 2782, name compression is not
// to be used for this field.
renderer.writeName(impl_->target_, false);
}
/// \brief Compare two instances of \c SRV RDATA.
///
/// See documentation in \c Rdata.
int
SRV::compare(const Rdata& other) const {
const SRV& other_srv = dynamic_cast<const SRV&>(other);
......
......@@ -14,11 +14,7 @@
#include <stdint.h>
#include <string>
#include <dns/name.h>
#include <dns/rrtype.h>
#include <dns/rrttl.h>
#include <dns/rdata.h>
// BEGIN_HEADER_GUARD
......@@ -30,21 +26,59 @@
// BEGIN_RDATA_NAMESPACE
/// \brief \c rdata::SRV class represents the SRV RDATA as defined %in
/// RFC2782.
///
/// This class implements the basic interfaces inherited from the abstract
/// \c rdata::Rdata class, and provides trivial accessors specific to the
/// SRV RDATA.
struct SRVImpl;
class SRV : public Rdata {
public:
// BEGIN_COMMON_MEMBERS
// END_COMMON_MEMBERS
/// \brief Assignment operator.
///
/// It internally allocates a resource, and if it fails a corresponding
/// standard exception will be thrown.
/// This operator never throws an exception otherwise.
///
/// This operator provides the strong exception guarantee: When an
/// exception is thrown the content of the assignment target will be
/// intact.
SRV& operator=(const SRV& source);
/// \brief The destructor.
~SRV();
///
/// Specialized methods
///
/// \brief Return the value of the priority field.
///
/// This method never throws an exception.
uint16_t getPriority() const;
/// \brief Return the value of the weight field.
///
/// This method never throws an exception.
uint16_t getWeight() const;
/// \brief Return the value of the port field.
///
/// This method never throws an exception.
uint16_t getPort() const;
/// \brief Return the value of the target field.
///
/// \return A reference to a \c Name class object corresponding to the
/// internal target name.
///
/// This method never throws an exception.
const Name& getTarget() const;
private:
......
......@@ -50,8 +50,8 @@ const uint8_t wiredata_srv2[] = {
0x00, 0x01, 0x00, 0x05, 0x05, 0x78, 0x07, 0x65, 0x78, 0x61, 0x6d,
0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00};
const generic::SRV rdata_srv(srv_txt);
const generic::SRV rdata_srv2(srv_txt2);
const in::SRV rdata_srv(srv_txt);
const in::SRV rdata_srv2(srv_txt2);
TEST_F(Rdata_SRV_Test, createFromText) {
EXPECT_EQ(1, rdata_srv.getPriority());
......@@ -62,30 +62,32 @@ TEST_F(Rdata_SRV_Test, createFromText) {
TEST_F(Rdata_SRV_Test, badText) {
// priority is too large (2814...6 is 2^48)
EXPECT_THROW(generic::SRV("281474976710656 5 1500 a.example.com."),
EXPECT_THROW(in::SRV("281474976710656 5 1500 a.example.com."),
InvalidRdataText);
// weight is too large
EXPECT_THROW(generic::SRV("1 281474976710656 1500 a.example.com."),
EXPECT_THROW(in::SRV("1 281474976710656 1500 a.example.com."),
InvalidRdataText);
// port is too large
EXPECT_THROW(generic::SRV("1 5 281474976710656 a.example.com."),
EXPECT_THROW(in::SRV("1 5 281474976710656 a.example.com."),
InvalidRdataText);
// incomplete text
EXPECT_THROW(generic::SRV("1 5 a.example.com."),
EXPECT_THROW(in::SRV("1 5 a.example.com."),
InvalidRdataText);
EXPECT_THROW(in::SRV("1 5 1500a.example.com."),
InvalidRdataText);
// bad name
EXPECT_THROW(generic::SRV("1 5 1500 a.example.com." + too_long_label),
EXPECT_THROW(in::SRV("1 5 1500 a.example.com." + too_long_label),
TooLongLabel);
}
TEST_F(Rdata_SRV_Test, assignment) {
generic::SRV copy((string(srv_txt2)));
in::SRV copy((string(srv_txt2)));
copy = rdata_srv;
EXPECT_EQ(0, copy.compare(rdata_srv));
// Check if the copied data is valid even after the original is deleted
generic::SRV* copy2 = new generic::SRV(rdata_srv);
generic::SRV copy3((string(srv_txt2)));
in::SRV* copy2 = new in::SRV(rdata_srv);
in::SRV copy3((string(srv_txt2)));
copy3 = *copy2;
delete copy2;
EXPECT_EQ(0, copy3.compare(rdata_srv));
......@@ -148,18 +150,18 @@ TEST_F(Rdata_SRV_Test, toText) {
TEST_F(Rdata_SRV_Test, compare) {
// test RDATAs, sorted in the ascendent order.
vector<generic::SRV> compare_set;
compare_set.push_back(generic::SRV("1 5 1500 a.example.com."));
compare_set.push_back(generic::SRV("2 5 1500 a.example.com."));
compare_set.push_back(generic::SRV("2 6 1500 a.example.com."));
compare_set.push_back(generic::SRV("2 6 1600 a.example.com."));
compare_set.push_back(generic::SRV("2 6 1600 example.com."));
vector<in::SRV> compare_set;
compare_set.push_back(in::SRV("1 5 1500 a.example.com."));
compare_set.push_back(in::SRV("2 5 1500 a.example.com."));
compare_set.push_back(in::SRV("2 6 1500 a.example.com."));
compare_set.push_back(in::SRV("2 6 1600 a.example.com."));
compare_set.push_back(in::SRV("2 6 1600 example.com."));
EXPECT_EQ(0, compare_set[0].compare(
generic::SRV("1 5 1500 a.example.com.")));
in::SRV("1 5 1500 a.example.com.")));
vector<generic::SRV>::const_iterator it;
vector<generic::SRV>::const_iterator it_end = compare_set.end();
vector<in::SRV>::const_iterator it;
vector<in::SRV>::const_iterator it_end = compare_set.end();
for (it = compare_set.begin(); it != it_end - 1; ++it) {
EXPECT_GT(0, (*it).compare(*(it + 1)));
EXPECT_LT(0, (*(it + 1)).compare(*it));
......
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