Commit d8dd6f7c authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[2231] Implemented sub-second timeouts for IfaceMgr::receiveX functions.

parent 7f11d6a7
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2012 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
......@@ -785,7 +785,7 @@ IfaceMgr::send(const Pkt4Ptr& pkt)
boost::shared_ptr<Pkt4>
IfaceMgr::receive4(uint32_t timeout) {
IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec) {
const SocketInfo* candidate = 0;
IfaceCollection::const_iterator iface;
......@@ -825,13 +825,12 @@ IfaceMgr::receive4(uint32_t timeout) {
names << session_socket_ << "(session)";
}
/// @todo: implement sub-second precision one day
struct timeval select_timeout;
select_timeout.tv_sec = timeout;
select_timeout.tv_usec = 0;
select_timeout.tv_sec = timeout_sec;
select_timeout.tv_usec = timeout_usec;
cout << "Trying to receive data on sockets: " << names.str()
<< ". Timeout is " << timeout << " seconds." << endl;
<< ". Timeout is " << timeout_sec << " seconds." << endl;
int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout);
cout << "select returned " << result << endl;
......@@ -953,7 +952,7 @@ IfaceMgr::receive4(uint32_t timeout) {
return (pkt);
}
Pkt6Ptr IfaceMgr::receive6(uint32_t timeout) {
Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec) {
const SocketInfo* candidate = 0;
fd_set sockets;
......@@ -994,12 +993,11 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout) {
}
cout << "Trying to receive data on sockets:" << names.str()
<< ".Timeout is " << timeout << " seconds." << endl;
<< ".Timeout is " << timeout_sec << " seconds." << endl;
/// @todo: implement sub-second precision one day
struct timeval select_timeout;
select_timeout.tv_sec = timeout;
select_timeout.tv_usec = 0;
select_timeout.tv_sec = timeout_sec;
select_timeout.tv_usec = timeout_usec;
int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout);
......
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2012 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
......@@ -345,10 +345,12 @@ public:
/// to not wait infinitely, but rather do something useful
/// (e.g. remove expired leases)
///
/// @param timeout specifies timeout (in seconds)
/// @param timeout_sec specifies integral part of the timeout (in seconds)
/// @param timeout_usec specifies fractional part of the timeout
/// (in microseconds)
///
/// @return Pkt6 object representing received packet (or NULL)
Pkt6Ptr receive6(uint32_t timeout);
Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec = 0);
/// @brief Tries to receive IPv4 packet over open IPv4 sockets.
///
......@@ -356,10 +358,12 @@ public:
/// If reception is successful and all information about its sender
/// are obtained, Pkt4 object is created and returned.
///
/// @param timeout specifies timeout (in seconds)
/// @param timeout_sec specifies integral part of the timeout (in seconds)
/// @param timeout_usec specifies fractional part of the timeout
/// (in microseconds)
///
/// @return Pkt4 object representing received packet (or NULL)
Pkt4Ptr receive4(uint32_t timeout);
Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec = 0);
/// Opens UDP/IP socket and binds it to address, interface and port.
///
......
......@@ -217,6 +217,112 @@ TEST_F(IfaceMgrTest, getIface) {
}
TEST_F(IfaceMgrTest, receiveTimeout6) {
std::cout << "Testing DHCPv6 packet reception timeouts."
<< " Test will block for a few seconds when waiting"
<< " for timeout to occur." << std::endl;
boost::scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
// Open socket on the lo interface.
IOAddress loAddr("::1");
int socket1 = 0;
ASSERT_NO_THROW(
socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547)
);
// Socket is open if its descriptor is greater than zero.
ASSERT_GT(socket1, 0);
// Time when call to IfaceMgr::receive6() started.
timeval start_time;
// Time when call to IfaceMgr::receive6() ended.
timeval stop_time;
// Remember when we call receive6().
gettimeofday(&start_time, NULL);
// Call receive with timeout of 1s + 1000us.
Pkt6Ptr pkt = ifacemgr->receive6(1, 1000);
// Remember when call to receive6() ended.
gettimeofday(&stop_time, NULL);
// We did not send a packet to lo interface so we expect that
// nothing has been received and timeout has been reached.
ASSERT_FALSE(pkt);
// Calculate duration of call to receive6().
stop_time.tv_sec -= start_time.tv_sec;
stop_time.tv_usec -= start_time.tv_usec;
// Duration should be equal or greater than timeout specified
// for the receive6() call.
EXPECT_EQ(stop_time.tv_sec, 1);
EXPECT_GT(stop_time.tv_usec, 1000);
// Test timeout shorter than 1s.
gettimeofday(&start_time, NULL);
pkt = ifacemgr->receive6(0, 500);
gettimeofday(&stop_time, NULL);
ASSERT_FALSE(pkt);
stop_time.tv_sec -= start_time.tv_sec;
stop_time.tv_usec -= start_time.tv_usec;
// The timeout has been set to 500us. Even though the way we measure
// duration of receive6() may result in durations slightly longer than
// timeout it is safe to assume that measured value will not exceed 1s
// when timeout is only 500us. If it exceeds, this is an error and
// should be investigated.
EXPECT_EQ(0, stop_time.tv_sec);
EXPECT_GT(stop_time.tv_usec, 500);
}
TEST_F(IfaceMgrTest, receiveTimeout4) {
std::cout << "Testing DHCPv6 packet reception timeouts."
<< " Test will block for a few seconds when waiting"
<< " for timeout to occur." << std::endl;
boost::scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
// Open socket on the lo interface.
IOAddress loAddr("127.0.0.1");
int socket1 = 0;
ASSERT_NO_THROW(
socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10067)
);
// Socket is open if its descriptor is greater than zero.
ASSERT_GT(socket1, 0);
// Time when call to IfaceMgr::receive4() started.
timeval start_time;
// Time when call to IfaceMgr::receive4() ended.
timeval stop_time;
// Remember when we call receive4().
gettimeofday(&start_time, NULL);
// Call receive with timeout of 2s + 150us.
Pkt4Ptr pkt = ifacemgr->receive4(2, 150);
// Remember when call to receive4() ended.
gettimeofday(&stop_time, NULL);
// We did not send a packet to lo interface so we expect that
// nothing has been received and timeout has been reached.
ASSERT_FALSE(pkt);
// Calculate duration of call to receive4().
stop_time.tv_sec -= start_time.tv_sec;
stop_time.tv_usec -= start_time.tv_usec;
// Duration should be equal or greater than timeout specified
// for the receive4() call.
EXPECT_EQ(stop_time.tv_sec, 2);
EXPECT_GT(stop_time.tv_usec, 150);
// Test timeout shorter than 1s.
gettimeofday(&start_time, NULL);
pkt = ifacemgr->receive4(0, 350);
gettimeofday(&stop_time, NULL);
ASSERT_FALSE(pkt);
stop_time.tv_sec -= start_time.tv_sec;
stop_time.tv_usec -= start_time.tv_usec;
// The timeout has been set to 350us. Even though the way we measure
// duration of receive4() may result in durations slightly longer than
// timeout it is safe to assume that measured value will not exceed 1s
// when timeout is only 350us. If it exceeds, this is an error and
// should be investigated.
EXPECT_EQ(0, stop_time.tv_sec);
EXPECT_GT(stop_time.tv_usec, 350);
}
TEST_F(IfaceMgrTest, sockets6) {
// testing socket operation in a portable way is tricky
// without interface detection implemented
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment