%PDF- %PDF-
| Direktori : /backups/router/usr/local/include/kea/dns/ |
| Current File : //backups/router/usr/local/include/kea/dns/txt_like.h |
// Copyright (C) 2011-2024 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 TXT_LIKE_H
#define TXT_LIKE_H
#include <dns/master_lexer.h>
#include <dns/char_string.h>
#include <stdint.h>
#include <algorithm>
#include <string>
#include <sstream>
#include <vector>
namespace isc {
namespace dns {
namespace rdata {
namespace generic {
namespace detail {
/// \brief \c rdata::TXTLikeImpl class represents the TXT-like RDATA for TXT
/// and SPF types.
///
/// This class implements the basic interfaces inherited by the TXT and SPF
/// classes from the abstract \c rdata::Rdata class, and provides trivial
/// accessors to TXT-like RDATA.
template<class Type, uint16_t typeCode>class TXTLikeImpl {
public:
/// \brief Constructor from wire-format data.
///
/// \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.
///
/// <b>Exceptions</b>
///
/// \c InvalidRdataLength is thrown if rdata_len exceeds the maximum.
/// \c DNSMessageFORMERR is thrown if the RR is malformed.
TXTLikeImpl(util::InputBuffer& buffer, size_t rdata_len) {
if (rdata_len > MAX_RDLENGTH) {
isc_throw(InvalidRdataLength, "RDLENGTH too large: " << rdata_len);
}
if (rdata_len == 0) { // note that this couldn't happen in the loop.
isc_throw(DNSMessageFORMERR, "Error in parsing " <<
RRType(typeCode) << " RDATA: 0-length character string");
}
do {
const uint8_t len = buffer.readUint8();
if (rdata_len < len + 1) {
isc_throw(DNSMessageFORMERR, "Error in parsing " <<
RRType(typeCode) <<
" RDATA: character string length is too large: " <<
static_cast<int>(len));
}
std::vector<uint8_t> data(len + 1);
data[0] = len;
buffer.readData(&data[0] + 1, len);
string_list_.push_back(data);
rdata_len -= (len + 1);
} while (rdata_len > 0);
}
/// \brief Constructor from string.
///
/// \throw CharStringTooLong the parameter string length exceeds maximum.
/// \throw InvalidRdataText the method cannot process the parameter data
explicit TXTLikeImpl(const std::string& txtstr) {
std::istringstream ss(txtstr);
MasterLexer lexer;
lexer.pushSource(ss);
try {
buildFromTextHelper(lexer);
if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) {
isc_throw(InvalidRdataText, "Failed to construct " <<
RRType(typeCode) << " RDATA from '" << txtstr <<
"': extra new line");
}
} catch (const MasterLexer::LexerError& ex) {
isc_throw(InvalidRdataText, "Failed to construct " <<
RRType(typeCode) << " RDATA from '" << txtstr << "': "
<< ex.what());
}
}
/// \brief Constructor using the master lexer.
///
/// \throw CharStringTooLong the parameter string length exceeds maximum.
/// \throw InvalidRdataText the method cannot process the parameter data
///
/// \param lexer A \c MasterLexer object parsing a master file for this
/// RDATA.
TXTLikeImpl(MasterLexer& lexer) {
buildFromTextHelper(lexer);
}
private:
void buildFromTextHelper(MasterLexer& lexer) {
while (true) {
const MasterToken& token = lexer.getNextToken(
MasterToken::QSTRING, true);
if (token.getType() != MasterToken::STRING &&
token.getType() != MasterToken::QSTRING) {
break;
}
string_list_.push_back(std::vector<uint8_t>());
stringToCharString(token.getStringRegion(), string_list_.back());
}
// Let upper layer handle eol/eof.
lexer.ungetToken();
if (string_list_.empty()) {
isc_throw(InvalidRdataText, "Failed to construct " <<
RRType(typeCode) << " RDATA: empty input");
}
}
public:
/// \brief The copy constructor.
///
/// Trivial for now, we could've used the default one.
TXTLikeImpl(const TXTLikeImpl& other) :
string_list_(other.string_list_)
{}
/// \brief Render the TXT-like data in the wire format to an OutputBuffer
/// object.
///
/// \param buffer An output buffer to store the wire data.
void
toWire(util::OutputBuffer& buffer) const {
for (std::vector<std::vector<uint8_t> >::const_iterator it =
string_list_.begin();
it != string_list_.end();
++it)
{
buffer.writeData(&(*it)[0], (*it).size());
}
}
/// \brief Render the TXT-like data in the wire format to an
/// AbstractMessageRenderer object.
///
/// \param renderer An output AbstractMessageRenderer to send the wire data
/// to.
void
toWire(AbstractMessageRenderer& renderer) const {
for (std::vector<std::vector<uint8_t> >::const_iterator it =
string_list_.begin();
it != string_list_.end();
++it)
{
renderer.writeData(&(*it)[0], (*it).size());
}
}
/// \brief Convert the TXT-like data to a string.
///
/// \return A \c string object that represents the TXT-like data.
std::string
toText() const {
std::string s;
for (std::vector<std::vector<uint8_t> >::const_iterator it =
string_list_.begin(); it != string_list_.end(); ++it)
{
if (!s.empty()) {
s.push_back(' ');
}
s.push_back('"');
s.append(charStringToString(*it));
s.push_back('"');
}
return (s);
}
/// \brief Compare two instances of TXT-like RDATA.
///
/// It is up to the caller to make sure that \c other is an object of the
/// same \c TXTLikeImpl class.
///
/// \param other the right-hand operand to compare against.
/// \return < 0 if \c this would be sorted before \c other.
/// \return 0 if \c this is identical to \c other in terms of sorting
/// order.
/// \return > 0 if \c this would be sorted after \c other.
int
compare(const TXTLikeImpl& other) const {
// This implementation is not efficient. Revisit this (TBD).
util::OutputBuffer this_buffer(0);
toWire(this_buffer);
uint8_t const* const this_data = (uint8_t const*)this_buffer.getData();
const size_t this_len = this_buffer.getLength();
util::OutputBuffer other_buffer(0);
other.toWire(other_buffer);
uint8_t const* const other_data
= (uint8_t const*)other_buffer.getData();
const size_t other_len = other_buffer.getLength();
const size_t cmplen = std::min(this_len, other_len);
const int cmp = memcmp(this_data, other_data, cmplen);
if (cmp != 0) {
return (cmp);
} else {
return ((this_len == other_len) ? 0 :
(this_len < other_len) ? -1 : 1);
}
}
private:
/// Note: this is a prototype version; we may reconsider
/// this representation later.
std::vector<std::vector<uint8_t> > string_list_;
};
} // namespace detail
} // namespace generic
} // namespace rdata
} // namespace dns
} // namespace isc
#endif // TXT_LIKE_H