Browse Source

[2765] Implemented the logic which opens fallback a socket.

Marcin Siodelski 11 years ago
parent
commit
d0506dcfcf

+ 25 - 3
src/lib/dhcp/pkt_filter.cc

@@ -13,15 +13,37 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <config.h>
+#include <dhcp/iface_mgr.h>
 #include <dhcp/pkt_filter.h>
 
 namespace isc {
 namespace dhcp {
 
 int
-PktFilter::openFallbackSocket(const isc::asiolink::IOAddress&,
-                              const uint16_t) {
-    return (0);
+PktFilter::openFallbackSocket(const isc::asiolink::IOAddress& addr,
+                              const uint16_t port) {
+    // Create socket.
+    int sock = socket(AF_INET, SOCK_DGRAM, 0);
+    if (sock < 0) {
+        isc_throw(SocketConfigError, "failed to create fallback socket for address "
+                  << addr.toText() << ", port " << port);
+    }
+    // Bind the socket to a specified address and port.
+    struct sockaddr_in addr4;
+    memset(&addr4, 0, sizeof(addr4));
+    addr4.sin_family = AF_INET;
+    addr4.sin_addr.s_addr = htonl(addr);
+    addr4.sin_port = htons(port);
+
+    if (bind(sock, reinterpret_cast<struct sockaddr*>(&addr4), sizeof(addr4)) < 0) {
+        // Remember to close the socket if we failed to bind it.
+        close(sock);
+        isc_throw(SocketConfigError, "failed to bind fallback socket to address "
+                  << addr.toText() << ", port " << port << " - is another DHCP "
+                  "server running?");
+    }
+    // Successfully created and bound a fallback socket. Return a descriptor.
+    return (sock);
 }
 
 

+ 1 - 0
src/lib/dhcp/tests/Makefile.am

@@ -48,6 +48,7 @@ libdhcp___unittests_SOURCES += option_string_unittest.cc
 libdhcp___unittests_SOURCES += option_vendor_unittest.cc
 libdhcp___unittests_SOURCES += pkt4_unittest.cc
 libdhcp___unittests_SOURCES += pkt6_unittest.cc
+libdhcp___unittests_SOURCES += pkt_filter_unittest.cc
 libdhcp___unittests_SOURCES += pkt_filter_inet_unittest.cc
 libdhcp___unittests_SOURCES += pkt_filter_test_utils.h pkt_filter_test_utils.cc
 

+ 5 - 23
src/lib/dhcp/tests/pkt_filter_inet_unittest.cc

@@ -64,30 +64,12 @@ TEST_F(PktFilterInetTest, openSocket) {
     PktFilterInet pkt_filter;
     sock_info_ = pkt_filter.openSocket(iface, addr, PORT,
                                        false, false);
-    // Check that socket has been opened.
-    ASSERT_GE(sock_info_.sockfd_, 0);
+    // For the packet filter in use, the fallback socket shouldn't be opened.
+    // Fallback is typically opened for raw sockets.
+    EXPECT_LT(sock_info_.fallbackfd_, 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(sock_info_.sockfd_,
-                             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(sock_info_.sockfd_, SOL_SOCKET, SO_TYPE,
-                            &sock_type, &sock_type_len));
-    EXPECT_EQ(SOCK_DGRAM, sock_type);
+    // Test the primary socket.
+    testDgramSocket(sock_info_.sockfd_);
 }
 
 // This test verifies that the packet is correctly sent over the INET

+ 65 - 0
src/lib/dhcp/tests/pkt_filter_unittest.cc

@@ -0,0 +1,65 @@
+// 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/tests/pkt_filter_test_utils.h>
+#include <gtest/gtest.h>
+
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+using namespace isc::dhcp::test;
+
+namespace {
+
+/// Port number used by tests.
+const uint16_t PORT = 10067;
+
+class PktFilterBaseClassTest : public isc::dhcp::test::PktFilterTest {
+public:
+    /// @brief Constructor
+    ///
+    /// Does nothing but setting up the UDP port for the test.
+    PktFilterBaseClassTest() : PktFilterTest(PORT) {
+    }
+};
+
+// This test verifies that the fallback socket is successfuly opened and
+// bound using the protected function of the PktFilter class.
+TEST_F(PktFilterBaseClassTest, openFallbackSocket) {
+    // Open socket using the function under test. Note that, we don't have to
+    // close the socket on our own because the test fixture constructor
+    // will handle it.
+    PktFilterStub pkt_filter;
+    ASSERT_NO_THROW(sock_info_.fallbackfd_ =
+                    pkt_filter.openFallbackSocket(IOAddress("127.0.0.1"), PORT)
+    );
+    // Test that the socket has been successfully created.
+    testDgramSocket(sock_info_.fallbackfd_);
+
+    // Now that we have the socket open, let's try to open another one. This
+    // should cause a binding error.
+    int another_sock;
+    EXPECT_THROW(another_sock =
+                 pkt_filter.openFallbackSocket(IOAddress("127.0.0.1"), PORT),
+                 isc::dhcp::SocketConfigError);
+    // Hard to believe we managed to open another socket. But if so, we have
+    // to close it to prevent a resource leak.
+    if (another_sock >= 0) {
+        close(another_sock);
+    }
+}
+
+} // anonymous namespace