Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sebastian Schrader
Kea
Commits
80f01bc6
Commit
80f01bc6
authored
Apr 26, 2013
by
Marcin Siodelski
Browse files
[2902] Implemented selective closure of sockets (e.g. only v4 sockets).
parent
1ca6a3ac
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/lib/dhcp/iface_mgr.cc
View file @
80f01bc6
...
...
@@ -58,11 +58,44 @@ Iface::Iface(const std::string& name, int ifindex)
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
...
...
@@ -150,6 +183,14 @@ void IfaceMgr::closeSockets() {
}
}
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
;
...
...
src/lib/dhcp/iface_mgr.h
View file @
80f01bc6
...
...
@@ -110,6 +110,27 @@ public:
/// @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
...
...
@@ -268,7 +289,7 @@ public:
/// 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,
...
...
@@ -538,6 +559,27 @@ public:
/// 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
...
...
src/lib/dhcp/tests/iface_mgr_unittest.cc
View file @
80f01bc6
...
...
@@ -122,6 +122,24 @@ public:
~
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
...
...
@@ -216,6 +234,66 @@ TEST_F(IfaceMgrTest, basic) {
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
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment