Commit 18ea57dd authored by Jelte Jansen's avatar Jelte Jansen
Browse files

Merge branch 'trac658_new'

parents dabcc74a 6a1a198d
......@@ -44,4 +44,17 @@ IOEndpoint::create(const int protocol, const IOAddress& address,
protocol);
}
bool
IOEndpoint::operator==(const IOEndpoint& other) const {
return (getProtocol() == other.getProtocol() &&
getPort() == other.getPort() &&
getFamily() == other.getFamily() &&
getAddress() == other.getAddress());
}
bool
IOEndpoint::operator!=(const IOEndpoint& other) const {
return (!operator==(other));
}
}
......@@ -89,6 +89,9 @@ public:
/// \brief Returns the address family of the endpoint.
virtual short getFamily() const = 0;
bool operator==(const IOEndpoint& other) const;
bool operator!=(const IOEndpoint& other) const;
/// \brief A polymorphic factory of endpoint from address and port.
///
/// This method creates a new instance of (a derived class of)
......
......@@ -43,6 +43,9 @@
#include <asiolink/tcp_socket.h>
#include <asiolink/udp_endpoint.h>
#include <asiolink/udp_socket.h>
#include <asiolink/qid_gen.h>
#include <stdint.h>
using namespace asio;
using namespace isc::dns;
......@@ -69,19 +72,20 @@ struct IOFetchData {
// which is not known until construction of the IOFetch. Use of a shared
// pointer here is merely to ensure deletion when the data object is deleted.
boost::scoped_ptr<IOAsioSocket<IOFetch> > socket;
///< Socket to use for I/O
boost::scoped_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 received; ///< Received data put here
IOFetch::Callback* callback; ///< Called on I/O Completion
asio::deadline_timer timer; ///< Timer to measure timeouts
IOFetch::Protocol protocol; ///< Protocol being used
size_t cumulative; ///< Cumulative received amount
size_t expected; ///< Expected amount of data
size_t offset; ///< Offset to receive data
bool stopped; ///< Have we stopped running?
int timeout; ///< Timeout in ms
///< Socket to use for I/O
boost::scoped_ptr<IOEndpoint> remote_snd;///< Where the fetch is sent
boost::scoped_ptr<IOEndpoint> remote_rcv;///< Where the response came from
isc::dns::Question question; ///< Question to be asked
isc::dns::OutputBufferPtr msgbuf; ///< Wire buffer for question
isc::dns::OutputBufferPtr received; ///< Received data put here
IOFetch::Callback* callback; ///< Called on I/O Completion
asio::deadline_timer timer; ///< Timer to measure timeouts
IOFetch::Protocol protocol; ///< Protocol being used
size_t cumulative; ///< Cumulative received amount
size_t expected; ///< Expected amount of data
size_t offset; ///< Offset to receive data
bool stopped; ///< Have we stopped running?
int timeout; ///< Timeout in ms
// In case we need to log an error, the origin of the last asynchronous
// I/O is recorded. To save time and simplify the code, this is recorded
......@@ -91,6 +95,7 @@ struct IOFetchData {
isc::log::MessageID origin; ///< Origin of last asynchronous I/O
uint8_t staging[IOFetch::STAGING_LENGTH];
///< Temporary array for received data
isc::dns::qid_t qid; ///< The QID set in the query
/// \brief Constructor
///
......@@ -121,7 +126,11 @@ struct IOFetchData {
static_cast<IOAsioSocket<IOFetch>*>(
new TCPSocket<IOFetch>(service))
),
remote((proto == IOFetch::UDP) ?
remote_snd((proto == IOFetch::UDP) ?
static_cast<IOEndpoint*>(new UDPEndpoint(address, port)) :
static_cast<IOEndpoint*>(new TCPEndpoint(address, port))
),
remote_rcv((proto == IOFetch::UDP) ?
static_cast<IOEndpoint*>(new UDPEndpoint(address, port)) :
static_cast<IOEndpoint*>(new TCPEndpoint(address, port))
),
......@@ -138,8 +147,21 @@ struct IOFetchData {
stopped(false),
timeout(wait),
origin(ASIO_UNKORIGIN),
staging()
staging(),
qid(QidGenerator::getInstance().generateQid())
{}
// Checks if the response we received was ok;
// - data contains the buffer we read, as well as the address
// we sent to and the address we received from.
// length is provided by the operator() in IOFetch.
// Addresses must match, number of octets read must be at least
// 2, and the first two octets must match the qid of the message
// we sent.
bool responseOK() {
return (*remote_snd == *remote_rcv && cumulative >= 2 &&
readUint16(received->getData()) == qid);
}
};
/// IOFetch Constructor - just initialize the private data
......@@ -180,7 +202,7 @@ IOFetch::operator()(asio::error_code ec, size_t length) {
/// declarations.
{
Message msg(Message::RENDER);
msg.setQid(QidGenerator::getInstance().generateQid());
msg.setQid(data_->qid);
msg.setOpcode(Opcode::QUERY());
msg.setRcode(Rcode::NOERROR());
msg.setHeaderFlag(Message::HEADERFLAG_RD);
......@@ -202,47 +224,50 @@ IOFetch::operator()(asio::error_code ec, size_t length) {
// is synchronous (i.e. UDP operation) we bypass the yield.
data_->origin = ASIO_OPENSOCK;
if (data_->socket->isOpenSynchronous()) {
data_->socket->open(data_->remote.get(), *this);
data_->socket->open(data_->remote_snd.get(), *this);
} else {
CORO_YIELD data_->socket->open(data_->remote.get(), *this);
CORO_YIELD data_->socket->open(data_->remote_snd.get(), *this);
}
// Begin an asynchronous send, and then yield. When the send completes,
// we will resume immediately after this point.
data_->origin = ASIO_SENDSOCK;
CORO_YIELD data_->socket->asyncSend(data_->msgbuf->getData(),
data_->msgbuf->getLength(), data_->remote.get(), *this);
// Now receive the response. Since TCP may not receive the entire
// message in one operation, we need to loop until we have received
// it. (This can't be done within the asyncReceive() method because
// each I/O operation will be done asynchronously and between each one
// we need to yield ... and we *really* don't want to set up another
// coroutine within that method.) So after each receive (and yield),
// we check if the operation is complete and if not, loop to read again.
//
// Another concession to TCP is that the amount of is contained in the
// first two bytes. This leads to two problems:
//
// a) We don't want those bytes in the return buffer.
// b) They may not both arrive in the first I/O.
//
// So... we need to loop until we have at least two bytes, then store
// the expected amount of data. Then we need to loop until we have
// received all the data before copying it back to the user's buffer.
// And we want to minimise the amount of copying...
data_->origin = ASIO_RECVSOCK;
data_->cumulative = 0; // No data yet received
data_->offset = 0; // First data into start of buffer
do {
CORO_YIELD data_->socket->asyncReceive(data_->staging,
static_cast<size_t>(STAGING_LENGTH),
data_->offset,
data_->remote.get(), *this);
} while (!data_->socket->processReceivedData(data_->staging, length,
data_->cumulative, data_->offset,
data_->expected, data_->received));
// Begin an asynchronous send, and then yield. When the send completes,
// we will resume immediately after this point.
data_->origin = ASIO_SENDSOCK;
CORO_YIELD data_->socket->asyncSend(data_->msgbuf->getData(),
data_->msgbuf->getLength(), data_->remote_snd.get(), *this);
// Now receive the response. Since TCP may not receive the entire
// message in one operation, we need to loop until we have received
// it. (This can't be done within the asyncReceive() method because
// each I/O operation will be done asynchronously and between each one
// we need to yield ... and we *really* don't want to set up another
// coroutine within that method.) So after each receive (and yield),
// we check if the operation is complete and if not, loop to read again.
//
// Another concession to TCP is that the amount of is contained in the
// first two bytes. This leads to two problems:
//
// a) We don't want those bytes in the return buffer.
// b) They may not both arrive in the first I/O.
//
// So... we need to loop until we have at least two bytes, then store
// the expected amount of data. Then we need to loop until we have
// received all the data before copying it back to the user's buffer.
// And we want to minimise the amount of copying...
data_->origin = ASIO_RECVSOCK;
data_->cumulative = 0; // No data yet received
data_->offset = 0; // First data into start of buffer
data_->received->clear(); // Clear the receive buffer
do {
CORO_YIELD data_->socket->asyncReceive(data_->staging,
static_cast<size_t>(STAGING_LENGTH),
data_->offset,
data_->remote_rcv.get(), *this);
} while (!data_->socket->processReceivedData(data_->staging, length,
data_->cumulative, data_->offset,
data_->expected, data_->received));
} while (!data_->responseOK());
// 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.
......@@ -290,16 +315,16 @@ IOFetch::stop(Result result) {
case TIME_OUT:
if (logger.isDebugEnabled(1)) {
logger.debug(20, ASIO_RECVTMO,
data_->remote->getAddress().toText().c_str(),
static_cast<int>(data_->remote->getPort()));
data_->remote_snd->getAddress().toText().c_str(),
static_cast<int>(data_->remote_snd->getPort()));
}
break;
case SUCCESS:
if (logger.isDebugEnabled(50)) {
logger.debug(30, ASIO_FETCHCOMP,
data_->remote->getAddress().toText().c_str(),
static_cast<int>(data_->remote->getPort()));
data_->remote_rcv->getAddress().toText().c_str(),
static_cast<int>(data_->remote_rcv->getPort()));
}
break;
......@@ -308,14 +333,14 @@ IOFetch::stop(Result result) {
// allowed but as it is unusual it is logged, but with a lower
// debug level than a timeout (which is totally normal).
logger.debug(1, ASIO_FETCHSTOP,
data_->remote->getAddress().toText().c_str(),
static_cast<int>(data_->remote->getPort()));
data_->remote_snd->getAddress().toText().c_str(),
static_cast<int>(data_->remote_snd->getPort()));
break;
default:
logger.error(ASIO_UNKRESULT, static_cast<int>(result),
data_->remote->getAddress().toText().c_str(),
static_cast<int>(data_->remote->getPort()));
data_->remote_snd->getAddress().toText().c_str(),
static_cast<int>(data_->remote_snd->getPort()));
}
// Stop requested, cancel and I/O's on the socket and shut it down,
......@@ -345,10 +370,10 @@ void IOFetch::logIOFailure(asio::error_code ec) {
static const char* PROTOCOL[2] = {"TCP", "UDP"};
logger.error(data_->origin,
ec.value(),
((data_->remote->getProtocol() == IPPROTO_TCP) ?
((data_->remote_snd->getProtocol() == IPPROTO_TCP) ?
PROTOCOL[0] : PROTOCOL[1]),
data_->remote->getAddress().toText().c_str(),
static_cast<int>(data_->remote->getPort()));
data_->remote_snd->getAddress().toText().c_str(),
static_cast<int>(data_->remote_snd->getPort()));
}
} // namespace asiolink
......
......@@ -60,6 +60,62 @@ TEST(IOEndpointTest, createTCPv6) {
EXPECT_EQ(IPPROTO_TCP, ep->getProtocol());
}
TEST(IOEndpointTest, equality) {
std::vector<const IOEndpoint *> epv;
epv.push_back(IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1234"), 5303));
epv.push_back(IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1234"), 5303));
epv.push_back(IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1234"), 5304));
epv.push_back(IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1234"), 5304));
epv.push_back(IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1235"), 5303));
epv.push_back(IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1235"), 5303));
epv.push_back(IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1235"), 5304));
epv.push_back(IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1235"), 5304));
epv.push_back(IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.1"), 5303));
epv.push_back(IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.1"), 5303));
epv.push_back(IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.1"), 5304));
epv.push_back(IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.1"), 5304));
epv.push_back(IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.2"), 5303));
epv.push_back(IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.2"), 5303));
epv.push_back(IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.2"), 5304));
epv.push_back(IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.2"), 5304));
for (size_t i = 0; i < epv.size(); ++i) {
for (size_t j = 0; j < epv.size(); ++j) {
if (i != j) {
// We use EXPECT_TRUE/FALSE instead of _EQ here, since
// _EQ requires there is an operator<< as well
EXPECT_FALSE(*epv[i] == *epv[j]);
EXPECT_TRUE(*epv[i] != *epv[j]);
}
}
}
// Create a second array with exactly the same values. We use create()
// again to make sure we get different endpoints
std::vector<const IOEndpoint *> epv2;
epv2.push_back(IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1234"), 5303));
epv2.push_back(IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1234"), 5303));
epv2.push_back(IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1234"), 5304));
epv2.push_back(IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1234"), 5304));
epv2.push_back(IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1235"), 5303));
epv2.push_back(IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1235"), 5303));
epv2.push_back(IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1235"), 5304));
epv2.push_back(IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1235"), 5304));
epv2.push_back(IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.1"), 5303));
epv2.push_back(IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.1"), 5303));
epv2.push_back(IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.1"), 5304));
epv2.push_back(IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.1"), 5304));
epv2.push_back(IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.2"), 5303));
epv2.push_back(IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.2"), 5303));
epv2.push_back(IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.2"), 5304));
epv2.push_back(IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.2"), 5304));
for (size_t i = 0; i < epv.size(); ++i) {
EXPECT_TRUE(*epv[i] == *epv2[i]);
EXPECT_FALSE(*epv[i] != *epv2[i]);
}
}
TEST(IOEndpointTest, createIPProto) {
EXPECT_THROW(IOEndpoint::create(IPPROTO_IP, IOAddress("192.0.2.1"),
53210)->getAddress().toText(),
......
......@@ -76,6 +76,7 @@ public:
// response handler methods in this class) receives the question sent by the
// fetch object.
uint8_t receive_buffer_[MAX_SIZE]; ///< Server receive buffer
OutputBufferPtr expected_buffer_; ///< Data we expect to receive
vector<uint8_t> send_buffer_; ///< Server send buffer
uint16_t send_cumulative_; ///< Data sent so far
......@@ -84,6 +85,11 @@ public:
string test_data_; ///< Large string - here for convenience
bool debug_; ///< true to enable debug output
size_t tcp_send_size_; ///< Max size of TCP send
uint8_t qid_0; ///< First octet of qid
uint8_t qid_1; ///< Second octet of qid
bool tcp_short_send_; ///< If set to true, we do not send
/// all data in the tcp response
/// \brief Constructor
IOFetchTest() :
......@@ -102,12 +108,16 @@ public:
cumulative_(0),
timer_(service_.get_io_service()),
receive_buffer_(),
expected_buffer_(new OutputBuffer(512)),
send_buffer_(),
send_cumulative_(0),
return_data_(""),
test_data_(""),
debug_(DEBUG),
tcp_send_size_(0)
tcp_send_size_(0),
qid_0(0),
qid_1(0),
tcp_short_send_(false)
{
// Construct the data buffer for question we expect to receive.
Message msg(Message::RENDER);
......@@ -118,6 +128,8 @@ public:
msg.addQuestion(question_);
MessageRenderer renderer(*msgbuf_);
msg.toWire(renderer);
MessageRenderer renderer2(*expected_buffer_);
msg.toWire(renderer2);
// Initialize the test data to be returned: tests will return a
// substring of this data. (It's convenient to have this as a member of
......@@ -144,9 +156,14 @@ public:
/// \param socket Socket to use to send the answer
/// \param ec ASIO error code, completion code of asynchronous I/O issued
/// by the "server" to receive data.
/// \param bad_qid If set to true, the QID in the response will be mangled
/// \param second_send If set to true, (and bad_qid is too), after the
/// mangled qid response has been sent, a second packet will be
/// sent with the correct QID.
/// \param length Amount of data received.
void udpReceiveHandler(udp::endpoint* remote, udp::socket* socket,
error_code ec = error_code(), size_t length = 0) {
error_code ec = error_code(), size_t length = 0,
bool bad_qid = false, bool second_send = false) {
if (debug_) {
cout << "udpReceiveHandler(): error = " << ec.value() <<
", length = " << length << endl;
......@@ -155,6 +172,8 @@ public:
// The QID in the incoming data is random so set it to 0 for the
// data comparison check. (It is set to 0 in the buffer containing
// the expected data.)
qid_0 = receive_buffer_[0];
qid_1 = receive_buffer_[1];
receive_buffer_[0] = receive_buffer_[1] = 0;
// Check that length of the received data and the expected data are
......@@ -164,10 +183,23 @@ public:
static_cast<const uint8_t*>(msgbuf_->getData())));
// Return a message back to the IOFetch object.
socket->send_to(asio::buffer(return_data_.c_str(), return_data_.size()),
*remote);
if (!bad_qid) {
expected_buffer_->writeUint8At(qid_0, 0);
expected_buffer_->writeUint8At(qid_1, 1);
} else {
expected_buffer_->writeUint8At(qid_0 + 1, 0);
expected_buffer_->writeUint8At(qid_1 + 1, 1);
}
socket->send_to(asio::buffer(expected_buffer_->getData(), length), *remote);
if (bad_qid && second_send) {
expected_buffer_->writeUint8At(qid_0, 0);
expected_buffer_->writeUint8At(qid_1, 1);
socket->send_to(asio::buffer(expected_buffer_->getData(),
expected_buffer_->getLength()), *remote);
}
if (debug_) {
cout << "udpReceiveHandler(): returned " << return_data_.size() <<
cout << "udpReceiveHandler(): returned " << expected_buffer_->getLength() <<
" bytes to the client" << endl;
}
}
......@@ -249,18 +281,25 @@ public:
// field the QID in the received buffer is in the third and fourth
// bytes.
EXPECT_EQ(msgbuf_->getLength() + 2, cumulative_);
qid_0 = receive_buffer_[2];
qid_1 = receive_buffer_[3];
receive_buffer_[2] = receive_buffer_[3] = 0;
EXPECT_TRUE(equal((receive_buffer_ + 2), (receive_buffer_ + cumulative_ - 2),
static_cast<const uint8_t*>(msgbuf_->getData())));
// ... and return a message back. This has to be preceded by a two-byte
// count field.
send_buffer_.clear();
send_buffer_.push_back(0);
send_buffer_.push_back(0);
writeUint16(return_data_.size(), &send_buffer_[0]);
copy(return_data_.begin(), return_data_.end(), back_inserter(send_buffer_));
if (return_data_.size() >= 2) {
send_buffer_[2] = qid_0;
send_buffer_[3] = qid_1;
}
// Send the data. This is done in multiple writes with a delay between
// each to check that the reassembly of TCP packets from fragments works.
send_cumulative_ = 0;
......@@ -298,10 +337,21 @@ public:
amount = min(tcp_send_size_,
(send_buffer_.size() - send_cumulative_));
}
if (debug_) {
cout << "tcpSendData(): sending " << amount << " bytes" << endl;
}
// This is for the short send test; reduce the actual amount of
// data we send
if (tcp_short_send_) {
if (debug_) {
cout << "tcpSendData(): sending incomplete data (" <<
(amount - 1) << " of " << amount << " bytes)" <<
endl;
}
--amount;
} else {
if (debug_) {
cout << "tcpSendData(): sending " << amount << " bytes" << endl;
}
}
// ... and send it. The amount sent is also passed as the first
// argument of the send callback, as a check.
......@@ -373,10 +423,23 @@ public:
// when one of the "servers" in this class has sent back return_data_.
// Check the data is as expected/
if (expected_ == IOFetch::SUCCESS) {
EXPECT_EQ(return_data_.size(), result_buff_->getLength());
const uint8_t* start = static_cast<const uint8_t*>(result_buff_->getData());
EXPECT_TRUE(equal(return_data_.begin(), return_data_.end(), start));
// In the case of UDP, we actually send back a real looking packet
// in the case of TCP, we send back a 'random' string
if (protocol_ == IOFetch::UDP) {
EXPECT_EQ(expected_buffer_->getLength(), result_buff_->getLength());
EXPECT_EQ(0, memcmp(expected_buffer_->getData(), result_buff_->getData(),
expected_buffer_->getLength()));
} else {
EXPECT_EQ(return_data_.size(), result_buff_->getLength());
// Overwrite the random qid with our own data for the
// comparison to succeed
if (result_buff_->getLength() >= 2) {
result_buff_->writeUint8At(return_data_[0], 0);
result_buff_->writeUint8At(return_data_[1], 1);
}
const uint8_t* start = static_cast<const uint8_t*>(result_buff_->getData());
EXPECT_TRUE(equal(return_data_.begin(), return_data_.end(), start));
}
}
// ... and cause the run loop to exit.
......@@ -452,13 +515,20 @@ public:
/// Send a query to the server then receives a response.
///
/// \param Test data to return to client
void tcpSendReturnTest(const std::string& return_data) {
/// \param short_send If true, do not send all data
/// (should result in timeout)
void tcpSendReturnTest(const std::string& return_data, bool short_send = false) {
if (debug_) {
cout << "tcpSendReturnTest(): data size = " << return_data.size() << endl;
}
return_data_ = return_data;
protocol_ = IOFetch::TCP;
expected_ = IOFetch::SUCCESS;
if (short_send) {
tcp_short_send_ = true;
expected_ = IOFetch::TIME_OUT;
} else {
expected_ = IOFetch::SUCCESS;
}
// Socket into which the connection will be accepted.
tcp::socket socket(service_.get_io_service());
......@@ -481,6 +551,39 @@ public:
// Tidy up
socket.close();
}
/// Perform a send/receive test over UDP
///
/// \param bad_qid If true, do the test where the QID is mangled
/// in the response
/// \param second_send If true, do the test where the QID is
/// mangled in the response, but a second
/// (correct) packet is used
void udpSendReturnTest(bool bad_qid, bool second_send) {
protocol_ = IOFetch::UDP;
// Set up the server.
udp::socket socket(service_.get_io_service(), udp::v4());
socket.set_option(socket_base::reuse_address(true));
socket.bind(udp::endpoint(TEST_HOST, TEST_PORT));
return_data_ = "Message returned to the client";
udp::endpoint remote;
socket.async_receive_from(asio::buffer(receive_buffer_, sizeof(receive_buffer_)),
remote,
boost::bind(&IOFetchTest::udpReceiveHandler, this, &remote, &socket,
_1, _2, bad_qid, second_send));
service_.get_io_service().post(udp_fetch_);
if (debug_) {
cout << "udpSendReceive: async_receive_from posted, waiting for callback" <<
endl;
}
service_.run();
socket.close();
EXPECT_TRUE(run_);;
}
};
// Check the protocol
......@@ -507,28 +610,25 @@ TEST_F(IOFetchTest, UdpTimeout) {
// UDP SendReceive test. Set up a UDP server then ports a UDP fetch object.
// This will send question_ to the server and receive the answer back from it.
TEST_F(IOFetchTest, UdpSendReceive) {
protocol_ = IOFetch::UDP;
expected_ = IOFetch::SUCCESS;
// Set up the server.
udp::socket socket(service_.get_io_service(), udp::v4());
socket.set_option(socket_base::reuse_address(true));
socket.bind(udp::endpoint(TEST_HOST, TEST_PORT));
return_data_ = "Message returned to the client";
udp::endpoint remote;
socket.async_receive_from(asio::buffer(receive_buffer_, sizeof(receive_buffer_)),
remote,
boost::bind(&IOFetchTest::udpReceiveHandler, this, &remote, &socket,
_1, _2));
service_.get_io_service().post(udp_fetch_);
if (debug_) {
cout << "udpSendReceive: async_receive_from posted, waiting for callback" <<
endl;
}
service_.run();
udpSendReturnTest(false, false);
socket.close();
EXPECT_TRUE(run_);;
}
TEST_F(IOFetchTest, UdpSendReceiveBadQid) {
expected_ = IOFetch::TIME_OUT;
udpSendReturnTest(true, false);