]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
Merge branch 'trac1237'
authorTomek Mrugalski <tomasz@isc.org>
Fri, 23 Dec 2011 12:52:12 +0000 (13:52 +0100)
committerTomek Mrugalski <tomasz@isc.org>
Fri, 23 Dec 2011 12:52:12 +0000 (13:52 +0100)
Conflicts:
ChangeLog
src/bin/dhcp4/dhcp4_srv.cc
src/bin/dhcp6/dhcp6_srv.cc
src/lib/dhcp/iface_mgr.cc
src/lib/dhcp/iface_mgr.h
src/lib/dhcp/tests/iface_mgr_unittest.cc

1  2 
ChangeLog
configure.ac
src/bin/dhcp6/dhcp6_srv.cc
src/lib/dhcp/iface_mgr.cc
src/lib/dhcp/iface_mgr.h
src/lib/dhcp/tests/iface_mgr_unittest.cc

diff --cc ChangeLog
index a88f9e107e71186a309f50644c6d9bc219b34fd8,5109c2692b89d0faf0b2b01bf166c5a66eb1d94f..ff15bf746b9b40ebc757caf1b2a73c07176763d1
+++ b/ChangeLog
@@@ -1,25 -1,8 +1,31 @@@
 -3XX.  [func]          tomek
++362.  [func]          tomek
+       libdhcp++: Interface detection in Linux implemented. libdhcp++
+       if now able to detect available network interfaces, its link-layer
+       addresses, flags and configured IPv4 and IPv6 addresses.
 -      (Trac #1237, git TBD)
++      (Trac #1237, git 8a040737426aece7cc92a795f2b712d7c3407513)
++
 +361.  [func]          tomek
 +      libdhcp++: Transmission and reception of DHCPv4 packets is now
 +      implemented. Low-level hacks are not implemented for transmission
 +      to hosts that don't have IPv4 address yet, so currently the code
 +      is usable for communication with relays only, not hosts on the
 +      same link.
 +      (Trac #1239, #1240, git f382050248b5b7ed1881b086d89be2d9dd8fe385)
 +
 +360.  [func]          fdupont
 +      Alpha version of DHCP benchmarking tool added.  "perfdhcp" is able to
 +      test both IPv4 and IPv6 servers: it can time the four-packet exchange
 +      (DORA and SARR) as well as time the initial two-packet exchange (DO and
 +      SA).  More information can be obtained by invoking the utility (in
 +      tests/tools/perfdhcp) with the "-h" flag.
 +      (Trac #1450, git 85083a76107ba2236732b45524ce7018eefbaf90)
 +
 +359.  [func]*         vorner
 +      The target parameter of ZoneFinder::find is no longer present, as the
 +      interface was awkward. To get all the RRsets of a single domain, use
 +      the new findAll method (the same applies to python version, the method
 +      is named find_all).
 +      (Trac #1483,#1484, git 0020456f8d118c9f3fd6fc585757c822b79a96f6)
  
  349.  [bug]           dvv
        resolver: If an upstream server responds with FORMERR to an EDNS query,
diff --cc configure.ac
Simple merge
index c559d8cbb38f8cab3e6c618d4ad7d287c69a50c8,9e77f8c54821e3d0ea63d5f37d62455d071e9214..7d1b549bdcbb47f265a1f5a58221177fde967d0a
@@@ -27,16 -27,28 +27,24 @@@ using namespace isc::dhcp
  using namespace isc::asiolink;
  
  Dhcpv6Srv::Dhcpv6Srv(uint16_t port) {
- //void Dhcpv6Srv::Dhcpv6Srv_impl(uint16_t port) {
      cout << "Initialization" << endl;
  
-     // First call to instance() will create IfaceMgr (it's a singleton).
-     // It may throw something if things go wrong.
-     IfaceMgr::instance();
+     // first call to instance() will create IfaceMgr (it's a singleton)
+     // it may throw something if things go wrong
+     try {
+       IfaceMgr::instance();
+     } catch (const std::exception &e) {
+       cout << "Failed to instantiate InterfaceManager:" << e.what() << ". Aborting." << endl;
+       shutdown = true;
+     }
+     if (IfaceMgr::instance().countIfaces() == 0) {
+       cout << "Failed to detect any network interfaces. Aborting." << endl;
+       shutdown = true;
+     }
  
      // Now try to open IPv6 sockets on detected interfaces.
 -    cout << "Opening sockets on port " << port << endl;
 -#if 0
 -    // uncomment this once #1238, #992 and #1239 are merged
      IfaceMgr::instance().openSockets6(port);
 -#endif
  
      /// @todo: instantiate LeaseMgr here once it is imlpemented.
  
index bb8981386d58b5d9873763a0327f7283b1be499c,2a8c0010a4f54fffad2bd8b8b6410f8c11802bda..c086e46fc3c0b87a54ac27356cd7817e47cd526c
@@@ -192,23 -194,17 +195,29 @@@ IfaceMgr::stubDetectIfaces() 
      }
  }
  
 -void IfaceMgr::openSockets6(uint16_t port) {
 -    int sock1, sock2;
+ #if !defined(OS_LINUX) && !defined(OS_BSD)
+ void IfaceMgr::detectIfaces() {
+     stubDetectIfaces();
+ }
+ #endif
 +bool IfaceMgr::openSockets4(uint16_t port) {
 +    int sock;
 +    int count = 0;
  
 -    for (IfaceCollection::iterator iface = ifaces_.begin();
 -         iface != ifaces_.end(); ++iface) {
 +    for (IfaceCollection::iterator iface=ifaces_.begin();
 +         iface!=ifaces_.end();
 +         ++iface) {
 +
 +        cout << "Trying interface " << iface->getFullName() << endl;
 +
 +#if 0
 +        if (iface->flag_loopback_ ||
 +            !iface->flag_up_ ||
 +            !iface->flag_running_) {
 +            continue;
 +        }
 +#endif
  
          AddressCollection addrs = iface->getAddresses();
  
               addr != addrs.end();
               ++addr) {
  
 -            sock1 = openSocket(iface->getName(), *addr, port);
 -            if (sock1 < 0) {
 -                isc_throw(Unexpected, "Failed to open unicast socket on "
 -                          << " interface " << iface->getFullName());
 +            // skip IPv4 addresses
 +            if (addr->getFamily() != AF_INET) {
 +                continue;
              }
  
 -            if ( !joinMulticast(sock1, iface->getName(),
 -                             string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
 -                close(sock1);
 +            sock = openSocket(iface->getName(), *addr, port);
 +            if (sock<0) {
 +                cout << "Failed to open unicast socket." << endl;
 +                return (false);
 +            }
 +
 +            count++;
 +        }
 +    }
 +    return (count > 0);
 +
 +}
 +
 +bool IfaceMgr::openSockets6(uint16_t port) {
 +    int sock;
 +    int count = 0;
 +
 +    for (IfaceCollection::iterator iface=ifaces_.begin();
 +         iface!=ifaces_.end();
 +         ++iface) {
 +
 +        AddressCollection addrs = iface->getAddresses();
 +
 +        for (AddressCollection::iterator addr= addrs.begin();
 +             addr != addrs.end();
 +             ++addr) {
 +
 +            // skip IPv4 addresses
 +            if (addr->getFamily() != AF_INET6) {
 +                continue;
 +            }
 +
 +            sock = openSocket(iface->getName(), *addr, port);
 +            if (sock<0) {
 +                cout << "Failed to open unicast socket." << endl;
 +                return (false);
 +            }
 +
-             if ( !joinMcast(sock, iface->getName(),
-                              string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
++            if ( !joinMulticast(sock, iface->getName(),
++                                string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
 +                close(sock);
                  isc_throw(Unexpected, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
                            << " multicast group.");
              }
index e937967045883a0e05a8dc1b97cc3171e81f5c41,39024b5a82f8025dafb23e9bdaf6d3391cd79bef..2cfd1ee5c64163e58ca07fb9a2195fac3ff95d6c
@@@ -308,14 -337,11 +340,19 @@@ public
      /// Is used in destructor, but also from Dhcpv4_srv and Dhcpv6_srv classes.
      void closeSockets();
  
 +    /// Opens IPv4 sockets on detected interfaces.
 +    /// Will throw exception if socket creation fails.
 +    ///
 +    /// @param port specifies port number (usually DHCP6_SERVER_PORT)
 +    ///
 +    /// @return true if any sockets were open
 +    bool openSockets4(uint16_t port = DHCP4_SERVER_PORT);
 +
+     /// @brief returns number of detected interfaces
+     ///
+     /// @return number of detected interfaces
+     uint16_t countIfaces() { return ifaces_.size(); }
      // don't use private, we need derived classes in tests
  protected:
  
index 9ccc55d1ab610b7eb943ff8d8c2133fb9cfedf22,9abbe1343be65eb3dc27d0b93f533e37d77e0bb6..f2d8016b8b5446b647a0dfd5f1ed4fb78d97471a
@@@ -151,9 -151,8 +151,10 @@@ TEST_F(IfaceMgrTest, dhcp6Sniffer) 
  
  TEST_F(IfaceMgrTest, basic) {
      // checks that IfaceManager can be instantiated
+     createLoInterfacesTxt();
  
 +    createLoInterfacesTxt();
 +
      IfaceMgr & ifacemgr = IfaceMgr::instance();
      ASSERT_TRUE(&ifacemgr != 0);
  }
@@@ -217,10 -217,10 +218,11 @@@ TEST_F(IfaceMgrTest, getIface) 
      EXPECT_EQ(static_cast<void*>(NULL), ifacemgr->getIface("wifi0") );
  
      delete ifacemgr;
 +
  }
  
- TEST_F(IfaceMgrTest, detectIfaces) {
+ #if !defined(OS_LINUX)
+ TEST_F(IfaceMgrTest, detectIfaces_stub) {
  
      // test detects that interfaces can be detected
      // there is no code for that now, but interfaces are
@@@ -368,93 -367,8 +369,92 @@@ TEST_F(IfaceMgrTest, sendReceive6) 
      EXPECT_TRUE( (rcvPkt->remote_port_ == 10546) || (rcvPkt->remote_port_ == 10547) );
  
      delete ifacemgr;
-     unlink(INTERFACE_FILE);
  }
  
 +TEST_F(IfaceMgrTest, sendReceive4) {
 +
 +    // testing socket operation in a portable way is tricky
 +    // without interface detection implemented
 +    createLoInterfacesTxt();
 +
 +    NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
 +
 +    // let's assume that every supported OS have lo interface
 +    IOAddress loAddr("127.0.0.1");
 +    int socket1 = 0, socket2 = 0;
 +    EXPECT_NO_THROW(
 +        socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, DHCP4_SERVER_PORT + 10000);
 +        socket2 = ifacemgr->openSocket(LOOPBACK, loAddr, DHCP4_SERVER_PORT + 10000 + 1);
 +    );
 +
 +    boost::shared_ptr<Pkt4> sendPkt(new Pkt4(DHCPDISCOVER, 1234) );
 +
 +    sendPkt->setLocalAddr(IOAddress("127.0.0.1"));
 +
 +    sendPkt->setLocalPort(DHCP4_SERVER_PORT + 10000 + 1);
 +    sendPkt->setRemotePort(DHCP4_SERVER_PORT + 10000);
 +    sendPkt->setRemoteAddr(IOAddress("127.0.0.1"));
 +    sendPkt->setIndex(1);
 +    sendPkt->setIface(string(LOOPBACK));
 +    sendPkt->setHops(6);
 +    sendPkt->setSecs(42);
 +    sendPkt->setCiaddr(IOAddress("192.0.2.1"));
 +    sendPkt->setSiaddr(IOAddress("192.0.2.2"));
 +    sendPkt->setYiaddr(IOAddress("192.0.2.3"));
 +    sendPkt->setGiaddr(IOAddress("192.0.2.4"));
 +
 +    uint8_t sname[] = "That's just a string that will act as SNAME";
 +    sendPkt->setSname(sname, strlen((const char*)sname));
 +    uint8_t file[] = "/another/string/that/acts/as/a/file_name.txt";
 +    sendPkt->setFile(file, strlen((const char*)file));
 +
 +    ASSERT_NO_THROW(
 +        sendPkt->pack();
 +    );
 +
 +    boost::shared_ptr<Pkt4> rcvPkt;
 +
 +    EXPECT_EQ(true, ifacemgr->send(sendPkt));
 +
 +    rcvPkt = ifacemgr->receive4();
 +
 +    ASSERT_TRUE( rcvPkt ); // received our own packet
 +
 +    ASSERT_NO_THROW(
 +        rcvPkt->unpack();
 +    );
 +
 +    // let's check that we received what was sent
 +    EXPECT_EQ(sendPkt->len(), rcvPkt->len());
 +
 +    EXPECT_EQ("127.0.0.1", rcvPkt->getRemoteAddr().toText());
 +    EXPECT_EQ(sendPkt->getRemotePort(), rcvPkt->getLocalPort());
 +
 +    // now let's check content
 +    EXPECT_EQ(sendPkt->getHops(), rcvPkt->getHops());
 +    EXPECT_EQ(sendPkt->getOp(),   rcvPkt->getOp());
 +    EXPECT_EQ(sendPkt->getSecs(), rcvPkt->getSecs());
 +    EXPECT_EQ(sendPkt->getFlags(), rcvPkt->getFlags());
 +    EXPECT_EQ(sendPkt->getCiaddr(), rcvPkt->getCiaddr());
 +    EXPECT_EQ(sendPkt->getSiaddr(), rcvPkt->getSiaddr());
 +    EXPECT_EQ(sendPkt->getYiaddr(), rcvPkt->getYiaddr());
 +    EXPECT_EQ(sendPkt->getGiaddr(), rcvPkt->getGiaddr());
 +    EXPECT_EQ(sendPkt->getTransid(), rcvPkt->getTransid());
 +    EXPECT_EQ(sendPkt->getType(), rcvPkt->getType());
 +    EXPECT_TRUE(sendPkt->getSname() == rcvPkt->getSname());
 +    EXPECT_TRUE(sendPkt->getFile() == rcvPkt->getFile());
 +    EXPECT_EQ(sendPkt->getHtype(), rcvPkt->getHtype());
 +    EXPECT_EQ(sendPkt->getHlen(), rcvPkt->getHlen());
 +
 +    // since we opened 2 sockets on the same interface and none of them is multicast,
 +    // none is preferred over the other for sending data, so we really should not
 +    // assume the one or the other will always be choosen for sending data. We should
 +    // skip checking source port of sent address.
 +
 +    delete ifacemgr;
 +}
 +
 +
  TEST_F(IfaceMgrTest, socket4) {
  
      createLoInterfacesTxt();