Browse Source

[4106] Improved IPC handler functions for DHCPv4 and DHCPv6 server.

Marcin Siodelski 9 years ago
parent
commit
b9d837a1f8

+ 21 - 5
src/bin/dhcp4/dhcp4_dhcp4o6_ipc.cc

@@ -48,20 +48,36 @@ void Dhcp4o6Ipc::open() {
 
 void Dhcp4o6Ipc::handler() {
     Dhcp4o6Ipc& ipc = Dhcp4o6Ipc::instance();
+
+    // Reset received message in case we return from this method before the
+    // received message pointer is updated.
+    ipc.received_.reset();
+
+    // Receive message from the IPC socket.
     Pkt6Ptr pkt = ipc.receive();
     if (!pkt) {
         return;
     }
 
+    // Each message must contain option holding DHCPv4 message.
     OptionCollection msgs = pkt->getOptions(D6O_DHCPV4_MSG);
-    if (msgs.size() != 1) {
-        return;
+    if (msgs.empty()) {
+        isc_throw(Dhcp4o6IpcError, "DHCPv4 message option not present in the"
+                  " DHCPv4o6 message received by the DHCPv4 server");
+
+    } else if (msgs.size() > 1) {
+        isc_throw(Dhcp4o6IpcError, "expected exactly one DHCPv4 message within"
+                  " DHCPv4 message option received by the DHCPv4 server");
     }
-    OptionPtr msg = pkt->getOption(D6O_DHCPV4_MSG);
+
+    OptionPtr msg = msgs.begin()->second;
     if (!msg) {
-        isc_throw(Unexpected, "Can't get DHCPv4 message option");
+        isc_throw(Dhcp4o6IpcError, "null DHCPv4 message option in the"
+                  " DHCPv4o6 message received by the DHCPv4 server");
     }
-    instance().received_.reset(new Pkt4o6(msg->getData(), pkt));
+
+    // Record this message.
+    ipc.received_.reset(new Pkt4o6(msg->getData(), pkt));
 }
 
 Pkt4o6Ptr& Dhcp4o6Ipc::getReceived() {

+ 8 - 1
src/bin/dhcp6/dhcp6_dhcp4o6_ipc.cc

@@ -46,23 +46,30 @@ void Dhcp4o6Ipc::open() {
 }
 
 void Dhcp4o6Ipc::handler() {
+    std::cout << "handler" << std::endl;
     Dhcp4o6Ipc& ipc = Dhcp4o6Ipc::instance();
+
+    // Receive message from IPC.
     Pkt6Ptr pkt = ipc.receive();
     if (!pkt) {
         return;
     }
 
+    // The received message has been unpacked by the receive() function. This
+    // method could have modified the message so it's better to pack() it
+    // again because we'll be forwarding it to a client.
     isc::util::OutputBuffer& buf = pkt->getBuffer();
     buf.clear();
     pkt->pack();
 
-    uint8_t msg_type = buf[0];
+    uint8_t msg_type = pkt->getType();
     if ((msg_type == DHCPV6_RELAY_FORW) || (msg_type == DHCPV6_RELAY_REPL)) {
         pkt->setRemotePort(DHCP6_SERVER_PORT);
     } else {
         pkt->setRemotePort(DHCP6_CLIENT_PORT);
     }
 
+    // Forward packet to the client.
     IfaceMgr::instance().send(pkt);
     // processStatsSent(pkt);
 }

+ 1 - 0
src/bin/dhcp6/tests/dhcp6_dhcp4o6_ipc_unittest.cc

@@ -111,6 +111,7 @@ TEST_F(Dhcp4o6IpcTest, receive) {
     ASSERT_NO_THROW(src_ipc.send(pkt));
     ASSERT_NO_THROW(IfaceMgr::instance().receive6(1, 0));
 
+
     // The stub packet filter exposes static function to retrieve messages
     // sent over the fake sockets/interfaces. This is the message that the
     // IPC endpoint should forward to the client after receiving it

+ 39 - 1
src/lib/dhcp/tests/pkt_filter6_test_stub.cc

@@ -13,7 +13,9 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <config.h>
+#include <exceptions/exceptions.h>
 #include <dhcp/tests/pkt_filter6_test_stub.h>
+#include <netinet/in.h>
 #include <list>
 
 namespace {
@@ -38,7 +40,43 @@ SocketInfo
 PktFilter6TestStub::openSocket(const Iface&,
            const isc::asiolink::IOAddress& addr,
            const uint16_t port, const bool) {
-    return (SocketInfo(addr, port, 0));
+    // Create a socket which may be used on select() but which is unlikely
+    // to return any data.
+    int sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+    if (sock < 0) {
+        isc_throw(Unexpected, "PktFilter6TestStub: opening socket failed");
+    }
+
+    // Set reuse address
+    int flag = 1;
+    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, static_cast<const void*>(&flag),
+                   sizeof(flag)) < 0) {
+        ::close(sock);
+        isc_throw(Unexpected, "PktFilter6TestStub:: failed to set SO_REUSEADDR on"
+                  " socket");
+    }
+
+    // Set no blocking
+    if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+        ::close(sock);
+        isc_throw(Unexpected, "PktFilter6TestStub: failed to set O_NONBLOCK on"
+                  " socket");
+    }
+
+    // Bind to the local address and random port.
+    struct sockaddr_in6 local6;
+    memset(&local6, 0, sizeof(local6));
+    local6.sin6_family = AF_INET6;
+#ifdef HAVE_SA_LEN
+    local6.sin6_len = sizeof(local6);
+#endif
+
+    if (bind(sock, (struct sockaddr *)&local6, sizeof(local6)) < 0) {
+        ::close(sock);
+        isc_throw(Unexpected, "PktFilter6TestStub: failed to bind socket");
+    }
+
+    return (SocketInfo(addr, port, sock));
 }
 
 Pkt6Ptr

+ 4 - 6
src/lib/dhcp/tests/pkt_filter6_test_stub.h

@@ -36,11 +36,10 @@ public:
     /// @brief Constructor.
     PktFilter6TestStub();
 
-    /// @brief Simulate opening of the socket.
+    /// @brief Open a socket.
     ///
-    /// This function simulates opening a primary socket. In reality, it doesn't
-    /// open a socket but the socket descriptor returned in the SocketInfo
-    /// structure is always set to 0.
+    /// This function opens a socket. This socket is bound to any address
+    /// and port. The select() function may be called on this socket.
     ///
     /// @param iface An interface descriptor.
     /// @param addr Address on the interface to be used to send packets.
@@ -50,8 +49,7 @@ public:
     ///
     /// @note All parameters are ignored.
     ///
-    /// @return A SocketInfo structure with the socket descriptor set to 0. The
-    /// fallback socket descriptor is set to a negative value.
+    /// @return A SocketInfo structure with the socket descriptor.
     virtual SocketInfo openSocket(const Iface& iface,
                                   const isc::asiolink::IOAddress& addr,
                                   const uint16_t port,