Parcourir la source

[1957] Implemented openSocketFromRemoteAddress method.

Marcin Siodelski il y a 13 ans
Parent
commit
6df91c2dc8
3 fichiers modifiés avec 131 ajouts et 31 suppressions
  1. 56 19
      src/lib/dhcp/iface_mgr.cc
  2. 57 6
      src/lib/dhcp/iface_mgr.h
  3. 18 6
      src/lib/dhcp/tests/iface_mgr_unittest.cc

+ 56 - 19
src/lib/dhcp/iface_mgr.cc

@@ -23,6 +23,9 @@
 #include <dhcp/dhcp6.h>
 #include <dhcp/iface_mgr.h>
 #include <exceptions/exceptions.h>
+#include <asio.hpp>
+#include <asiolink/udp_endpoint.h>
+#include <asio/error.hpp>
 #include <asiolink/io_error.h>
 #include <util/io/pktinfo_utilities.h>
 
@@ -279,7 +282,7 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
 
         AddressCollection addrs = iface->getAddresses();
 
-        for (AddressCollection::iterator addr= addrs.begin();
+        for (AddressCollection::iterator addr = addrs.begin();
              addr != addrs.end();
              ++addr) {
 
@@ -413,7 +416,6 @@ int IfaceMgr::openSocketFromIface(const std::string& ifname,
              addr != addrs.end();
              ++addr) {
 
-            // skip IPv4 addresses
             if (addr->getFamily() != family) {
                 continue;
             }
@@ -428,8 +430,8 @@ int IfaceMgr::openSocketFromIface(const std::string& ifname,
     return (sock);
 }
 
-int IfaceMgr::openSocketFromAddr(const std::string& addr_name,
-                                 const uint16_t port) {
+int IfaceMgr::openSocketFromAddress(const IOAddress& addr,
+                                    const uint16_t port) {
     int sock = 0;
     for (IfaceCollection::iterator iface=ifaces_.begin();
          iface!=ifaces_.end();
@@ -437,13 +439,12 @@ int IfaceMgr::openSocketFromAddr(const std::string& addr_name,
 
         AddressCollection addrs = iface->getAddresses();
 
-        for (AddressCollection::iterator addr = addrs.begin();
-             addr != addrs.end();
-             ++addr) {
+        for (AddressCollection::iterator addr_it = addrs.begin();
+             addr_it != addrs.end();
+             ++addr_it) {
 
             try {
-                IOAddress searched_addr(addr_name);
-                if (addr->getAddress() != searched_addr.getAddress()) {
+                if (addr_it->getAddress() != addr.getAddress()) {
                     continue;
                 }
             } catch (const isc::asiolink::IOError& e) {
@@ -452,26 +453,62 @@ int IfaceMgr::openSocketFromAddr(const std::string& addr_name,
                 return (sock);
             }
 
-            sock = openSocket(iface->getName(), *addr, port);
-            if (sock<0) {
+            sock = openSocket(iface->getName(), *addr_it, port);
+            if (sock < 0) {
                 cout << "Failed to open unicast socket." << endl;
             }
             return (sock);
         }
     }
     return (sock);
+}
+
+int IfaceMgr::openSocketFromRemoteAddress(const IOAddress& remote_addr,
+                                          const uint16_t port) {
+    int sock = 0;
+    IOAddress local_address(getLocalAddress(remote_addr, port).getAddress());
+
+    for (IfaceCollection::iterator iface=ifaces_.begin();
+         iface!=ifaces_.end();
+         ++iface) {
+
+        AddressCollection addrs = iface->getAddresses();
 
+        for (AddressCollection::iterator addr = addrs.begin();
+             addr != addrs.end();
+             ++addr) {
+
+            if (addr->getAddress() != local_address.getAddress()) {
+                continue;
+            }
+
+            sock = openSocket(iface->getName(), *addr, port);
+            if (sock < 0) {
+                cout << "Failed to open unicast socket." << endl;
+            }
+            return (sock);
+        }
+    }
+    return (sock);
 }
 
-int IfaceMgr::openSocketFromRemoteAddr(const std::string&,
-                                       const uint16_t,
-                                       const uint8_t) {
-    /*
-int IfaceMgr::openSocketFromRemoteAddr(const std::string& remote_addr_name,
-                                       const uint16_t port,
-                                       const uint8_t family) {*/
+isc::asiolink::IOAddress
+IfaceMgr::getLocalAddress(const IOAddress& remote_addr, const uint16_t port) {
+    boost::shared_ptr<const UDPEndpoint>
+        remote_endpoint(static_cast<const UDPEndpoint*>
+                        (UDPEndpoint::create(IPPROTO_UDP, remote_addr, port)));
+    asio::io_service io_service;
+    asio::ip::udp::socket sock(io_service);
+    asio::error_code err_code;
+    sock.connect(remote_endpoint->getASIOEndpoint(), err_code);
+    if (err_code) {
+        isc_throw(Unexpected,"Failed to connect to remote address.");
+    }
+
+    asio::ip::udp::socket::endpoint_type local_endpoint =  sock.local_endpoint();
+    asio::ip::address local_address(local_endpoint.address());
 
-    return 0;
+    return IOAddress(local_address);
 }
 
 int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, uint16_t port) {

+ 57 - 6
src/lib/dhcp/iface_mgr.h

@@ -373,16 +373,51 @@ public:
     /// @return socket descriptor, if socket creation, binding and multicast
     /// group join were all successful.
     int openSocket(const std::string& ifname,
-                   const isc::asiolink::IOAddress& addr, const uint16_t port);
+                   const isc::asiolink::IOAddress& addr,
+                   const uint16_t port);
 
-    int openSocketFromIface(const std::string& ifname, const uint16_t port,
+    /// @brief Opens UDP/IP socket and binds it to interface specified.
+    ///
+    /// This method differs from \ref openSocket such that it allows
+    /// not to specify local address to which socket will be bound.
+    /// Instead, method searches through addresses on specified
+    /// interface and selects one that matches address family.
+    ///
+    /// @param ifname name of the interface
+    /// @param addr address to be bound
+    /// @param port UDP port
+    /// @return socket descriptor, if socket creation, binding and multicast
+    /// group join were all successful.
+    int openSocketFromIface(const std::string& ifname,
+                            const uint16_t port,
                             const uint8_t family);
 
-    int openSocketFromAddr(const std::string& addr_name, const uint16_t port);
+    /// @brief Opens UDP/IP socket and binds to address specified
+    ///
+    /// This methods differs from \ref openSocket such that it allows
+    /// not to specify interface to which socket will be bound.
+    ///
+    /// @param addr address to be bound
+    /// @param port UDP port
+    /// @return socket descriptor, if socket creation, binding and multicast
+    /// group join were all successful.
+    int openSocketFromAddress(const isc::asiolink::IOAddress& addr,
+                              const uint16_t port);
+
+    /// @brief Opens UDP/IP socket to be used to connect to remote address
+    ///
+    /// This method identifies local address to be used to connect
+    /// to remote address specified as argument.
+    /// Once local address is idetified \ref openSocket is called
+    /// to open socket and bind it to interface, address and port.
+    ///
+    /// @param remote_addr remote address to connect to
+    /// @param port UDP port
+    /// @return socket descriptor, if socket creation, binding and multicast
+    /// group join were all successful.
+    int openSocketFromRemoteAddress(const isc::asiolink::IOAddress& remote_addr,
+                                    const uint16_t port);
 
-    int openSocketFromRemoteAddr(const std::string& remote_addr_name,
-                                 const uint16_t port,
-                                 const uint8_t family);
 
     /// Opens IPv6 sockets on detected interfaces.
     ///
@@ -537,6 +572,22 @@ private:
     joinMulticast(int sock, const std::string& ifname,
                   const std::string& mcast);
 
+    /// @brief Identifies local network address to be used to
+    /// connect to remote address.
+    ///
+    /// This method identifies local network address that can be used
+    /// to connect to remote address specified.
+    /// This method creates socket and makes attempt to connect
+    /// to remote location via this socket. If connection
+    /// is established successfully, the local address to which
+    /// socket is bound is returned.
+    ///
+    /// @param remote_addr remote address to connect to
+    /// @param port port to be used
+    /// @return local address to be used to connect to remote address
+    isc::asiolink::IOAddress
+    getLocalAddress(const isc::asiolink::IOAddress& remote_addr,
+                    const uint16_t port);
 };
 
 }; // namespace isc::dhcp

+ 18 - 6
src/lib/dhcp/tests/iface_mgr_unittest.cc

@@ -258,15 +258,17 @@ TEST_F(IfaceMgrTest, socketsFromIface) {
 }
 
 
-TEST_F(IfaceMgrTest, socketsFromAddr) {
+TEST_F(IfaceMgrTest, socketsFromAddress) {
     NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
 
     // open v6 socket on loopback address and bind to 10547 port
-    int socket1 = ifacemgr->openSocketFromAddr("::1", 10547);
+    IOAddress loAddr6("::1");
+    int socket1 = ifacemgr->openSocketFromAddress(loAddr6, 10547);
     EXPECT_GT(socket1, 0);
 
-    // open v4 socket on loopback address and bind to 10548 port
-    int socket2 = ifacemgr->openSocketFromAddr("127.0.0.1", 10548);
+    // open v4 socket on loopip::udp::socketback address and bind to 10548 port
+    IOAddress loAddr("127.0.0.1");
+    int socket2 = ifacemgr->openSocketFromAddress(loAddr, 10548);
     EXPECT_GT(socket2, 0);
 
     close(socket1);
@@ -275,13 +277,23 @@ TEST_F(IfaceMgrTest, socketsFromAddr) {
     delete ifacemgr;
 }
 
-TEST_F(IfaceMgrTest, socketsFromRemoteAddr) {
+TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
     NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
 
-    int socket1 = ifacemgr->openSocketFromRemoteAddr("::1", 10547, AF_INET6);
+    // Open v6 socket to connect to remote address.
+    // Loopback address is the only one that we know
+    // so let's treat it as remote address.
+    IOAddress loAddr6("::1");
+    int socket1 = ifacemgr->openSocketFromRemoteAddress(loAddr6, 10547);
     EXPECT_GT(socket1, 0);
 
+    // Open v4 socket to connect to remote address.
+    IOAddress loAddr("127.0.0.1");
+    int socket2 = ifacemgr->openSocketFromRemoteAddress(loAddr, 10548);
+    EXPECT_GT(socket2, 0);
+
     close(socket1);
+    close(socket2);
 
     delete ifacemgr;
 }