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

[2902] Test sending packet over INET DGRAM socket.

parent b91e4297
......@@ -16,6 +16,7 @@
#define PKT_FILTER_INET_H
#include <dhcp/pkt_filter.h>
#include <boost/scoped_array.hpp>
namespace isc {
namespace dhcp {
......
......@@ -43,6 +43,7 @@ libdhcp___unittests_SOURCES += option_unittest.cc
libdhcp___unittests_SOURCES += option_space_unittest.cc
libdhcp___unittests_SOURCES += pkt4_unittest.cc
libdhcp___unittests_SOURCES += pkt6_unittest.cc
libdhcp___unittests_SOURCES += pkt_filter_inet_unittest.cc
libdhcp___unittests_SOURCES += protocol_util_unittest.cc
libdhcp___unittests_SOURCES += duid_unittest.cc
......
......@@ -105,7 +105,7 @@ class NakedIfaceMgr: public IfaceMgr {
// "naked" Interface Manager, exposes internal fields
public:
NakedIfaceMgr() {
setPacketFilter(PktFilterPtr(new PktFilterLPF()));
// setPacketFilter(PktFilterPtr(new PktFilterLPF()));
}
IfaceCollection & getIfacesLst() { return ifaces_; }
};
......
// Copyright (C) 2013 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.
#include <config.h>
#include <asiolink/io_address.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt_filter_inet.h>
#include <gtest/gtest.h>
#include <sys/socket.h>
using namespace isc::asiolink;
using namespace isc::dhcp;
namespace {
const uint16_t PORT = 10067;
const size_t RECV_BUF_SIZE = 2048;
class PktFilterInetTest : public ::testing::Test {
public:
PktFilterInetTest() {
// Initialize ifname_ and ifindex_.
loInit();
}
~PktFilterInetTest() {
// Cleanup after each test. This guarantees
// that the socket does not hang after a test.
close(socket_);
}
/// @brief Detect loopback interface.
///
/// @todo this function will be removed once cross-OS interface
/// detection is implemented
void loInit() {
if (if_nametoindex("lo") > 0) {
ifname_ = "lo";
ifindex_ = if_nametoindex("lo");
} else if (if_nametoindex("lo0") > 0) {
ifname_ = "lo0";
ifindex_ = if_nametoindex("lo0");
} else {
std::cout << "Failed to detect loopback interface. Neither "
<< "lo nor lo0 worked. Giving up." << std::endl;
FAIL();
}
}
std::string ifname_; ///< Loopback interface name
uint16_t ifindex_; ///< Loopback interface index.
int socket_; ///< Socket descriptor.
};
// This test verifies that the INET datagram socket is correctly opened and
// bound to the appropriate address and port.
TEST_F(PktFilterInetTest, openSocket) {
// Create object representing loopback interface.
Iface iface(ifname_, ifindex_);
// Set loopback address.
IOAddress addr("127.0.0.1");
// Try to open socket.
PktFilterInet pkt_filter;
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
// Check that socket has been opened.
ASSERT_GE(socket_, 0);
// Verify that the socket belongs to AF_INET family.
sockaddr_in sock_address;
socklen_t sock_address_len = sizeof(sock_address);
ASSERT_EQ(0, getsockname(socket_, reinterpret_cast<sockaddr*>(&sock_address),
&sock_address_len));
EXPECT_EQ(AF_INET, sock_address.sin_family);
// Verify that the socket is bound the appropriate address.
const std::string bind_addr(inet_ntoa(sock_address.sin_addr));
EXPECT_EQ("127.0.0.1", bind_addr);
// Verify that the socket is bound to appropriate port.
EXPECT_EQ(PORT, ntohs(sock_address.sin_port));
// Verify that the socket has SOCK_DGRAM type.
int sock_type;
socklen_t sock_type_len = sizeof(sock_type);
ASSERT_EQ(0, getsockopt(socket_, SOL_SOCKET, SO_TYPE, &sock_type, &sock_type_len));
EXPECT_EQ(SOCK_DGRAM, sock_type);
}
// This test verifies that the packet is correctly sent over the INET
// datagram socket.
TEST_F(PktFilterInetTest, send) {
// Let's create a DHCPv4 packet.
Pkt4Ptr pkt(new Pkt4(DHCPOFFER, 0));
ASSERT_TRUE(pkt);
// Set required fields.
pkt->setLocalAddr(IOAddress("127.0.0.1"));
pkt->setRemotePort(PORT);
pkt->setLocalPort(PORT + 1);
pkt->setIndex(ifindex_);
pkt->setIface(ifname_);
pkt->setHops(6);
pkt->setSecs(42);
pkt->setCiaddr(IOAddress("192.0.2.1"));
pkt->setSiaddr(IOAddress("192.0.2.2"));
pkt->setYiaddr(IOAddress("192.0.2.3"));
pkt->setGiaddr(IOAddress("192.0.2.4"));
// Create the on-wire data.
ASSERT_NO_THROW(pkt->pack());
// Packet will be sent over loopback interface.
Iface iface(ifname_, ifindex_);
IOAddress addr("127.0.0.1");
// Create an instance of the class which we are testing.
PktFilterInet pkt_filter;
// Open socket. We don't check that the socket has appropriate
// options and family set because we have checked that in the
// openSocket test already.
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
ASSERT_GE(socket_, 0);
// Send the packet over the socket.
ASSERT_NO_THROW(pkt_filter.send(iface, socket_, pkt));
// Read the data from socket.
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(socket_, &readfds);
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
int result = select(socket_ + 1, &readfds, NULL, NULL, &timeout);
// We should receive some data from loopback interface.
ASSERT_GT(result, 0);
// Get the actual data.
uint8_t rcv_buf[RECV_BUF_SIZE];
result = recv(socket_, rcv_buf, RECV_BUF_SIZE, 0);
ASSERT_GT(result, 0);
// Create the DHCPv4 packet from the received data.
Pkt4Ptr rcvd_pkt(new Pkt4(rcv_buf, result));
ASSERT_TRUE(rcvd_pkt);
// Parse the packet.
ASSERT_NO_THROW(rcvd_pkt->unpack());
// Verify that the received packet matches sent packet.
EXPECT_EQ(pkt->getHops(), rcvd_pkt->getHops());
EXPECT_EQ(pkt->getOp(), rcvd_pkt->getOp());
EXPECT_EQ(pkt->getSecs(), rcvd_pkt->getSecs());
EXPECT_EQ(pkt->getFlags(), rcvd_pkt->getFlags());
EXPECT_EQ(pkt->getCiaddr(), rcvd_pkt->getCiaddr());
EXPECT_EQ(pkt->getSiaddr(), rcvd_pkt->getSiaddr());
EXPECT_EQ(pkt->getYiaddr(), rcvd_pkt->getYiaddr());
EXPECT_EQ(pkt->getGiaddr(), rcvd_pkt->getGiaddr());
EXPECT_EQ(pkt->getTransid(), rcvd_pkt->getTransid());
EXPECT_TRUE(pkt->getSname() == rcvd_pkt->getSname());
EXPECT_TRUE(pkt->getFile() == rcvd_pkt->getFile());
EXPECT_EQ(pkt->getHtype(), rcvd_pkt->getHtype());
EXPECT_EQ(pkt->getHlen(), rcvd_pkt->getHlen());
}
} // anonymous namespace
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