summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcp/tests/pkt_filter6_test_utils.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dhcp/tests/pkt_filter6_test_utils.cc')
-rw-r--r--src/lib/dhcp/tests/pkt_filter6_test_utils.cc206
1 files changed, 206 insertions, 0 deletions
diff --git a/src/lib/dhcp/tests/pkt_filter6_test_utils.cc b/src/lib/dhcp/tests/pkt_filter6_test_utils.cc
new file mode 100644
index 0000000..83afc1c
--- /dev/null
+++ b/src/lib/dhcp/tests/pkt_filter6_test_utils.cc
@@ -0,0 +1,206 @@
+// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <dhcp/pkt6.h>
+#include <dhcp/tests/pkt_filter6_test_utils.h>
+
+#include <boost/foreach.hpp>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+using namespace isc::asiolink;
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+PktFilter6Test::PktFilter6Test(const uint16_t port)
+ : port_(port),
+ sock_info_(isc::asiolink::IOAddress("::1"), port, -1, -1),
+ send_msg_sock_(-1) {
+ // Initialize ifname_ and ifindex_.
+ loInit();
+ // Initialize test_message_.
+ initTestMessage();
+}
+
+PktFilter6Test::~PktFilter6Test() {
+ // Cleanup after each test. This guarantees
+ // that the sockets do not hang after a test.
+ if (sock_info_.sockfd_ >= 0) {
+ close(sock_info_.sockfd_);
+ }
+ if (sock_info_.fallbackfd_ >=0) {
+ close(sock_info_.fallbackfd_);
+ }
+ if (send_msg_sock_ >= 0) {
+ close(send_msg_sock_);
+ }
+}
+
+void
+PktFilter6Test::initTestMessage() {
+ // Let's create a DHCPv6 message instance.
+ test_message_.reset(new Pkt6(DHCPV6_ADVERTISE, 123));
+
+ // Set required fields.
+ test_message_->setLocalAddr(IOAddress("::1"));
+ test_message_->setRemoteAddr(IOAddress("::1"));
+ test_message_->setRemotePort(port_);
+ test_message_->setLocalPort(port_ + 1);
+ test_message_->setIndex(ifindex_);
+ test_message_->setIface(ifname_);
+
+ try {
+ test_message_->pack();
+ } catch (const isc::Exception& ex) {
+ ADD_FAILURE() << "failed to create test message for PktFilter6Test";
+ }
+}
+
+void
+PktFilter6Test::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();
+
+ }
+}
+
+void
+PktFilter6Test::sendMessage() {
+ // DHCPv6 message will be sent over loopback interface.
+ Iface iface(ifname_, ifindex_);
+ IOAddress addr("::1");
+
+ // Initialize the source address and port.
+ struct sockaddr_in6 addr6;
+ memset(&addr6, 0, sizeof(addr6));
+ addr6.sin6_family = AF_INET6;
+ addr6.sin6_port = htons(port_);
+ memcpy(&addr6.sin6_addr, &addr.toBytes()[0], sizeof(addr6.sin6_addr));
+
+ // Open socket and bind to source address and port.
+ send_msg_sock_ = socket(AF_INET6, SOCK_DGRAM, 0);
+ ASSERT_GE(send_msg_sock_, 0);
+
+ ASSERT_GE(bind(send_msg_sock_, (struct sockaddr *)&addr6,
+ sizeof(addr6)), 0);
+
+ // Set the destination address and port.
+ struct sockaddr_in6 dest_addr6;
+ memset(&dest_addr6, 0, sizeof(sockaddr_in6));
+ dest_addr6.sin6_family = AF_INET6;
+ dest_addr6.sin6_port = htons(port_ + 1);
+ memcpy(&dest_addr6.sin6_addr, &addr.toBytes()[0], 16);
+
+ // Initialize the message header structure, required by sendmsg.
+ struct msghdr m;
+ memset(&m, 0, sizeof(m));
+ m.msg_name = &dest_addr6;
+ m.msg_namelen = sizeof(dest_addr6);
+ // The iovec structure holds the packet data.
+ struct iovec v;
+ memset(&v, 0, sizeof(v));
+ v.iov_base = const_cast<void *>(test_message_->getBuffer().getData());
+ v.iov_len = test_message_->getBuffer().getLength();
+ // Assign the iovec to msghdr structure.
+ m.msg_iov = &v;
+ m.msg_iovlen = 1;
+ // We should be able to send the whole message. The sendmsg function should
+ // return the number of bytes sent, which is equal to the size of our
+ // message.
+ ASSERT_EQ(sendmsg(send_msg_sock_, &m, 0),
+ test_message_->getBuffer().getLength());
+ close(send_msg_sock_);
+ send_msg_sock_ = -1;
+
+}
+
+void
+PktFilter6Test::testDgramSocket(const int sock) const {
+ // Check that socket has been opened.
+ ASSERT_GE(sock, 0);
+
+ // Verify that the socket belongs to AF_INET family.
+ sockaddr_in6 sock_address;
+ socklen_t sock_address_len = sizeof(sock_address);
+ ASSERT_EQ(0, getsockname(sock,
+ reinterpret_cast<sockaddr*>(&sock_address),
+ &sock_address_len));
+ EXPECT_EQ(AF_INET6, sock_address.sin6_family);
+
+ // Verify that the socket is bound the appropriate address.
+ char straddr[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET6, &sock_address.sin6_addr, straddr, sizeof(straddr));
+ std::string bind_addr(straddr);
+ EXPECT_EQ("::1", bind_addr);
+
+ // Verify that the socket is bound to appropriate port.
+ EXPECT_EQ(port_, ntohs(sock_address.sin6_port));
+
+ // Verify that the socket has SOCK_DGRAM type.
+ int sock_type;
+ socklen_t sock_type_len = sizeof(sock_type);
+ ASSERT_EQ(0, getsockopt(sock, SOL_SOCKET, SO_TYPE,
+ &sock_type, &sock_type_len));
+ EXPECT_EQ(SOCK_DGRAM, sock_type);
+}
+
+void
+PktFilter6Test::testRcvdMessage(const Pkt6Ptr& rcvd_msg) const {
+ // Currently, we don't send any payload in the message.
+ // Let's just check that the transaction id matches so as we
+ // are sure that we received the message that we expected.
+ EXPECT_EQ(test_message_->getTransid(), rcvd_msg->getTransid());
+}
+
+PktFilter6Stub::PktFilter6Stub()
+ : open_socket_count_ (0) {
+}
+
+SocketInfo
+PktFilter6Stub::openSocket(const Iface& iface, const isc::asiolink::IOAddress& addr,
+ const uint16_t port, const bool) {
+ // Check if there is any other socket bound to the specified address
+ // and port on this interface.
+ BOOST_FOREACH(SocketInfo socket, iface.getSockets()) {
+ if ((socket.addr_ == addr) && (socket.port_ == port)) {
+ isc_throw(SocketConfigError, "test socket bind error");
+ }
+ }
+ ++open_socket_count_;
+ return (SocketInfo(addr, port, 0));
+}
+
+Pkt6Ptr
+PktFilter6Stub::receive(const SocketInfo&) {
+ return Pkt6Ptr();
+}
+
+int
+PktFilter6Stub::send(const Iface&, uint16_t, const Pkt6Ptr&) {
+ return (0);
+}
+
+
+} // end of isc::dhcp::test namespace
+} // end of isc::dhcp namespace
+} // end of isc namespace