diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 11:36:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 11:36:04 +0000 |
commit | 040eee1aa49b49df4698d83a05af57c220127fd1 (patch) | |
tree | f635435954e6ccde5eee9893889e24f30ca68346 /src/lib/dns/name.h | |
parent | Initial commit. (diff) | |
download | isc-kea-upstream.tar.xz isc-kea-upstream.zip |
Adding upstream version 2.2.0.upstream/2.2.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib/dns/name.h')
-rw-r--r-- | src/lib/dns/name.h | 766 |
1 files changed, 766 insertions, 0 deletions
diff --git a/src/lib/dns/name.h b/src/lib/dns/name.h new file mode 100644 index 0000000..0720684 --- /dev/null +++ b/src/lib/dns/name.h @@ -0,0 +1,766 @@ +// Copyright (C) 2009-2019 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef NAME_H +#define NAME_H 1 + +#include <stdint.h> + +#include <string> +#include <vector> + +#include <dns/exceptions.h> + +namespace isc { +namespace util { +class InputBuffer; +class OutputBuffer; +} + +namespace dns { +class AbstractMessageRenderer; + +/// +/// \brief A standard DNS module exception that is thrown if the name parser +/// encounters an empty label in the middle of a name. +/// +class EmptyLabel : public NameParserException { +public: + EmptyLabel(const char* file, size_t line, const char* what) : + NameParserException(file, line, what) {} +}; + +/// +/// \brief A standard DNS module exception that is thrown if the name parser +/// encounters too long a name. +/// +class TooLongName : public NameParserException { +public: + TooLongName(const char* file, size_t line, const char* what) : + NameParserException(file, line, what) {} +}; + +/// +/// \brief A standard DNS module exception that is thrown if the name parser +/// encounters too long a label. +/// +class TooLongLabel : public NameParserException { +public: + TooLongLabel(const char* file, size_t line, const char* what) : + NameParserException(file, line, what) {} +}; + +/// +/// \brief A standard DNS module exception that is thrown if the name parser +/// encounters an obsolete or incomplete label type. In effect "obsolete" only +/// applies to bitstring labels, which would begin with "\[". Incomplete cases +/// include an incomplete escaped sequence such as "\12". +/// +class BadLabelType : public NameParserException { +public: + BadLabelType(const char* file, size_t line, const char* what) : + NameParserException(file, line, what) {} +}; + +/// +/// \brief A standard DNS module exception that is thrown if the name parser +/// fails to decode a back-slash escaped sequence. +/// +class BadEscape : public NameParserException { +public: + BadEscape(const char* file, size_t line, const char* what) : + NameParserException(file, line, what) {} +}; + +/// +/// \brief A standard DNS module exception that is thrown if the name parser +/// finds the input (string or wire-format %data) is incomplete. +/// +/// An attempt of constructing a name from an empty string will trigger this +/// exception. +/// +class IncompleteName : public NameParserException { +public: + IncompleteName(const char* file, size_t line, const char* what) : + NameParserException(file, line, what) {} +}; + +/// \brief Thrown when origin is NULL and is needed. +/// +/// The exception is thrown when the Name constructor for master file +/// is used, the provided data is relative and the origin parameter is +/// set to NULL. +class MissingNameOrigin : public NameParserException { +public: + MissingNameOrigin(const char* file, size_t line, const char* what) : + NameParserException(file, line, what) {} +}; + +/// +/// This is a supplemental class used only as a return value of +/// Name::compare() and LabelSequence::compare(). +/// It encapsulate a tuple of the comparison: ordering, number of common +/// labels, and relationship as follows: +/// - ordering: relative ordering under the DNSSEC order relation +/// - labels: the number of common significant labels of the two names or +/// two label sequences being compared +/// - relationship: see NameComparisonResult::NameRelation +/// +/// Note that the ordering is defined for two label sequences that have no +/// hierarchical relationship (in which case the relationship will be NONE). +/// For example, two non absolute (or "relative") sequences "example.com" and +/// "example.org" have no hierarchical relationship, and the former should be +/// sorted before (i.e. "smaller") than the latter. +class NameComparisonResult { +public: + /// The relation of two names under comparison. + /// Its semantics for the case of + /// <code>name1->compare(name2)</code> (where name1 and name2 are instances + /// of the \c Name or \c LabelSequence class) is as follows: + /// - SUPERDOMAIN: name1 properly contains name2; name2 is a proper + /// subdomain of name1 + /// - SUBDOMAIN: name1 is a proper subdomain of name2 + /// - EQUAL: name1 and name2 are equal + /// - COMMONANCESTOR: name1 and name2 share a common ancestor + /// - NONE: There's no hierarchical relationship between name1 and name2 + /// + /// Note that there's always a hierarchical relationship between any two + /// names since all names (not generic label sequences) are absolute and + /// they at least share the trailing empty label. + /// So, for example, the relationship between "com." and "net." is + /// "commonancestor". The relationship of "NONE" can only happen for + /// comparison between two label sequences (\c LabelSequence objects); + /// usually only SUPERDOMAIN, SUBDOMAIN or EQUAL are important relationship + /// between two names. + /// + /// When two \c LabelSequence objects are compared, it's generally expected + /// they are either both absolute or both non absolute; if one is absolute + /// and the other is not, the resulting relationship will be NONE. + enum NameRelation { + SUPERDOMAIN = 0, + SUBDOMAIN = 1, + EQUAL = 2, + COMMONANCESTOR = 3, + NONE = 4 + }; + + /// + /// \name Constructors and Destructor + /// + //@{ + /// \brief Constructor from a comparison tuple + /// + /// This constructor simply initializes the object in the straightforward + /// way. + NameComparisonResult(int order, unsigned int nlabels, + NameRelation relation) : + order_(order), nlabels_(nlabels), relation_(relation) {} + //@} + + /// + /// \name Getter Methods + /// + //@{ + /// Returns the ordering of the comparison result + int getOrder() const { return (order_); } + /// Returns the number of common labels of the comparison result + unsigned int getCommonLabels() const { return (nlabels_); } + /// Returns the NameRelation of the comparison result + NameRelation getRelation() const { return (relation_); } + //@} +private: + int order_; + unsigned int nlabels_; + NameRelation relation_; +}; + +/// +/// The \c Name class encapsulates DNS names. +/// +/// It provides interfaces to construct a name from string or wire-format %data, +/// transform a name into a string or wire-format %data, compare two names, get +/// access to various properties of a name, etc. +/// +/// Notes to developers: Internally, a name object maintains the name %data +/// in wire format as an instance of \c std::string. Since many string +/// implementations adopt copy-on-write %data sharing, we expect this approach +/// will make copying a name less expensive in typical cases. If this is +/// found to be a significant performance bottleneck later, we may reconsider +/// the internal representation or perhaps the API. +/// +/// A name object also maintains a vector of offsets (\c offsets_ member), +/// each of which is the offset to a label of the name: The n-th element of +/// the vector specifies the offset to the n-th label. For example, if the +/// object represents "www.example.com", the elements of the offsets vector +/// are 0, 4, 12, and 16. Note that the offset to the trailing dot (16) is +/// included. In the BIND9 DNS library from which this implementation is +/// derived, the offsets are optional, probably due to performance +/// considerations (in fact, offsets can always be calculated from the name +/// %data, and in that sense are redundant). In our implementation, however, +/// we always build and maintain the offsets. We believe we need more low +/// level, specialized %data structure and interface where we really need to +/// pursue performance, and would rather keep this generic API and +/// implementation simpler. +/// +/// While many other DNS APIs introduce an "absolute or relative" +/// attribute of names as defined in RFC1035, names are always "absolute" in +/// the initial design of this API. +/// In fact, separating absolute and relative would confuse API users +/// unnecessarily. For example, it's not so intuitive to consider the +/// comparison result of an absolute name with a relative name. +/// We've looked into how the concept of absolute names is used in BIND9, +/// and found that in many cases names are generally absolute. +/// The only reasonable case of separating absolute and relative is in a master +/// file parser, where a relative name must be a complete name with an "origin" +/// name, which must be absolute. So, in this initial design, we chose a +/// simpler approach: the API generally handles names as absolute; when we +/// introduce a parser of master files, we'll introduce the notion of relative +/// names as a special case. +/// +class Name { + // LabelSequences use knowledge about the internal data structure + // of this class for efficiency (they use the offsets_ vector and + // the ndata_ string) + friend class LabelSequence; + + /// + /// \name Constructors and Destructor + /// + //@{ +private: + /// \brief Name data string + typedef std::basic_string<uint8_t> NameString; + /// \brief Name offsets type + typedef std::vector<uint8_t> NameOffsets; + + /// The default constructor + /// + /// This is used internally in the class implementation, but at least at + /// the moment defined as private because it will construct an incomplete + /// object in that it doesn't have any labels. We may reconsider this + /// design choice as we see more applications of the class. + Name() : length_(0), labelcount_(0) {} +public: + /// Constructor from a string + /// + /// If the given string does not represent a valid DNS name, an exception + /// of class \c EmptyLabel, \c TooLongLabel, \c BadLabelType, \c BadEscape, + /// \c TooLongName, or \c IncompleteName will be thrown. + /// In addition, if resource allocation for the new name fails, a + /// corresponding standard exception will be thrown. + /// + /// \param namestr A string representation of the name to be constructed. + /// \param downcase Whether to convert upper case alphabets to lower case. + explicit Name(const std::string& namestr, bool downcase = false); + + /// \brief Constructor for master file parser + /// + /// This acts similar to the above. But the data is passed as raw C-string + /// instead of wrapped-up C++ std::string. + /// + /// Also, when the origin is non-NULL and the name_data is not ending with + /// a dot, it is considered relative and the origin is appended to it. + /// + /// If the name_data is equal to "@", the content of origin is copied. + /// + /// \param name_data The raw data of the name. + /// \param data_len How many bytes in name_data is valid and considered + /// part of the name. + /// \param origin If non-NULL, it is taken as the origin to complete + /// relative names. + /// \param downcase Whether to convert upper case letters to lower case. + /// \throw NameParserException or any of its descendants in case the + /// input data is invalid. + /// \throw isc::InvalidParameter In case name_data is NULL or data_len is + /// 0. + /// \throw std::bad_alloc In case allocation fails. + /// \note This constructor is specially designed for the use of master + /// file parser. It mimics the behaviour of names in the master file + /// and accepts raw data. It is not recommended to be used by anything + /// else. + /// \todo Should we make it private and the parser a friend, to hide the + /// constructor? + Name(const char* name_data, size_t data_len, const Name* origin, + bool downcase = false); + + /// Constructor from wire-format %data. + /// + /// The \c buffer parameter normally stores a complete DNS message + /// containing the name to be constructed. The current read position of + /// the buffer points to the head of the name. + /// + /// The input %data may or may not be compressed; if it's compressed, this + /// method will automatically decompress it. + /// + /// If the given %data does not represent a valid DNS name, an exception + /// of class \c DNSMessageFORMERR will be thrown. + /// In addition, if resource allocation for the new name fails, a + /// corresponding standard exception will be thrown. + /// + /// \param buffer A buffer storing the wire format %data. + /// \param downcase Whether to convert upper case alphabets to lower case. + explicit Name(isc::util::InputBuffer& buffer, bool downcase = false); + /// + /// We use the default copy constructor intentionally. + //@} + /// We use the default copy assignment operator intentionally. + /// + + /// + /// \name Getter Methods + /// + //@{ + /// \brief Provides one-byte name %data in wire format at the specified + /// position. + /// + /// This method returns the unsigned 8-bit value of wire-format \c Name + /// %data at the given position from the head. + /// + /// For example, if \c n is a \c Name object for "example.com", + /// \c n.at(3) would return \c 'a', and \c n.at(7) would return \c 'e'. + /// Note that \c n.at(0) would be 7 (decimal), the label length of + /// "example", instead of \c 'e', because it returns a %data portion + /// in wire-format. Likewise, \c n.at(8) would return 3 (decimal) + /// instead of <code>'.'</code> + /// + /// This method would be useful for an application to examine the + /// wire-format name %data without dumping the %data into a buffer, + /// which would involve %data copies and would be less efficient. + /// One common usage of this method would be something like this: + /// \code for (size_t i = 0; i < name.getLength(); ++i) { + /// uint8_t c = name.at(i); + /// // do something with c + /// } \endcode + /// + /// Parameter \c pos must be in the valid range of the name %data, that is, + /// must be less than \c Name.getLength(). Otherwise, an exception of + /// class \c OutOfRange will be thrown. + /// This method never throws an exception in other ways. + /// + /// \param pos The position in the wire format name %data to be returned. + /// \return An unsigned 8-bit integer corresponding to the name %data + /// at the position of \c pos. + uint8_t at(size_t pos) const + { + if (pos >= length_) { + isc_throw(OutOfRange, "Out of range access in Name::at()"); + } + return (ndata_[pos]); + } + + /// \brief Gets the length of the <code>Name</code> in its wire format. + /// + /// This method never throws an exception. + /// + /// \return the length (the number of octets in wire format) of the + /// <code>Name</code> + size_t getLength() const { return (length_); } + + /// \brief Returns the number of labels contained in the <code>Name</code>. + /// + /// Note that an empty label (corresponding to a trailing '.') is counted + /// as a single label, so the return value of this method must be >0. + /// + /// This method never throws an exception. + /// + /// \return the number of labels + unsigned int getLabelCount() const { return (labelcount_); } + //@} + + /// + /// \name Converter methods + /// + //@{ + /// \brief Convert the Name to a string. + /// + /// This method returns a <code>std::string</code> object representing the + /// Name as a string. Unless <code>omit_final_dot</code> is + /// <code>true</code>, the returned string ends with a dot '.'; the default + /// is <code>false</code>. The default value of this parameter is + /// <code>true</code>; converted names will have a trailing dot by default. + /// + /// This function assumes the name is in proper uncompressed wire format. + /// If it finds an unexpected label character including compression pointer, + /// an exception of class \c BadLabelType will be thrown. + /// In addition, if resource allocation for the result string fails, a + /// corresponding standard exception will be thrown. + // + /// \param omit_final_dot whether to omit the trailing dot in the output. + /// \return a string representation of the <code>Name</code>. + std::string toText(bool omit_final_dot = false) const; + + /// \brief Convert the LabelSequence to a string without escape sequences. + /// + /// The string returned will contain a single character value for any + /// escape sequences in the label(s). + /// + /// \param omit_final_dot whether to omit the trailing dot in the output. + /// \return a string representation of the <code>LabelSequence</code> + /// that does not contain escape sequences. Default value is false. + std::string toRawText(bool omit_final_dot = false) const; + + /// \brief Render the <code>Name</code> in the wire format with compression. + /// + /// This method dumps the Name in wire format with help of \c renderer, + /// which encapsulates output buffer and name compression algorithm to + /// render the name. + /// + /// If resource allocation in rendering process fails, a corresponding + /// standard exception will be thrown. + /// + /// \param renderer DNS message rendering context that encapsulates the + /// output buffer and name compression information. + void toWire(AbstractMessageRenderer& renderer) const; + + /// \brief Render the <code>Name</code> in the wire format without + /// compression. + /// + /// If resource allocation in rendering process fails, a corresponding + /// standard exception will be thrown. This can be avoided by preallocating + /// a sufficient size of \c buffer. Specifically, if + /// <code>buffer.getCapacity() - buffer.getLength() >= Name::MAX_WIRE</code> + /// then this method should not throw an exception. + /// + /// \param buffer An output buffer to store the wire %data. + void toWire(isc::util::OutputBuffer& buffer) const; + //@} + + /// + /// \name Comparison methods + /// + //@{ + /// \brief Compare two <code>Name</code>s. + /// + /// This method compares the <code>Name</code> and <code>other</code> and + /// returns the result in the form of a <code>NameComparisonResult</code> + /// object. + /// + /// Note that this is case-insensitive comparison. + /// + /// This method never throws an exception. + /// + /// \param other the right-hand operand to compare against. + /// \return a <code>NameComparisonResult</code> object representing the + /// comparison result. + NameComparisonResult compare(const Name& other) const; + +public: + /// \brief Return true iff two names are equal. + /// + /// Semantically this could be implemented based on the result of the + /// \c compare() method, but the actual implementation uses different code + /// that simply performs character-by-character comparison (case + /// insensitive for the name label parts) on the two names. This is because + /// it would be much faster and the simple equality check would be pretty + /// common. + /// + /// This method never throws an exception. + /// + /// \param other the <code>Name</code> object to compare against. + /// \return true if the two names are equal; otherwise false. + bool equals(const Name& other) const; + + /// Same as equals() + bool operator==(const Name& other) const { return (equals(other)); } + + /// \brief Return true iff two names are not equal. + /// + /// This method simply negates the result of \c equal() method, and in that + /// sense it's redundant. The separate method is provided just for + /// convenience. + bool nequals(const Name& other) const { return (!(equals(other))); } + + /// Same as nequals() + bool operator!=(const Name& other) const { return (nequals(other)); } + + /// \brief Less-than or equal comparison for Name against <code>other</code> + /// + /// The comparison is based on the result of the \c compare() method. + /// + /// This method never throws an exception. + /// + /// \param other the <code>Name</code> object to compare against. + /// \return true if <code>compare(other).getOrder() <= 0</code>; + /// otherwise false. + bool leq(const Name& other) const; + + /// Same as leq() + bool operator<=(const Name& other) const { return (leq(other)); } + + /// \brief Greater-than or equal comparison for Name against + /// <code>other</code> + /// + /// The comparison is based on the result of the \c compare() method. + /// + /// This method never throws an exception. + /// + /// \param other the <code>Name</code> object to compare against. + /// \return true if <code>compare(other).getOrder() >= 0</code>; + /// otherwise false. + bool geq(const Name& other) const; + + /// Same as geq() + bool operator>=(const Name& other) const { return (geq(other)); } + + /// \brief Less-than comparison for Name against <code>other</code> + /// + /// The comparison is based on the result of the \c compare() method. + /// + /// This method never throws an exception. + /// + /// \param other the <code>Name</code> object to compare against. + /// \return true if <code>compare(other).getOrder() < 0</code>; + /// otherwise false. + bool lthan(const Name& other) const; + + /// Same as lthan() + bool operator<(const Name& other) const { return (lthan(other)); } + + /// \brief Greater-than comparison for Name against <code>other</code> + /// + /// The comparison is based on the result of the \c compare() method. + //// + /// This method never throws an exception. + /// + /// \param other the <code>Name</code> object to compare against. + /// \return true if <code>compare(other).getOrder() > 0</code>; + /// otherwise false. + bool gthan(const Name& other) const; + + /// Same as gthan() + bool operator>(const Name& other) const { return (gthan(other)); } + //@} + + /// + /// \name Transformer methods + /// + //@{ + /// \brief Extract a specified subpart of Name. + /// + /// <code>name.split(first, n)</code> constructs a new name starting from + /// the <code>first</code>-th label of the \c name, and subsequent \c n + /// labels including the \c first one. Since names in this current + /// implementation are always "absolute", if the specified range doesn't + /// contain the trailing dot of the original \c name, then a dot will be + /// appended to the resulting name. As a result, the number of labels + /// will be <code>n + 1</code>, rather than \c n. For example, + /// when \c n is <code>Name("www.example.com")</code>, + /// both <code>n.split(1, 2)</code> and <code>n.split(1, 3)</code> + /// will produce a name corresponding to "example.com.", which has 3 labels. + /// Note also that labels are counted from 0, and so <code>first = 1</code> + /// in this example specified the label "example", not "www". + /// + /// Parameter \c n must be larger than 0, and the range specified by + /// \c first and \c n must not exceed the valid range of the original name; + /// otherwise, an exception of class \c OutOfRange will be thrown. + /// + /// Note to developers: we may want to have different versions (signatures) + /// of this method. For example, we want to split the Name based on a given + /// suffix name. + /// + /// \param first The start position (in labels) of the extracted name + /// \param n Number of labels of the extracted name + /// \return A new Name object based on the Name containing <code>n</code> + /// labels including and following the <code>first</code> label. + Name split(unsigned int first, unsigned int n) const; + + /// \brief Extract a specified super domain name of Name. + /// + /// This function constructs a new \c Name object that is a super domain + /// of \c this name. + /// The new name is \c level labels upper than \c this name. + /// For example, when \c name is www.example.com, + /// <code>name.split(1)</code> will return a \c Name object for example.com. + /// \c level can be 0, in which case this method returns a copy of + /// \c this name. + /// The possible maximum value for \c level is + /// <code>this->getLabelCount()-1</code>, in which case this method + /// returns a root name. + /// + /// One common expected usage of this method is to iterate over super + /// domains of a given name, label by label, as shown in the following + /// sample code: + /// \code // if name is www.example.com... + /// for (int i = 0; i < name.getLabelCount(); ++i) { + /// Name upper_name(name.split(i)); + /// // upper_name'll be www.example.com., example.com., com., and then . + /// } + /// \endcode + /// + /// \c level must be smaller than the number of labels of \c this name; + /// otherwise an exception of class \c OutOfRange will be thrown. + /// In addition, if resource allocation for the new name fails, a + /// corresponding standard exception will be thrown. + /// + /// Note to developers: probably as easily imagined, this method is a + /// simple wrapper to one usage of the other + /// <code>split(unsigned int, unsigned int) const</code> method and is + /// redundant in some sense. + /// We provide the "redundant" method for convenience, however, because + /// the expected usage shown above seems to be common, and the parameters + /// to the other \c split(unsigned int, unsigned int) const to implement + /// it may not be very intuitive. + /// + /// We are also aware that it is generally discouraged to add a public + /// member function that could be implemented using other member functions. + /// We considered making it a non member function, but we could not come + /// up with an intuitive function name to represent the specific service. + /// Some other developers argued, probably partly because of the + /// counter intuitive function name, a different signature of \c split + /// would be better to improve code readability. + /// While that may be a matter of personal preference, we accepted the + /// argument. One major goal of public APIs like this is wider acceptance + /// from internal/external developers, so unless there is a clear advantage + /// it would be better to respect the preference of the API users. + /// + /// Since this method doesn't have to be a member function in other way, + /// it is intentionally implemented only using public interfaces of the + /// \c Name class; it doesn't refer to private members of the class even if + /// it could. + /// This way we hope we can avoid damaging the class encapsulation, + /// which is a major drawback of public member functions. + /// As such if and when this "method" has to be extended, it should be + /// implemented without the privilege of being a member function unless + /// there is a very strong reason to do so. In particular a minor + /// performance advantage shouldn't justify that approach. + /// + /// \param level The number of labels to be removed from \c this name to + /// create the super domain name. + /// (0 <= \c level < <code>this->getLabelCount()</code>) + /// \return A new \c Name object to be created. + Name split(unsigned int level) const; + + /// \brief Reverse the labels of a name + /// + /// This method reverses the labels of a name. For example, if + /// \c this is "www.example.com.", this method will return + /// "com.example.www." (This is useful because DNSSEC sort order + /// is equivalent to a lexical sort of label-reversed names.) + Name reverse() const; + + /// \brief Concatenate two names. + /// + /// This method appends \c suffix to \c this Name. The trailing dot of + /// \c this Name will be removed. For example, if \c this is "www." + /// and \c suffix is "example.com.", a successful return of this method + /// will be a name of "www.example.com." + /// + ///The resulting length of the concatenated name must not exceed + /// \c Name::MAX_WIRE; otherwise an exception of class + /// \c TooLongName will be thrown. + /// + /// \param suffix a Name object to be appended to the Name. + /// \return a new Name object concatenating \c suffix to \c this Name. + Name concatenate(const Name& suffix) const; + + /// \brief Downcase all upper case alphabet characters in the name. + /// + /// This method modifies the calling object so that it can perform the + /// conversion as fast as possible and can be exception free. + /// + /// The return value of this version of \c downcase() is a reference to + /// the calling object (i.e., \c *this) so that the caller can use the + /// result of downcasing in a single line. For example, if variable + /// \c n is a \c Name class object possibly containing upper case + /// characters, and \c b is an \c OutputBuffer class object, then the + /// following code will dump the name in wire format to \c b with + /// downcasing upper case characters: + /// + /// \code n.downcase().toWire(b); \endcode + /// + /// Since this method modifies the calling object, a \c const name object + /// cannot call it. If \c n is a \c const Name class object, it must first + /// be copied to a different object and the latter must be used for the + /// downcase modification. + /// + /// \return A reference to the calling object with being downcased. + Name& downcase(); + //@} + + /// + /// \name Testing methods + /// + //@{ + /// \brief Test if this is a wildcard name. + /// + /// \return \c true if the least significant label of this Name is + /// <code>'*'</code>; otherwise \c false. + bool isWildcard() const; + //@} + + /// + /// \name Protocol constants + /// + //@{ + /// \brief Max allowable length of domain names. + static const size_t MAX_WIRE = 255; + + /// \brief Max allowable labels of domain names. + /// + /// This is <code>ceil(MAX_WIRE / 2)</code>, and is equal to the number of + /// labels of name "a.a.a.a....a." (127 "a"'s and trailing dot). + static const size_t MAX_LABELS = 128; + + /// \brief Max allowable length of labels of a domain name. + static const size_t MAX_LABELLEN = 63; + + /// \brief Max possible pointer value for name compression. + /// + /// This is the highest number of 14-bit unsigned integer. Name compression + /// pointers are identified as a 2-byte value starting with the upper two + /// bit being 11. + static const uint16_t MAX_COMPRESS_POINTER = 0x3fff; + /// \brief A 8-bit masked value indicating a start of compression pointer. + static const uint16_t COMPRESS_POINTER_MARK8 = 0xc0; + /// \brief A 16-bit masked value indicating a start of compression pointer. + static const uint16_t COMPRESS_POINTER_MARK16 = 0xc000; + //@} + + /// + /// \name Well-known name constants + /// + //@{ + /// \brief Root name (i.e. "."). + static const Name& ROOT_NAME(); + //@} + +private: + NameString ndata_; + NameOffsets offsets_; + unsigned int length_; + unsigned int labelcount_; +}; + +inline const Name& +Name::ROOT_NAME() { + static Name root_name("."); + return (root_name); +} + +/// +/// \brief Insert the name as a string into stream. +/// +/// This method convert the \c name into a string and inserts it into the +/// output stream \c os. +/// +/// This function overloads the global operator<< to behave as described in +/// ostream::operator<< but applied to \c Name objects. +/// +/// \param os A \c std::ostream object on which the insertion operation is +/// performed. +/// \param name The \c Name object output by the operation. +/// \return A reference to the same \c std::ostream object referenced by +/// parameter \c os after the insertion operation. +std::ostream& +operator<<(std::ostream& os, const Name& name); + +} +} +#endif // NAME_H + +// Local Variables: +// mode: c++ +// End: |