Browse Source

[1238] Socket binding for IPv4 implemented.

Tomek Mrugalski 13 years ago
parent
commit
d5e189cf15

+ 71 - 17
src/bin/dhcp6/iface_mgr.cc

@@ -250,17 +250,75 @@ IfaceMgr::openSocket(const std::string& ifname,
 
 
 uint16_t
 uint16_t
 IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, int port) {
 IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, int port) {
-    isc_throw(NotImplemented, "Sorry. Try again in 2 weeks");
-    cout << iface.getFullName() << addr.toText() << port; // just to disable unused warning
+
+    cout << "Creating UDP4 socket on " << iface.getFullName()
+         << " " << addr.toText() << "/port=" << port << endl;
+
+    struct sockaddr_in addr4;
+    memset(&addr4, 0, sizeof(sockaddr));
+    addr4.sin_family = AF_INET;
+    addr4.sin_port = htons(port);
+    memcpy(&addr4.sin_addr, addr.getAddress().to_v4().to_bytes().data(),
+           sizeof(addr4.sin_addr));
+
+    int sock = socket(AF_INET, SOCK_DGRAM, 0);
+    if (sock < 0) {
+        isc_throw(Unexpected, "Failed to create UDP6 socket.");
+    }
+
+    if (bind(sock, (struct sockaddr *)&addr4, sizeof(addr4)) < 0) {
+        close(sock);
+        isc_throw(Unexpected, "Failed to bind socket " << sock << " to " << addr.toText()
+                  << "/port=" << port);
+    }
+
+#if defined(SO_BINDTODEVICE)
+#if 0
+    /// For some reason that doesn't work. It's not a big deal as this is
+    /// Linux only feature. We can use IP_PKTINFO to check that we received
+    /// packet over proper interface.
+
+    // Bind this socket to this interface.
+    const char* ifname = iface.getName().c_str();
+    int len = strlen(ifname);
+    if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
+                   ifname, len) < 0) {
+        isc_throw(Unexpected, "setsockopt: SO_BINDTODEVICE failed.");
+    }
+#endif
+#endif
+
+    int flag = 1;
+#ifdef IP_RECVPKTINFO
+    if (setsockopt(sock, IPPROTO_IP, IP_RECVPKTINFO,
+                   &flag, sizeof(flag)) != 0) {
+        close(sock);
+        isc_throw(Unexpected, "setsockopt: IP_RECVPKTINFO failed.")
+    }
+#else
+    /* RFC2292 - an old way */
+    if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO,
+                   &flag, sizeof(flag)) != 0) {
+        close(sock);
+        isc_throw(Unexpected, "setsockopt: IP_PKTINFO: failed.");
+    }
+#endif
+
+
+    cout << "Created socket " << sock << " on " << iface.getName() << "/" <<
+        addr.toText() << "/port=" << port << endl;
+
+    // TODO: Add socket to iface interface
+    return (sock);
 }
 }
 
 
 uint16_t
 uint16_t
 IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
 IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
-    struct sockaddr_in6 addr6;
 
 
-    cout << "Creating socket on " << iface.getFullName()
-         << "/port=" << port << endl;
+    cout << "Creating UDP6 socket on " << iface.getFullName()
+         << " " << addr.toText() << "/port=" << port << endl;
 
 
+    struct sockaddr_in6 addr6;
     memset(&addr6, 0, sizeof(addr6));
     memset(&addr6, 0, sizeof(addr6));
     addr6.sin6_family = AF_INET6;
     addr6.sin6_family = AF_INET6;
     addr6.sin6_port = htons(port);
     addr6.sin6_port = htons(port);
@@ -278,8 +336,7 @@ IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
     // make a socket
     // make a socket
     int sock = socket(AF_INET6, SOCK_DGRAM, 0);
     int sock = socket(AF_INET6, SOCK_DGRAM, 0);
     if (sock < 0) {
     if (sock < 0) {
-        cout << "Failed to create UDP6 socket." << endl;
-        return (-1);
+        isc_throw(Unexpected, "Failed to create UDP6 socket.");
     }
     }
 
 
     /* Set the REUSEADDR option so that we don't fail to start if
     /* Set the REUSEADDR option so that we don't fail to start if
@@ -287,32 +344,28 @@ IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
     int flag = 1;
     int flag = 1;
     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
                    (char *)&flag, sizeof(flag)) < 0) {
                    (char *)&flag, sizeof(flag)) < 0) {
-        cout << "Can't set SO_REUSEADDR option on dhcpv6 socket." << endl;
         close(sock);
         close(sock);
-        return (-1);
+        isc_throw(Unexpected, "Can't set SO_REUSEADDR option on dhcpv6 socket.");
     }
     }
 
 
     if (bind(sock, (struct sockaddr *)&addr6, sizeof(addr6)) < 0) {
     if (bind(sock, (struct sockaddr *)&addr6, sizeof(addr6)) < 0) {
-        cout << "Failed to bind socket " << sock << " to " << addr.toText()
-             << "/port=" << port << endl;
         close(sock);
         close(sock);
-        return (-1);
+        isc_throw(Unexpected, "Failed to bind socket " << sock << " to " << addr.toText()
+                  << "/port=" << port);
     }
     }
 #ifdef IPV6_RECVPKTINFO
 #ifdef IPV6_RECVPKTINFO
     /* RFC3542 - a new way */
     /* RFC3542 - a new way */
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
                    &flag, sizeof(flag)) != 0) {
                    &flag, sizeof(flag)) != 0) {
-        cout << "setsockopt: IPV6_RECVPKTINFO failed." << endl;
         close(sock);
         close(sock);
-        return (-1);
+        isc_throw(Unexpected, "setsockopt: IPV6_RECVPKTINFO failed.");
     }
     }
 #else
 #else
     /* RFC2292 - an old way */
     /* RFC2292 - an old way */
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
                    &flag, sizeof(flag)) != 0) {
                    &flag, sizeof(flag)) != 0) {
-        cout << "setsockopt: IPV6_PKTINFO: failed." << endl;
         close(sock);
         close(sock);
-        return (-1);
+        isc_throw(Unexpected, "setsockopt: IPV6_PKTINFO: failed.");
     }
     }
 #endif
 #endif
 
 
@@ -326,7 +379,8 @@ IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
         if ( !joinMcast( sock, iface.getName(),
         if ( !joinMcast( sock, iface.getName(),
                          string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
                          string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
             close(sock);
             close(sock);
-            return (-1);
+            isc_throw(Unexpected, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
+                      << " multicast group.");
         }
         }
     }
     }
 
 

+ 0 - 3
src/bin/dhcp6/tests/Makefile.am

@@ -25,8 +25,6 @@ check-local:
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_builddir)/src/bin # for generated spec_config.h header
 AM_CPPFLAGS += -I$(top_builddir)/src/bin # for generated spec_config.h header
 AM_CPPFLAGS += -I$(top_srcdir)/src/bin
 AM_CPPFLAGS += -I$(top_srcdir)/src/bin
-AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
-AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_top_srcdir)/src/lib/testutils/testdata\"
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_top_srcdir)/src/lib/testutils/testdata\"
 AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/bin/dhcp6/tests\"
 AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/bin/dhcp6/tests\"
@@ -58,7 +56,6 @@ dhcp6_unittests_LDADD += $(SQLITE_LIBS)
 dhcp6_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
 dhcp6_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
 dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libdhcp.la
 dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libdhcp.la
 dhcp6_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 dhcp6_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-dhcp6_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
 endif
 endif
 
 
 noinst_PROGRAMS = $(TESTS)
 noinst_PROGRAMS = $(TESTS)

+ 32 - 11
src/bin/dhcp6/tests/iface_mgr_unittest.cc

@@ -20,9 +20,10 @@
 #include <arpa/inet.h>
 #include <arpa/inet.h>
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
-#include "io_address.h"
-#include "dhcp/pkt6.h"
-#include "dhcp6/iface_mgr.h"
+#include <asiolink/io_address.h>
+#include <dhcp/pkt6.h>
+#include <dhcp6/iface_mgr.h>
+#include <dhcp/dhcp4.h>
 
 
 using namespace std;
 using namespace std;
 using namespace isc;
 using namespace isc;
@@ -242,10 +243,6 @@ TEST_F(IfaceMgrTest, detectIfaces) {
     delete ifacemgr;
     delete ifacemgr;
 }
 }
 
 
-// TODO: disabled due to other naming on various systems
-// (lo in Linux, lo0 in BSD systems)
-// Fix for this is available on 1186 branch, will reenable
-// this test once 1186 is merged
 TEST_F(IfaceMgrTest, sockets6) {
 TEST_F(IfaceMgrTest, sockets6) {
     // testing socket operation in a portable way is tricky
     // testing socket operation in a portable way is tricky
     // without interface detection implemented
     // without interface detection implemented
@@ -285,7 +282,7 @@ TEST_F(IfaceMgrTest, sockets6) {
 
 
 // TODO: disabled due to other naming on various systems
 // TODO: disabled due to other naming on various systems
 // (lo in Linux, lo0 in BSD systems)
 // (lo in Linux, lo0 in BSD systems)
-TEST_F(IfaceMgrTest, sockets6Mcast) {
+TEST_F(IfaceMgrTest, DISABLED_sockets6Mcast) {
     // testing socket operation in a portable way is tricky
     // testing socket operation in a portable way is tricky
     // without interface detection implemented
     // without interface detection implemented
 
 
@@ -326,12 +323,15 @@ TEST_F(IfaceMgrTest, sendReceive6) {
     fakeifaces << LOOPBACK << " ::1";
     fakeifaces << LOOPBACK << " ::1";
     fakeifaces.close();
     fakeifaces.close();
 
 
-    NakedIfaceMgr * ifacemgr = new NakedIfaceMgr();
+    NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
 
 
     // let's assume that every supported OS have lo interface
     // let's assume that every supported OS have lo interface
     IOAddress loAddr("::1");
     IOAddress loAddr("::1");
-    int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
-    int socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10546);
+    int socket1 = 0, socket2 = 0;
+    EXPECT_NO_THROW(
+        socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
+        socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, 10546);
+    );
 
 
     ifacemgr->setSendSock(socket2);
     ifacemgr->setSendSock(socket2);
     ifacemgr->setRecvSock(socket1);
     ifacemgr->setRecvSock(socket1);
@@ -367,4 +367,25 @@ TEST_F(IfaceMgrTest, sendReceive6) {
     delete ifacemgr;
     delete ifacemgr;
 }
 }
 
 
+TEST_F(IfaceMgrTest, socket4) {
+
+    createLoInterfacesTxt();
+    NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
+
+    // let's assume that every supported OS have lo interface
+    IOAddress loAddr("127.0.0.1");
+    // use unprivileged port (it's convenient for running tests as non-root)
+    int socket1 = 0;
+
+    EXPECT_NO_THROW(
+        socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, DHCP4_SERVER_PORT + 10000);
+    );
+
+    EXPECT_GT(socket1, 0);
+
+    close(socket1);
+
+    delete ifacemgr;
+}
+
 }
 }