BIND 10 trac499, updated. 77027490d53b644e157fce2df59c5dbd496d1e1a [trac499] Add "normalization" of received data
BIND 10 source code commits
bind10-changes at lists.isc.org
Mon Feb 28 19:24:51 UTC 2011
The branch, trac499 has been updated
via 77027490d53b644e157fce2df59c5dbd496d1e1a (commit)
from be701769ab3ba884c550d22455ba09af3b725a07 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 77027490d53b644e157fce2df59c5dbd496d1e1a
Author: Stephen Morris <stephen at isc.org>
Date: Mon Feb 28 19:24:01 2011 +0000
[trac499] Add "normalization" of received data
... i.e. copying TCP data into the receive buffer omitting the leading
two-byte message length.
-----------------------------------------------------------------------
Summary of changes:
src/lib/asiolink/asiolink_utilities.h | 2 +-
src/lib/asiolink/io_asio_socket.h | 26 ++++++++++++
src/lib/asiolink/io_fetch.cc | 15 ++++---
src/lib/asiolink/tcp_socket.h | 27 ++++++++++++-
src/lib/asiolink/tests/io_fetch_unittest.cc | 31 +++------------
src/lib/asiolink/tests/tcp_socket_unittest.cc | 52 +++++++++++++++++++++++++
src/lib/asiolink/tests/udp_socket_unittest.cc | 50 ++++++++++++++++++++++++
src/lib/asiolink/udp_socket.h | 21 +++++++++-
8 files changed, 189 insertions(+), 35 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/lib/asiolink/asiolink_utilities.h b/src/lib/asiolink/asiolink_utilities.h
index f7f82be..659e6a0 100644
--- a/src/lib/asiolink/asiolink_utilities.h
+++ b/src/lib/asiolink/asiolink_utilities.h
@@ -41,7 +41,7 @@ readUint16(const void* buffer) {
/// \brief Write Unisgned 16-Bit Integer to Buffer
///
-/// This is essentially a copy of isc::dns::OutputBuffer::writeUint16. It
+/// This is essentially a copy of isc::dns::OutputBuffer::writeUint16. It
/// should really be moved into a separate library.
///
/// \param value 16-bit value to convert
diff --git a/src/lib/asiolink/io_asio_socket.h b/src/lib/asiolink/io_asio_socket.h
index fbf749e..c8fea04 100644
--- a/src/lib/asiolink/io_asio_socket.h
+++ b/src/lib/asiolink/io_asio_socket.h
@@ -26,6 +26,8 @@
#include <exceptions/exceptions.h>
#include <coroutine.h>
+#include <dns/buffer.h>
+
#include <asiolink/io_error.h>
#include <asiolink/io_socket.h>
@@ -224,6 +226,21 @@ public:
/// needed.
virtual bool receiveComplete(const void* data, size_t length) = 0;
+ /// \brief Append Normalized Data
+ ///
+ /// When a UDP buffer is received, the entire buffer contains the data.
+ /// When a TCP buffer is received, the first two bytes of the buffer hold
+ /// a length count. This method removes those bytes from the buffer.
+ ///
+ /// \param inbuf Input buffer. This contains the data received over the
+ /// network connection.
+ /// \param length Amount of data in the input buffer. If TCP, this includes
+ /// the two-byte count field.
+ /// \param outbuf Pointer to output buffer to which the data will be
+ /// appended.
+ virtual void appendNormalizedData(const void* inbuf, size_t length,
+ isc::dns::OutputBufferPtr outbuf) = 0;
+
/// \brief Cancel I/O On AsioSocket
virtual void cancel() = 0;
@@ -321,6 +338,15 @@ public:
virtual bool receiveComplete(void*, size_t, size_t&) {
return (true);
}
+ /// \brief Append Normalized Data
+ ///
+ /// \param inbuf Unused.
+ /// \param length Unused.
+ /// \param outbuf unused.
+ virtual void appendNormalizedData(const void*, size_t,
+ isc::dns::OutputBufferPtr)
+ {
+ }
/// \brief Cancel I/O On AsioSocket
///
diff --git a/src/lib/asiolink/io_fetch.cc b/src/lib/asiolink/io_fetch.cc
index 2992243..82e1907 100644
--- a/src/lib/asiolink/io_fetch.cc
+++ b/src/lib/asiolink/io_fetch.cc
@@ -72,8 +72,8 @@ struct IOFetchData {
boost::shared_ptr<IOEndpoint> remote; ///< Where the fetch was sent
isc::dns::Question question; ///< Question to be asked
isc::dns::OutputBufferPtr msgbuf; ///< Wire buffer for question
- isc::dns::OutputBufferPtr buffer; ///< Received data held here
- boost::shared_array<char> data; ///< Temporary array for data
+ isc::dns::OutputBufferPtr received; ///< Received data put here
+ boost::shared_array<char> staging; ///< Temporary array for received data
IOFetch::Callback* callback; ///< Called on I/O Completion
size_t cumulative; ///< Cumulative received amount
bool stopped; ///< Have we stopped running?
@@ -122,8 +122,8 @@ struct IOFetchData {
),
question(query),
msgbuf(new isc::dns::OutputBuffer(512)),
- buffer(buff),
- data(new char[IOFetch::MIN_LENGTH]),
+ received(buff),
+ staging(new char[IOFetch::MIN_LENGTH]),
callback(cb),
cumulative(0),
stopped(false),
@@ -211,11 +211,11 @@ IOFetch::operator()(asio::error_code ec, size_t length) {
// we check if the operation is complete and if not, loop to read again.
data_->origin = ASIO_RECVSOCK;
do {
- CORO_YIELD data_->socket->asyncReceive(data_->data.get(),
+ CORO_YIELD data_->socket->asyncReceive(data_->staging.get(),
static_cast<size_t>(MIN_LENGTH), data_->cumulative,
data_->remote.get(), *this);
data_->cumulative += length;
- } while (!data_->socket->receiveComplete(data_->data.get(),
+ } while (!data_->socket->receiveComplete(data_->staging.get(),
data_->cumulative));
/// Copy the answer into the response buffer. (TODO: If the
@@ -223,7 +223,8 @@ IOFetch::operator()(asio::error_code ec, size_t length) {
/// MutableBufferSequence, then it could be written to directly by
/// async_receive_from() and this additional copy step would be
/// unnecessary.)
- data_->buffer->writeData(data_->data.get(), length);
+ data_->socket->appendNormalizedData(data_->staging.get(),
+ data_->cumulative, data_->received);
// Finished with this socket, so close it. This will not generate an
// I/O error, but reset the origin to unknown in case we change this.
diff --git a/src/lib/asiolink/tcp_socket.h b/src/lib/asiolink/tcp_socket.h
index 1146fa3..492671e 100644
--- a/src/lib/asiolink/tcp_socket.h
+++ b/src/lib/asiolink/tcp_socket.h
@@ -119,7 +119,7 @@ public:
/// that was determined when the connection was opened.)
/// \param callback Callback object.
virtual void asyncSend(const void* data, size_t length,
- const IOEndpoint* endpoint, C& callback);
+ const IOEndpoint* endpoint, C& callback);
/// \brief Receive Asynchronously
///
@@ -147,6 +147,21 @@ public:
/// \return true if the receive is complete, false if not.
virtual bool receiveComplete(const void* data, size_t length);
+ /// \brief Append Normalized Data
+ ///
+ /// When a UDP buffer is received, the entire buffer contains the data.
+ /// When a TCP buffer is received, the first two bytes of the buffer hold
+ /// a length count. This method removes those bytes from the buffer.
+ ///
+ /// \param inbuf Input buffer. This contains the data received over the
+ /// network connection.
+ /// \param length Amount of data in the input buffer. If TCP, this includes
+ /// the two-byte count field.
+ /// \param outbuf Pointer to output buffer to which the data will be
+ /// appended
+ virtual void appendNormalizedData(const void* inbuf, size_t length,
+ isc::dns::OutputBufferPtr outbuf);
+
/// \brief Cancel I/O On Socket
virtual void cancel();
@@ -338,6 +353,16 @@ TCPSocket<C>::receiveComplete(const void* data, size_t length) {
return (complete);
}
+// Copy buffer less leading two bytes to the target buffer.
+
+template <typename C> void
+TCPSocket<C>::appendNormalizedData(const void* inbuf, size_t length,
+ isc::dns::OutputBufferPtr outbuf)
+{
+ const uint8_t* bytebuff = static_cast<const uint8_t*>(inbuf);
+ outbuf->writeData(bytebuff + 2, length - 2);
+}
+
// Cancel I/O on the socket. No-op if the socket is not open.
template <typename C> void
diff --git a/src/lib/asiolink/tests/io_fetch_unittest.cc b/src/lib/asiolink/tests/io_fetch_unittest.cc
index 99acee9..d743df2 100644
--- a/src/lib/asiolink/tests/io_fetch_unittest.cc
+++ b/src/lib/asiolink/tests/io_fetch_unittest.cc
@@ -47,7 +47,7 @@ namespace asiolink {
const asio::ip::address TEST_HOST(asio::ip::address::from_string("127.0.0.1"));
const uint16_t TEST_PORT(5301);
// FIXME Shouldn't we send something that is real message?
-const char TEST_DATA[] = "TEST DATA";
+const char TEST_DATA[] = "Test response from server to client";
/// \brief Test fixture for the asiolink::IOFetch.
class IOFetchTest : public virtual ::testing::Test, public virtual IOFetch::Callback
@@ -262,30 +262,11 @@ public:
// when one of the "servers" in this class has sent back the TEST_DATA.
// Check the data is as expected/
if (expected_ == IOFetch::SUCCESS) {
- size_t offset = 0; // Offset into start of buffer of data
- if (protocol_ == IOFetch::UDP) {
-
- // Check the length of data received against the amount expected.
- EXPECT_EQ(sizeof(TEST_DATA), result_buff_->getLength());
-
- } else {
-
- // Check the length of data received against the amount expected
- EXPECT_EQ(sizeof(TEST_DATA) + 2, result_buff_->getLength());
-
- // Check the count field. This should be equal to the total
- // length of the packet less 2 (the count field is equal to
- // the total length of the message less the count field itself -
- // RFC 1035, section 4.2.2).
- uint16_t count = readUint16(result_buff_->getData());
- EXPECT_EQ(result_buff_->getLength(), count + 2);
-
- // Update offset and count for the content check.
- offset += 2;
- }
- const void* start = static_cast<const void*>(
- static_cast<const uint8_t*>(result_buff_->getData()) + offset);
- EXPECT_TRUE(memcmp(TEST_DATA, start, sizeof(TEST_DATA)) == 0);
+ EXPECT_EQ(sizeof(TEST_DATA), result_buff_->getLength());
+
+ const uint8_t* start = static_cast<const uint8_t*>(result_buff_->getData());
+ EXPECT_TRUE(equal(TEST_DATA, (TEST_DATA + sizeof(TEST_DATA) - 1),
+ start));
}
// ... and cause the run loop to exit.
diff --git a/src/lib/asiolink/tests/tcp_socket_unittest.cc b/src/lib/asiolink/tests/tcp_socket_unittest.cc
index ca24e1a..e59eafc 100644
--- a/src/lib/asiolink/tests/tcp_socket_unittest.cc
+++ b/src/lib/asiolink/tests/tcp_socket_unittest.cc
@@ -274,6 +274,58 @@ clientReadComplete(TCPSocket<TCPCallback>& client, TCPCallback& client_cb,
return (complete);
}
+
+// Receive complete method should return true only if the count in the first
+// two bytes is equal to the size of the rest if the buffer.
+
+TEST(TCPSocket, receiveComplete) {
+ IOService service; // Used to instantiate socket
+ TCPSocket<TCPCallback> test(service); // Socket under test
+ uint8_t buffer[32]; // Buffer to check
+
+ // Expect that the value is true whatever number is written in the first
+ // two bytes of the buffer.
+ uint16_t count = 0;
+ for (uint32_t i = 0; i < (2 << 16); ++i, ++count) {
+ writeUint16(count, buffer);
+ if (count == (sizeof(buffer) - 2)) {
+ EXPECT_TRUE(test.receiveComplete(buffer, sizeof(buffer)));
+ } else {
+ EXPECT_FALSE(test.receiveComplete(buffer, sizeof(buffer)));
+ }
+ }
+}
+
+// Check that the normalized data copy only copies all but the first two bytes
+// of the buffer (whatever the count).
+
+TEST(TCPSocket, appendNormalizedData) {
+ IOService service; // Used to instantiate socket
+ TCPSocket<TCPCallback> test(service); // Socket under test
+ uint8_t inbuff[32]; // Buffer to check
+ isc::dns::OutputBufferPtr outbuff(new isc::dns::OutputBuffer(sizeof(inbuff)));
+ // Where data is written
+
+ // Initialize the input buffer with data.
+ for (uint8_t i = 0; i < sizeof(inbuff); ++i) {
+ inbuff[i] = i + 1; // An arbitrary number
+ }
+
+ // Loop to ensure that entire buffer is copied on all count values, no
+ // matter what.
+ uint16_t count = 0;
+ for (uint32_t i = 0; i < (2 << 16); ++i, ++count) {
+ writeUint16(count, inbuff);
+ outbuff->clear();
+ test.appendNormalizedData(inbuff, sizeof(inbuff), outbuff);
+
+ EXPECT_EQ((sizeof(inbuff) - 2), outbuff->getLength());
+
+ const uint8_t* outptr = static_cast<const uint8_t*>(outbuff->getData());
+ EXPECT_TRUE(equal(&inbuff[2], &inbuff[sizeof(inbuff) - 1], outptr));
+ }
+}
+
// TODO: Need to add a test to check the cancel() method
// Tests the operation of a TCPSocket by opening it, sending an asynchronous
diff --git a/src/lib/asiolink/tests/udp_socket_unittest.cc b/src/lib/asiolink/tests/udp_socket_unittest.cc
index aa46498..2ee1080 100644
--- a/src/lib/asiolink/tests/udp_socket_unittest.cc
+++ b/src/lib/asiolink/tests/udp_socket_unittest.cc
@@ -35,8 +35,11 @@
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
+#include <dns/buffer.h>
+
#include <asio.hpp>
+#include <asiolink/asiolink_utilities.h>
#include <asiolink/io_service.h>
#include <asiolink/udp_endpoint.h>
#include <asiolink/udp_socket.h>
@@ -162,6 +165,53 @@ private:
boost::shared_ptr<PrivateData> ptr_; ///< Pointer to private data
};
+// Receive complete method should return true regardless of what is in the first
+// two bytes of a buffer.
+
+TEST(UDPSocket, receiveComplete) {
+ IOService service; // Used to instantiate socket
+ UDPSocket<UDPCallback> test(service); // Socket under test
+ uint8_t buffer[32]; // Buffer to check
+
+ // Expect that the value is true whatever number is written in the first
+ // two bytes of the buffer.
+ uint16_t count = 0;
+ for (uint32_t i = 0; i < (2 << 16); ++i, ++count) {
+ writeUint16(count, buffer);
+ EXPECT_TRUE(test.receiveComplete(buffer, sizeof(buffer)));
+ }
+}
+
+// Check that the normalized data copy copies the entire buffer regardless of
+// the first two bytes.
+
+TEST(UDPSocket, appendNormalizedData) {
+ IOService service; // Used to instantiate socket
+ UDPSocket<UDPCallback> test(service); // Socket under test
+ uint8_t inbuff[32]; // Buffer to check
+ isc::dns::OutputBufferPtr outbuff(new isc::dns::OutputBuffer(sizeof(inbuff)));
+ // Where data is written
+
+ // Initialize the input buffer with data.
+ for (uint8_t i = 0; i < sizeof(inbuff); ++i) {
+ inbuff[i] = i + 1; // An arbitrary number
+ }
+
+ // Loop to ensure that entire buffer is copied on all count values, no
+ // matter what.
+ uint16_t count = 0;
+ for (uint32_t i = 0; i < (2 << 16); ++i, ++count) {
+ writeUint16(count, inbuff);
+ outbuff->clear();
+ test.appendNormalizedData(inbuff, sizeof(inbuff), outbuff);
+
+ EXPECT_EQ(sizeof(inbuff), outbuff->getLength());
+
+ const uint8_t* outptr = static_cast<const uint8_t*>(outbuff->getData());
+ EXPECT_TRUE(equal(&inbuff[0], &inbuff[sizeof(inbuff) - 1], outptr));
+ }
+}
+
// TODO: Need to add a test to check the cancel() method
// Tests the operation of a UDPSocket by opening it, sending an asynchronous
diff --git a/src/lib/asiolink/udp_socket.h b/src/lib/asiolink/udp_socket.h
index 1a016d2..8399f2c 100644
--- a/src/lib/asiolink/udp_socket.h
+++ b/src/lib/asiolink/udp_socket.h
@@ -107,7 +107,7 @@ public:
/// \param endpoint Target of the send
/// \param callback Callback object.
virtual void asyncSend(const void* data, size_t length,
- const IOEndpoint* endpoint, C& callback);
+ const IOEndpoint* endpoint, C& callback);
/// \brief Receive Asynchronously
///
@@ -137,6 +137,24 @@ public:
return (true);
}
+ /// \brief Append Normalized Data
+ ///
+ /// When a UDP buffer is received, the entire buffer contains the data.
+ /// When a TCP buffer is received, the first two bytes of the buffer hold
+ /// a length count. This method removes those bytes from the buffer.
+ ///
+ /// \param inbuf Input buffer. This contains the data received over the
+ /// network connection.
+ /// \param length Amount of data in the input buffer. If TCP, this includes
+ /// the two-byte count field.
+ /// \param outbuf Pointer to output buffer to which the data will be
+ /// appended
+ virtual void appendNormalizedData(const void* inbuf, size_t length,
+ isc::dns::OutputBufferPtr outbuf)
+ {
+ outbuf->writeData(inbuf, length);
+ }
+
/// \brief Cancel I/O On Socket
virtual void cancel();
@@ -271,6 +289,7 @@ UDPSocket<C>::asyncReceive(void* data, size_t length, size_t offset,
}
// Cancel I/O on the socket. No-op if the socket is not open.
+
template <typename C> void
UDPSocket<C>::cancel() {
if (isopen_) {
More information about the bind10-changes
mailing list