Commit 19760b1b authored by JINMEI Tatuya's avatar JINMEI Tatuya

merged the latest snapshot of DNS message library to parkinglot


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/parkinglot@530 e5f2f494-b856-4b98-b285-d166d9295462
parent 8fdab175
......@@ -12,9 +12,21 @@ AC_PROG_CXX
AC_PROG_CC
AC_PROG_RANLIB
AC_PROG_LIBTOOL
m4_define([_AM_PYTHON_INTERPRETER_LIST], [python python3 python3.1])
AM_PATH_PYTHON([3.1])
# default compiler warning settings
if test "X$GCC" = "Xyes"; then
CXXFLAGS="-g -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare"
fi
# produce PIC unless we disable shared libraries. need this for python bindings.
if test $enable_shared != "no" -a "X$GCC" = "Xyes"; then
CXXFLAGS="$CXXFLAGS -fPIC"
fi
# Checks for libraries.
# Checks for header files.
......@@ -141,6 +153,7 @@ AC_CONFIG_FILES([Makefile
src/lib/config/Makefile
src/lib/config/cpp/Makefile
src/lib/dns/Makefile
src/lib/dns/cpp/Makefile
])
AC_OUTPUT([src/bin/bind-cfgd/bind-cfgd
src/bin/cmd-ctrld/cmd-ctrld
......
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_srcdir)/ext
lib_LIBRARIES = libdns.a
libdns_a_SOURCES = name.cc buffer.cc rrset.cc message.cc \
name.h buffer.h rrset.h message.h data_source.cc data_source.h
TESTS =
if HAVE_GTEST
TESTS += run_unittests
run_unittests_SOURCES = run_unittests.cc name_unittest.cc rrset_unittest.cc
run_unittests_SOURCES += message_unittest.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(GTEST_LDFLAGS)
run_unittests_LDADD = ./libdns.a $(GTEST_LDADD)
endif
noinst_PROGRAMS = $(TESTS)
SUBDIRS = cpp
// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
// $Id$
#ifndef __BUFFER_HH
#define __BUFFER_HH 1
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdint.h>
#include <string.h>
#include <stdexcept>
#include <algorithm>
#include <vector>
#include <dns/exceptions.h>
namespace isc {
// Abstraction of buffers for socket I/O. This is a tentative idea and should
// be revisited.
class Buffer {
public:
virtual ~Buffer() {}
virtual void reserve(size_t len) = 0;
virtual void writeData(const void *cp, size_t len) = 0;
virtual void writeUint32(uint32_t data) = 0;
virtual void writeUint16(uint16_t data) = 0;
virtual void writeUint16At(uint16_t data, size_t pos) = 0;
virtual void writeUint8(uint8_t data) = 0;
virtual int sendTo(int s, const struct sockaddr& to, socklen_t to_len) = 0;
virtual size_t getSize() const = 0;
virtual size_t getSpace() const = 0;
virtual size_t getCurrent() const = 0;
virtual void setCurrent(size_t pos) = 0;
virtual uint8_t readUint8() = 0;
virtual uint16_t readUint16() = 0;
virtual uint32_t readUint32() = 0;
virtual void readData(void* data, size_t len) = 0;
virtual int recvFrom(int s, struct sockaddr *from,
socklen_t *from_len) = 0;
};
// I/O Buffer with a single array-style storage
class SingleBuffer : public Buffer {
public:
SingleBuffer() : _readpos(0) { buf_.reserve(4096); }
void reserve(size_t len) // XXX: API and implementation should be revisited
{
buf_.resize(len);
}
void writeData(const void *data, size_t len)
{
const uint8_t* cp = static_cast<const uint8_t*>(data);
buf_.insert(buf_.end(), cp, cp + len);
}
void writeUint32(uint32_t data)
{
data = htonl(data);
uint8_t* cp = static_cast<uint8_t*>((void*)&data);
buf_.insert(buf_.end(), cp, cp + sizeof(uint32_t));
}
void writeUint16(uint16_t data)
{
data = htons(data);
uint8_t* cp = static_cast<uint8_t*>((void*)&data);
buf_.insert(buf_.end(), cp, cp + sizeof(uint16_t));
}
void writeUint16At(uint16_t data, size_t pos)
{
if (pos + sizeof(data) >= buf_.size())
throw isc::ISCBufferInvalidPosition();
data = htons(data);
uint8_t* cp = static_cast<uint8_t*>((void*)&data);
copy(cp, cp + sizeof(uint16_t), buf_.begin() + pos);
}
void writeUint8(uint8_t data)
{
buf_.push_back(data);
}
int sendTo(int s, const struct sockaddr& to, socklen_t to_len);
size_t getSize() const { return (buf_.size()); }
size_t getSpace() const { return (buf_.size() - _readpos); }
size_t getCurrent() const { return (_readpos); }
void setCurrent(size_t pos)
{
if (pos > buf_.size())
throw isc::ISCBufferInvalidPosition();
_readpos = pos;
}
uint8_t readUint8();
uint16_t readUint16();
uint32_t readUint32();
void readData(void* data, size_t len);
int recvFrom(int s, struct sockaddr* from, socklen_t* from_len);
private:
size_t _readpos;
std::vector<uint8_t> buf_;
};
inline uint8_t
SingleBuffer::readUint8()
{
if (_readpos + sizeof(uint8_t) > buf_.size())
throw ISCBufferInvalidPosition();
return (buf_[_readpos++]);
}
inline uint16_t
SingleBuffer::readUint16()
{
uint16_t data;
if (_readpos + sizeof(data) > buf_.size())
throw ISCBufferInvalidPosition();
memcpy((void*)&data, &buf_[_readpos], sizeof(data));
_readpos += sizeof(data);
return (ntohs(data));
}
inline uint32_t
SingleBuffer::readUint32()
{
uint32_t data;
if (_readpos + sizeof(data) > buf_.size())
throw ISCBufferInvalidPosition();
memcpy((void*)&data, &buf_[_readpos], sizeof(data));
_readpos += sizeof(data);
return (ntohl(data));
}
inline void
SingleBuffer::readData(void *data, size_t len)
{
if (_readpos + len > buf_.size())
throw ISCBufferInvalidPosition();
memcpy(data, &buf_[_readpos], len);
_readpos += len;
}
}
#endif // __BUFFER_HH
// Local Variables:
// mode: c++
// End:
AM_CPPFLAGS = -I$(top_srcdir)/ext
CLEANFILES = *.gcno *.gcda
lib_LTLIBRARIES = libdns.la
libdns_la_SOURCES = buffer.h name.cc name.h messagerenderer.h messagerenderer.cc
libdns_la_SOURCES += rrparamregistry.h rrparamregistry.cc
libdns_la_SOURCES += rrclass.h rrclass.cc rrtype.h rrtype.cc rrttl.h rrttl.cc
libdns_la_SOURCES += rdata.h rdata.cc rrset.h rrset.cc
libdns_la_SOURCES += question.h question.cc
libdns_la_SOURCES += message.h message.cc
libdns_la_SOURCES += exceptions.h exceptions.cc
TESTS =
if HAVE_GTEST
TESTS += run_unittests
run_unittests_SOURCES = unittest_util.h unittest_util.cc
run_unittests_SOURCES += buffer_unittest.cc name_unittest.cc
run_unittests_SOURCES += messagerenderer_unittest.cc exceptions_unittest.cc
run_unittests_SOURCES += rrclass_unittest.cc rrtype_unittest.cc
run_unittests_SOURCES += rrttl_unittest.cc
run_unittests_SOURCES += rdata_unittest.cc
run_unittests_SOURCES += rrset_unittest.cc
run_unittests_SOURCES += question_unittest.cc
run_unittests_SOURCES += rrparamregistry_unittest.cc
run_unittests_SOURCES += message_unittest.cc
run_unittests_SOURCES += run_unittests.cc
run_unittests_CPPFLAGS = $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(GTEST_LDFLAGS)
run_unittests_LDADD = .libs/libdns.a $(GTEST_LDADD)
endif
noinst_PROGRAMS = $(TESTS)
// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
// $Id$
#ifndef __BUFFER_H
#define __BUFFER_H 1
#include <vector>
#include <string.h>
#include <stdint.h>
#include "exceptions.h"
namespace isc {
namespace dns {
///
/// \brief A standard DNS module exception that is thrown if an out-of-range
/// buffer operation is being performed.
///
class InvalidBufferPosition : public Exception {
public:
InvalidBufferPosition(const char* file, size_t line, const char* what) :
isc::dns::Exception(file, line, what) {}
};
///\brief The \c InputBuffer class is a buffer abstraction for manipulating
/// read-only data.
///
/// The main purpose of this class is to provide a safe placeholder for
/// examining wire-format data received from a network.
///
/// Applications normally use this class only in a limited situation: as an
/// interface between legacy I/O operation (such as receiving data from a BSD
/// socket) and the rest of the BIND10 DNS library. One common usage of this
/// class for an application would therefore be something like this:
///
/// \code unsigned char buf[1024];
/// struct sockaddr addr;
/// socklen_t addrlen = sizeof(addr);
/// int cc = recvfrom(s, buf, sizeof(buf), 0, &addr, &addrlen);
/// InputBuffer buffer(buf, cc);
/// // pass the buffer to a DNS message object to parse the message \endcode
///
/// Other BIND10 DNS classes will then use methods of this class to get access
/// to the data, but the application normally doesn't have to care about the
/// details.
///
/// An \c InputBuffer object internally holds a reference to the given data,
/// rather than make a local copy of the data. Also, it does not have an
/// ownership of the given data. It is application's responsibility to ensure
/// the data remains valid throughout the lifetime of the \c InputBuffer
/// object. Likewise, this object generally assumes the data isn't modified
/// throughout its lifetime; if the application modifies the data while this
/// object retains a reference to it, the result is undefined. The application
/// will also be responsible for releasing the data when it's not needed if it
/// was dynamically acquired.
///
/// This is a deliberate design choice: although it's safer to make a local
/// copy of the given data on construction, it would cause unacceptable
/// performance overhead, especially considering that a DNS message can be
/// as large as a few KB. Alternatively, we could allow the object to allocate
/// memory internally and expose it to the application to store network data
/// in it. This is also a bad design, however, in that we would effectively
/// break the abstraction employed in the class, and do so by publishing
/// "read-only" stuff as a writable memory region. Since there doesn't seem to
/// be a perfect solution, we have adopted what we thought a "least bad" one.
///
/// Methods for reading data from the buffer generally work like an input
/// stream: it begins with the head of the data, and once some length of data
/// is read from the buffer, the next read operation will take place from the
/// head of the unread data. An object of this class internally holds (a
/// notion of) where the next read operation should start. We call it the
/// <em>read position</em> in this document.
class InputBuffer {
public:
///
/// \name Constructors and Destructor
//@{
/// \brief Constructor from variable length of data.
///
/// It is caller's responsibility to ensure that the data is valid as long
/// as the buffer exists.
/// \param data A pointer to the data stored in the buffer.
/// \param len The length of the data in bytes.
InputBuffer(const void* data, size_t len) :
position_(0), data_(static_cast<const uint8_t*>(data)), len_(len) {}
//@}
///
/// \name Getter Methods
//@{
/// \brief Return the length of the data stored in the buffer.
size_t getLength() const { return (len_); }
/// \brief Return the current read position.
size_t getPosition() const { return (position_); }
//@}
///
/// \name Setter Methods
///
//@{
/// \brief Set the read position of the buffer to the given value.
///
/// The new position must be in the valid range of the buffer; otherwise
/// an exception of class \c isc::dns::InvalidBufferPosition will be thrown.
/// \param position The new position (offset from the beginning of the
/// buffer).
void setPosition(size_t position)
{
if (position > len_)
dns_throw(InvalidBufferPosition, "position is too large");
position_ = position;
}
//@}
///
/// \name Methods for reading data from the buffer.
//@{
/// \brief Read an unsigned 8-bit integer from the buffer and return it.
///
/// If the remaining length of the buffer is smaller than 8-bit, an
/// exception of class \c isc::dns::InvalidBufferPosition will be thrown.
uint8_t readUint8()
{
if (position_ + sizeof(uint8_t) > len_) {
dns_throw(InvalidBufferPosition, "read beyond end of buffer");
}
return (data_[position_++]);
}
/// \brief Read an unsigned 16-bit integer in network byte order from the
/// buffer, convert it to host byte order, and return it.
///
/// If the remaining length of the buffer is smaller than 16-bit, an
/// exception of class \c isc::dns::InvalidBufferPosition will be thrown.
uint16_t readUint16()
{
uint16_t data;
const uint8_t* cp;
if (position_ + sizeof(data) > len_) {
dns_throw(InvalidBufferPosition, "read beyond end of buffer");
}
cp = &data_[position_];
data = ((unsigned int)(cp[0])) << 8;
data |= ((unsigned int)(cp[1]));
position_ += sizeof(data);
return (data);
}
/// \brief Read an unsigned 32-bit integer in network byte order from the
/// buffer, convert it to host byte order, and return it.
///
/// If the remaining length of the buffer is smaller than 32-bit, an
/// exception of class \c isc::dns::InvalidBufferPosition will be thrown.
uint32_t readUint32()
{
uint32_t data;
const uint8_t* cp;
if (position_ + sizeof(data) > len_) {
dns_throw(InvalidBufferPosition, "read beyond end of buffer");
}
cp = &data_[position_];
data = ((unsigned int)(cp[0])) << 24;
data |= ((unsigned int)(cp[1])) << 16;
data |= ((unsigned int)(cp[2])) << 8;
data |= ((unsigned int)(cp[3]));
position_ += sizeof(data);
return (data);
}
/// \brief Read data of the specified length from the buffer and copy it to
/// the caller supplied buffer.
///
/// The data is copied as stored in the buffer; no conversion is performed.
/// If the remaining length of the buffer is smaller than the specified
/// length, an exception of class \c isc::dns::InvalidBufferPosition will
/// be thrown.
void readData(void* data, size_t len)
{
if (position_ + len > len_) {
dns_throw(InvalidBufferPosition, "read beyond end of buffer");
}
memcpy(data, &data_[position_], len);
position_ += len;
}
//@}
private:
size_t position_;
const uint8_t* data_;
size_t len_;
};
///
///\brief The \c OutputBuffer class is a buffer abstraction for manipulating
/// mutable data.
///
/// The main purpose of this class is to provide a safe workplace for
/// constructing wire-format data to be sent out to a network. Here,
/// <em>safe</em> means that it automatically allocates necessary memory and
/// avoid buffer overrun.
///
/// Like for the \c InputBuffer class, applications normally use this class only
/// in a limited situation. One common usage of this class for an application
/// would be something like this:
///
/// \code OutputBuffer buffer(4096); // give a sufficiently large initial size
/// // pass the buffer to a DNS message object to construct a wire-format
/// // DNS message.
/// struct sockaddr to;
/// sendto(s, buffer.getData(), buffer.getLength(), 0, &to, sizeof(to));
/// \endcode
///
/// where the \c getData() method gives a reference to the internal memory
/// region stored in the \c buffer object. This is a suboptimal design in that
/// it exposes an encapsulated "handle" of an object to its user.
/// Unfortunately, there is no easy way to avoid this without involving
/// expensive data copy if we want to use this object with a legacy API such as
/// a BSD socket interface. And, indeed, this is one major purpose for this
/// object. Applications should use this method only under such a special
/// circumstance. It should also be noted that the memory region returned by
/// \c getData() may be invalidated after a subsequent write operation.
///
/// An \c OutputBuffer class object automatically extends its memory region when
/// data is written beyond the end of the current buffer. However, it will
/// involve performance overhead such as reallocating more memory and copying
/// data. It is therefore recommended to construct the buffer object with a
/// sufficiently large initial size.
/// The \c getCapacity() method provides the current maximum size of data
/// (including the portion already written) that can be written into the buffer
/// without causing memory reallocation.
///
/// Methods for writing data into the buffer generally work like an output
/// stream: it begins with the head of the buffer, and once some length of data
/// is written into the buffer, the next write operation will take place from
/// the end of the buffer. Other methods to emulate "random access" are also
/// provided (e.g., \c writeUint16At()). The normal write operations are
/// normally exception-free as this class automatically extends the buffer
/// when necessary. However, in extreme cases such as an attempt of writing
/// multi-GB data, a separate exception (e.g., \c std::bad_alloc) may be thrown
/// by the system. This also applies to the constructor with a very large
/// initial size.
///
/// Note to developers: it may make more sense to introduce an abstract base
/// class for the \c OutputBuffer and define the simple implementation as a
/// a concrete derived class. That way we can provide flexibility for future
/// extension such as more efficient buffer implementation or allowing users
/// to have their own customized version without modifying the source code.
/// We in fact considered that option, but at the moment chose the simpler
/// approach with a single concrete class because it may make the
/// implementation unnecessarily complicated while we were still not certain
/// if we really want that flexibility. We may revisit the class design as
/// we see more applications of the class. The same considerations apply to
/// the \c InputBuffer and \c MessageRenderer classes.
class OutputBuffer {
public:
///
/// \name Constructors and Destructor
///
//@{
/// \brief Constructor from the initial size of the buffer.
///
/// \param len The initial length of the buffer in bytes.
OutputBuffer(size_t len) { data_.reserve(len); }
//@}
///
/// \name Getter Methods
///
//@{
/// \brief Return the current capacity of the buffer.
size_t getCapacity() const { return (data_.capacity()); }
/// \brief Return a pointer to the head of the data stored in the buffer.
///
/// The caller can assume that the subsequent \c getLength() bytes are
/// identical to the stored data of the buffer.
///
/// Note: The pointer returned by this method may be invalidated after a
/// subsequent write operation.
const void* getData() const { return (&data_[0]); }
/// \brief Return the length of data written in the buffer.
size_t getLength() const { return (data_.size()); }
/// \brief Return the value of the buffer at the specified position.
///
/// \c pos must specify the valid position of the buffer; otherwise an
/// exception class of \c InvalidBufferPosition will be thrown.
///
/// \param pos The position in the buffer to be returned.
uint8_t operator[](size_t pos) const
{
if (pos >= data_.size()) {
dns_throw(InvalidBufferPosition, "read at invalid position");
}
return (data_[pos]);
}
//@}
///
/// \name Methods for writing data into the buffer.
///
//@{
/// \brief Insert a specified length of gap at the end of the buffer.
///
/// The caller should not assume any particular value to be inserted.
/// This method is provided as a shortcut to make a hole in the buffer
/// that is to be filled in later, e.g, by \ref writeUint16At().
/// \param len The length of the gap to be inserted in bytes.
void skip(size_t len) { data_.insert(data_.end(), len, 0); }
/// \brief Clear buffer content.
///
/// This method can be used to re-initialize and reuse the buffer without
/// constructing a new one.
void clear() { data_.clear(); }
/// \brief Write an unsigned 8-bit integer into the buffer.
///
/// \param data The 8-bit integer to be written into the buffer.
void writeUint8(uint8_t data) { data_.push_back(data); }
/// \brief Write an unsigned 16-bit integer in host byte order into the