Commit 1f486ccd authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[2187] Throw exception in case of error when opening socket.

parent d863d2f2
......@@ -132,13 +132,7 @@ IfaceMgr::IfaceMgr()
detectIfaces();
} catch (const std::exception& ex) {
cout << "IfaceMgr creation failed:" << ex.what() << endl;
// TODO Uncomment this (or call LOG_FATAL) once
// interface detection is implemented. Otherwise
// it is not possible to run tests in a portable
// way (see detectIfaces() method).
throw;
isc_throw(IfaceDetectError, ex.what());
}
}
......@@ -164,45 +158,34 @@ void IfaceMgr::stubDetectIfaces() {
// is faked by detecting loopback interface (lo or lo0). It will eventually
// be removed once we have actual implementations for all supported systems.
try {
if (if_nametoindex("lo") > 0) {
ifaceName = "lo";
// this is Linux-like OS
} else if (if_nametoindex("lo0") > 0) {
ifaceName = "lo0";
// this is BSD-like OS
} else {
// we give up. What OS is this, anyway? Solaris? Hurd?
isc_throw(NotImplemented,
"Interface detection on this OS is not supported.");
}
Iface iface(ifaceName, if_nametoindex(ifaceName.c_str()));
iface.flag_up_ = true;
iface.flag_running_ = true;
// Note that we claim that this is not a loopback. iface_mgr tries to open a
// socket on all interaces that are up, running and not loopback. As this is
// the only interface we were able to detect, let's pretend this is a normal
// interface.
iface.flag_loopback_ = false;
iface.flag_multicast_ = true;
iface.flag_broadcast_ = true;
iface.setHWType(HWTYPE_ETHERNET);
iface.addAddress(IOAddress(v4addr));
iface.addAddress(IOAddress(v6addr));
addInterface(iface);
} catch (const std::exception& ex) {
// TODO: deallocate whatever memory we used
// not that important, since this function is going to be
// thrown away as soon as we get proper interface detection
// implemented
// TODO Do LOG_FATAL here
std::cerr << "Interface detection failed." << std::endl;
throw;
if (if_nametoindex("lo") > 0) {
ifaceName = "lo";
// this is Linux-like OS
} else if (if_nametoindex("lo0") > 0) {
ifaceName = "lo0";
// this is BSD-like OS
} else {
// we give up. What OS is this, anyway? Solaris? Hurd?
isc_throw(NotImplemented,
"Interface detection on this OS is not supported.");
}
Iface iface(ifaceName, if_nametoindex(ifaceName.c_str()));
iface.flag_up_ = true;
iface.flag_running_ = true;
// Note that we claim that this is not a loopback. iface_mgr tries to open a
// socket on all interaces that are up, running and not loopback. As this is
// the only interface we were able to detect, let's pretend this is a normal
// interface.
iface.flag_loopback_ = false;
iface.flag_multicast_ = true;
iface.flag_broadcast_ = true;
iface.setHWType(HWTYPE_ETHERNET);
iface.addAddress(IOAddress(v4addr));
iface.addAddress(IOAddress(v6addr));
addInterface(iface);
}
bool IfaceMgr::openSockets4(const uint16_t port) {
......@@ -231,15 +214,13 @@ bool IfaceMgr::openSockets4(const uint16_t port) {
sock = openSocket(iface->getName(), *addr, port);
if (sock < 0) {
cout << "Failed to open unicast socket." << endl;
return (false);
isc_throw(SocketConfigError, "failed to open unicast socket");
}
count++;
}
}
return (count > 0);
}
bool IfaceMgr::openSockets6(const uint16_t port) {
......@@ -268,8 +249,7 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
sock = openSocket(iface->getName(), *addr, port);
if (sock < 0) {
cout << "Failed to open unicast socket." << endl;
return (false);
isc_throw(SocketConfigError, "failed to open unicast socket");
}
// Binding socket to unicast address and then joining multicast group
......@@ -278,7 +258,8 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
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
isc_throw(SocketConfigError, "Failed to join "
<< ALL_DHCP_RELAY_AGENTS_AND_SERVERS
<< " multicast group.");
}
......@@ -293,7 +274,7 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
port);
if (sock2 < 0) {
isc_throw(Unexpected, "Failed to open multicast socket on "
isc_throw(SocketConfigError, "Failed to open multicast socket on "
<< " interface " << iface->getFullName());
iface->delSocket(sock); // delete previously opened socket
}
......@@ -406,7 +387,7 @@ int IfaceMgr::openSocketFromIface(const std::string& ifname,
family_name = "AF_INET6";
}
// We did not find address on the interface.
isc_throw(BadValue, "There is no address for interface: "
isc_throw(SocketConfigError, "There is no address for interface: "
<< ifname << ", port: " << port << ", address "
" family: " << family_name);
}
......@@ -448,9 +429,13 @@ int IfaceMgr::openSocketFromAddress(const IOAddress& addr,
int IfaceMgr::openSocketFromRemoteAddress(const IOAddress& remote_addr,
const uint16_t port) {
// Get local address to be used to connect to remote location.
IOAddress local_address(getLocalAddress(remote_addr, port).getAddress());
return openSocketFromAddress(local_address, port);
try {
// Get local address to be used to connect to remote location.
IOAddress local_address(getLocalAddress(remote_addr, port).getAddress());
return openSocketFromAddress(local_address, port);
} catch (const Exception& e) {
isc_throw(SocketConfigError, e.what());
}
}
isc::asiolink::IOAddress
......@@ -494,7 +479,7 @@ IfaceMgr::getLocalAddress(const IOAddress& remote_addr, const uint16_t port) {
sock.connect(remote_endpoint->getASIOEndpoint(), err_code);
if (err_code) {
sock.close();
isc_throw(Unexpected,"failed to connect to remote endpoint.");
isc_throw(Unexpected, "failed to connect to remote endpoint.");
}
// Once we are connected socket object holds local endpoint.
......@@ -522,12 +507,12 @@ int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, uint16_t port) {
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
isc_throw(Unexpected, "Failed to create UDP6 socket.");
isc_throw(SocketConfigError, "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()
isc_throw(SocketConfigError, "Failed to bind socket " << sock << " to " << addr.toText()
<< "/port=" << port);
}
......@@ -537,7 +522,7 @@ int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, uint16_t port) {
int flag = 1;
if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &flag, sizeof(flag)) != 0) {
close(sock);
isc_throw(Unexpected, "setsockopt: IP_PKTINFO: failed.");
isc_throw(SocketConfigError, "setsockopt: IP_PKTINFO: failed.");
}
#endif
......@@ -569,7 +554,7 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) {
// make a socket
int sock = socket(AF_INET6, SOCK_DGRAM, 0);
if (sock < 0) {
isc_throw(Unexpected, "Failed to create UDP6 socket.");
isc_throw(SocketConfigError, "Failed to create UDP6 socket.");
}
// Set the REUSEADDR option so that we don't fail to start if
......@@ -578,12 +563,12 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) {
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
(char *)&flag, sizeof(flag)) < 0) {
close(sock);
isc_throw(Unexpected, "Can't set SO_REUSEADDR option on dhcpv6 socket.");
isc_throw(SocketConfigError, "Can't set SO_REUSEADDR option on dhcpv6 socket.");
}
if (bind(sock, (struct sockaddr *)&addr6, sizeof(addr6)) < 0) {
close(sock);
isc_throw(Unexpected, "Failed to bind socket " << sock << " to " << addr.toText()
isc_throw(SocketConfigError, "Failed to bind socket " << sock << " to " << addr.toText()
<< "/port=" << port);
}
#ifdef IPV6_RECVPKTINFO
......@@ -591,14 +576,14 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) {
if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
&flag, sizeof(flag)) != 0) {
close(sock);
isc_throw(Unexpected, "setsockopt: IPV6_RECVPKTINFO failed.");
isc_throw(SocketConfigError, "setsockopt: IPV6_RECVPKTINFO failed.");
}
#else
// RFC2292 - an old way
if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
&flag, sizeof(flag)) != 0) {
close(sock);
isc_throw(Unexpected, "setsockopt: IPV6_PKTINFO: failed.");
isc_throw(SocketConfigError, "setsockopt: IPV6_PKTINFO: failed.");
}
#endif
......@@ -611,7 +596,7 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) {
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
isc_throw(SocketConfigError, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
<< " multicast group.");
}
}
......
......@@ -28,6 +28,38 @@
namespace isc {
namespace dhcp {
/// @brief IfaceMgr exception thrown thrown when interface detection fails.
class IfaceDetectError : public Exception {
public:
IfaceDetectError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
/// @brief IfaceMgr exception thrown thrown when socket opening
/// or configuration failed.
class SocketConfigError : public Exception {
public:
SocketConfigError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
/// @brief IfaceMgr exception thrown thrown when error occured during
/// reading data from socket.
class SocketReadError : public Exception {
public:
SocketReadError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
/// @brief IfaceMgr exception thrown thrown when error occured during
/// sedning data through socket.
class SocketWriteError : public Exception {
public:
SocketWriteError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
/// @brief handles network interfaces, transmission and reception
///
/// IfaceMgr is an interface manager class that detects available network
......@@ -460,6 +492,7 @@ public:
///
/// @param port specifies port number (usually DHCP6_SERVER_PORT)
///
/// @throw SocketOpenFailure if tried and failed to open socket.
/// @return true if any sockets were open
bool openSockets6(const uint16_t port = DHCP6_SERVER_PORT);
......@@ -472,6 +505,7 @@ public:
///
/// @param port specifies port number (usually DHCP4_SERVER_PORT)
///
/// @throw SocketOpenFailure if tried and failed to open socket.
/// @return true if any sockets were open
bool openSockets4(const uint16_t port = DHCP4_SERVER_PORT);
......
......@@ -419,7 +419,7 @@ TEST_F(IfaceMgrTest, sockets6) {
// testing socket operation in a portable way is tricky
// without interface detection implemented
NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
boost::scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
IOAddress loAddr("::1");
......@@ -439,10 +439,20 @@ TEST_F(IfaceMgrTest, sockets6) {
// removed code for binding socket twice to the same address/port
// as it caused problems on some platforms (e.g. Mac OS X)
close(socket1);
close(socket2);
ifacemgr->closeSockets();
delete ifacemgr;
// Use address that is not assigned to LOOPBACK iface.
IOAddress invalidAddr("::2");
EXPECT_THROW(
ifacemgr->openSocket(LOOPBACK, invalidAddr, 10547),
SocketConfigError
);
// Use non-existing interface name.
EXPECT_THROW(
ifacemgr->openSocket("non_existing_interface", loAddr, 10548),
BadValue
);
}
TEST_F(IfaceMgrTest, socketsFromIface) {
......@@ -466,6 +476,13 @@ TEST_F(IfaceMgrTest, socketsFromIface) {
EXPECT_GT(socket2, 0);
close(socket2);
ifacemgr->closeSockets();
// Use invalid interface name.
EXPECT_THROW(
ifacemgr->openSocketFromIface("non_existing_interface", PORT1, AF_INET),
BadValue
);
}
......@@ -480,7 +497,6 @@ TEST_F(IfaceMgrTest, socketsFromAddress) {
);
// socket descriptor must be positive integer
EXPECT_GT(socket1, 0);
close(socket1);
// Open v4 socket on loopback interface and bind to different port
int socket2 = 0;
......@@ -490,7 +506,14 @@ TEST_F(IfaceMgrTest, socketsFromAddress) {
);
// socket descriptor must be positive integer
EXPECT_GT(socket2, 0);
close(socket2);
ifacemgr->closeSockets();
// Use non-existing address.
IOAddress invalidAddr("1.2.3.4");
EXPECT_THROW(
ifacemgr->openSocketFromAddress(invalidAddr, PORT1), BadValue
);
}
TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
......@@ -505,7 +528,6 @@ TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
socket1 = ifacemgr->openSocketFromRemoteAddress(loAddr6, PORT1);
);
EXPECT_GT(socket1, 0);
close(socket1);
// Open v4 socket to connect to remote address.
int socket2 = 0;
......@@ -514,7 +536,8 @@ TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
socket2 = ifacemgr->openSocketFromRemoteAddress(loAddr, PORT2);
);
EXPECT_GT(socket2, 0);
close(socket2);
ifacemgr->closeSockets();
// The following test is currently disabled for OSes other than
// Linux because interface detection is not implemented on them.
......@@ -528,7 +551,6 @@ TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
socket3 = ifacemgr->openSocketFromRemoteAddress(bcastAddr, PORT2);
);
EXPECT_GT(socket3, 0);
close(socket3);
#endif
}
......
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