Commit 6df91c2d authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[1957] Implemented openSocketFromRemoteAddress method.

parent b8306189
......@@ -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) {
......
......@@ -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
......
......@@ -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;
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment