void
Iface::closeSockets() {
- for (SocketCollection::iterator sock = sockets_.begin();
- sock != sockets_.end(); ++sock) {
- close(sock->sockfd_);
+ // Close IPv4 sockets.
+ closeSockets(AF_INET);
+ // Close IPv6 sockets.
+ closeSockets(AF_INET6);
+}
+
+void
+Iface::closeSockets(const uint16_t family) {
+ // Check that the correect 'family' value has been specified.
+ // The possible values are AF_INET or AF_INET6. Note that, in
+ // the current code they are used to differentiate that the
+ // socket is used to transmit IPv4 or IPv6 traffic. However,
+ // the actual family types of the sockets may be different,
+ // e.g. for LPF we are using raw sockets of AF_PACKET family.
+ //
+ // @todo Consider replacing the AF_INET and AF_INET6 with some
+ // enum which will not be confused with the actual socket type.
+ if ((family != AF_INET) && (family != AF_INET6)) {
+ isc_throw(BadValue, "Invalid socket family " << family
+ << " specified when requested to close all sockets"
+ << " which belong to this family");
+ }
+ // Search for the socket of the specific type.
+ SocketCollection::iterator sock = sockets_.begin();
+ while (sock != sockets_.end()) {
+ if (sock->family_ == family) {
+ // Close and delete the socket and move to the
+ // next one.
+ close(sock->sockfd_);
+ sockets_.erase(sock++);
+
+ } else {
+ // Different type of socket. Let's move
+ // to the next one.
+ ++sock;
+
+ }
}
- sockets_.clear();
}
std::string
}
}
+void
+IfaceMgr::closeSockets(const uint16_t family) {
+ for (IfaceCollection::iterator iface = ifaces_.begin();
+ iface != ifaces_.end(); ++iface) {
+ iface->closeSockets(family);
+ }
+}
+
IfaceMgr::~IfaceMgr() {
// control_buf_ is deleted automatically (scoped_ptr)
control_buf_len_ = 0;
/// @brief Closes all open sockets on interface.
void closeSockets();
+ /// @brief Closes all IPv4 or IPv6 sockets.
+ ///
+ /// This function closes sockets of the specific 'type' and closes them.
+ /// The 'type' of the socket indicates whether it is used to send IPv4
+ /// or IPv6 packets. The allowed values of the parameter are AF_INET and
+ /// AF_INET6 for IPv4 and IPv6 packets respectively. It is important
+ /// to realize that the actual types of sockets may be different than
+ /// AF_INET for IPv4 packets. This is because, historically the IfaceMgr
+ /// always used AF_INET sockets for IPv4 traffic. This is no longer the
+ /// case when the Direct IPv4 traffic must be supported. In order to support
+ /// direct traffic, the IfaceMgr operates on raw sockets, e.g. AF_PACKET
+ /// family sockets on Linux.
+ ///
+ /// @todo Replace the AF_INET and AF_INET6 values with an enum
+ /// which will not be confused with the actual socket type.
+ ///
+ /// @param family type of the sockets to be closed (AF_INET or AF_INET6)
+ ///
+ /// @throw BadValue if family value is different than AF_INET or AF_INET6.
+ void closeSockets(const uint16_t family);
+
/// @brief Returns full interface name as "ifname/ifindex" string.
///
/// @return string with interface name
/// flag specifies if selected interface is multicast capable
bool flag_multicast_;
- /// flag specifies if selected interface is broadcast capable
+ /// flag specifies if selected interface is broadcast capable
bool flag_broadcast_;
/// interface flags (this value is as is returned by OS,
/// Is used in destructor, but also from Dhcpv4_srv and Dhcpv6_srv classes.
void closeSockets();
+ /// @brief Closes all IPv4 or IPv6 sockets.
+ ///
+ /// This function closes sockets of the specific 'type' and closes them.
+ /// The 'type' of the socket indicates whether it is used to send IPv4
+ /// or IPv6 packets. The allowed values of the parameter are AF_INET and
+ /// AF_INET6 for IPv4 and IPv6 packets respectively. It is important
+ /// to realize that the actual types of sockets may be different than
+ /// AF_INET for IPv4 packets. This is because, historically the IfaceMgr
+ /// always used AF_INET sockets for IPv4 traffic. This is no longer the
+ /// case when the Direct IPv4 traffic must be supported. In order to support
+ /// direct traffic, the IfaceMgr operates on raw sockets, e.g. AF_PACKET
+ /// family sockets on Linux.
+ ///
+ /// @todo Replace the AF_INET and AF_INET6 values with an enum
+ /// which will not be confused with the actual socket type.
+ ///
+ /// @param family type of the sockets to be closed (AF_INET or AF_INET6)
+ ///
+ /// @throw BadValue if family value is different than AF_INET or AF_INET6.
+ void closeSockets(const uint16_t family);
+
/// @brief returns number of detected interfaces
///
/// @return number of detected interfaces
~IfaceMgrTest() {
}
+ // Get ther number of IPv4 or IPv6 sockets on the loopback interface
+ int getOpenSocketsCount(const Iface& iface, uint16_t family) const {
+ // Get all sockets.
+ Iface::SocketCollection sockets = iface.getSockets();
+
+ // Loop through sockets and try to find the ones which match the
+ // specified type.
+ int sockets_count = 0;
+ for (Iface::SocketCollection::const_iterator sock = sockets.begin();
+ sock != sockets.end(); ++sock) {
+ // Match found, increase the counter.
+ if (sock->family_ == family) {
+ ++sockets_count;
+ }
+ }
+ return (sockets_count);
+ }
+
};
// We need some known interface to work reliably. Loopback interface
ASSERT_TRUE(&ifacemgr != 0);
}
+
+// This test verifies that sockets can be closed selectively, i.e. all
+// IPv4 sockets can be closed first and all IPv6 sockets remain open.
+TEST_F(IfaceMgrTest, closeSockets) {
+ // Will be using local loopback addresses for this test.
+ IOAddress loaddr("127.0.0.1");
+ IOAddress loaddr6("::1");
+
+ // Create instance of IfaceMgr.
+ boost::scoped_ptr<NakedIfaceMgr> iface_mgr(new NakedIfaceMgr());
+ ASSERT_TRUE(iface_mgr);
+
+ // Out constructor does not detect interfaces by itself. We need
+ // to create one and add.
+ int ifindex = if_nametoindex(LOOPBACK);
+ ASSERT_GT(ifindex, 0);
+ Iface lo_iface(LOOPBACK, ifindex);
+ iface_mgr->getIfacesLst().push_back(lo_iface);
+
+ // Create set of V4 and V6 sockets on the loopback interface.
+ // They must differ by a port they are bound to.
+ for (int i = 0; i < 6; ++i) {
+ // Every other socket will be IPv4.
+ if (i % 2) {
+ ASSERT_NO_THROW(
+ iface_mgr->openSocket(LOOPBACK, loaddr, 10000 + i)
+ );
+ } else {
+ ASSERT_NO_THROW(
+ iface_mgr->openSocket(LOOPBACK, loaddr6, 10000 + i)
+ );
+ }
+ }
+
+ // At the end we should have 3 IPv4 and 3 IPv6 sockets open.
+ Iface* iface = iface_mgr->getIface(LOOPBACK);
+ ASSERT_TRUE(iface != NULL);
+
+ int v4_sockets_count = getOpenSocketsCount(*iface, AF_INET);
+ ASSERT_EQ(3, v4_sockets_count);
+ int v6_sockets_count = getOpenSocketsCount(*iface, AF_INET6);
+ ASSERT_EQ(3, v6_sockets_count);
+
+ // Let's try to close only IPv4 sockets.
+ ASSERT_NO_THROW(iface_mgr->closeSockets(AF_INET));
+ v4_sockets_count = getOpenSocketsCount(*iface, AF_INET);
+ EXPECT_EQ(0, v4_sockets_count);
+ // The IPv6 sockets should remain open.
+ v6_sockets_count = getOpenSocketsCount(*iface, AF_INET6);
+ EXPECT_EQ(3, v6_sockets_count);
+
+ // Let's try to close IPv6 sockets.
+ ASSERT_NO_THROW(iface_mgr->closeSockets(AF_INET6));
+ v4_sockets_count = getOpenSocketsCount(*iface, AF_INET);
+ EXPECT_EQ(0, v4_sockets_count);
+ // They should have been closed now.
+ v6_sockets_count = getOpenSocketsCount(*iface, AF_INET6);
+ EXPECT_EQ(0, v6_sockets_count);
+}
+
TEST_F(IfaceMgrTest, ifaceClass) {
// basic tests for Iface inner class