Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Adam Osuchowski
Kea
Commits
af5eada1
Commit
af5eada1
authored
Jan 14, 2014
by
Marcin Siodelski
Browse files
[master] Merge branch 'trac3252'
parents
65afca2b
68b6c2b5
Changes
10
Hide whitespace changes
Inline
Side-by-side
doc/devel/mainpage.dox
View file @
af5eada1
...
...
@@ -74,6 +74,7 @@
* - @subpage libdhcpIfaceMgr
* - @subpage libdhcpPktFilter
* - @subpage libdhcpPktFilter6
* - @subpage libdhcpErrorLogging
* - @subpage libdhcpsrv
* - @subpage leasemgr
* - @subpage cfgmgr
...
...
src/bin/dhcp6/dhcp6_messages.mes
View file @
af5eada1
# Copyright (C) 2012-201
3
Internet Systems Consortium, Inc. ("ISC")
# Copyright (C) 2012-201
4
Internet Systems Consortium, Inc. ("ISC")
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
...
...
@@ -250,6 +250,10 @@ configured to receive the traffic.
A debug message issued during startup, this indicates that the IPv6 DHCP
server is about to open sockets on the specified port.
% DHCP6_OPEN_SOCKET_FAIL failed to create socket: %1
A warning message issued when IfaceMgr fails to open and bind a socket. The reason
for the failure is appended as an argument of the log message.
% DHCP6_PACKET_PARSE_FAIL failed to parse incoming packet
The IPv6 DHCP server has received a packet that it is unable to interpret.
...
...
src/bin/dhcp6/dhcp6_srv.cc
View file @
af5eada1
// Copyright (C) 2011-201
3
Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-201
4
Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
...
...
@@ -45,6 +45,7 @@
#include
<util/io_utilities.h>
#include
<util/range_utilities.h>
#include
<boost/bind.hpp>
#include
<boost/foreach.hpp>
#include
<boost/tokenizer.hpp>
#include
<boost/algorithm/string/erase.hpp>
...
...
@@ -152,7 +153,12 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port)
LOG_ERROR
(
dhcp6_logger
,
DHCP6_NO_INTERFACES
);
return
;
}
IfaceMgr
::
instance
().
openSockets6
(
port_
);
// Create error handler. This handler will be called every time
// the socket opening operation fails. We use this handler to
// log a warning.
isc
::
dhcp
::
IfaceMgrErrorMsgCallback
error_handler
=
boost
::
bind
(
&
Dhcpv6Srv
::
ifaceMgrSocket6ErrorHandler
,
_1
);
IfaceMgr
::
instance
().
openSockets6
(
port_
,
error_handler
);
}
string
duid_file
=
CfgMgr
::
instance
().
getDataDir
()
+
"/"
+
string
(
SERVER_DUID_FILE
);
...
...
@@ -2311,7 +2317,9 @@ Dhcpv6Srv::openActiveSockets(const uint16_t port) {
// sockets are marked active or inactive.
// @todo Optimization: we should not reopen all sockets but rather select
// those that have been affected by the new configuration.
if
(
!
IfaceMgr
::
instance
().
openSockets6
(
port
))
{
isc
::
dhcp
::
IfaceMgrErrorMsgCallback
error_handler
=
boost
::
bind
(
&
Dhcpv6Srv
::
ifaceMgrSocket6ErrorHandler
,
_1
);
if
(
!
IfaceMgr
::
instance
().
openSockets6
(
port
,
error_handler
))
{
LOG_WARN
(
dhcp6_logger
,
DHCP6_NO_SOCKETS_OPEN
);
}
}
...
...
@@ -2409,6 +2417,11 @@ Dhcpv6Srv::unpackOptions(const OptionBuffer& buf,
return
(
offset
);
}
void
Dhcpv6Srv
::
ifaceMgrSocket6ErrorHandler
(
const
std
::
string
&
errmsg
)
{
// Log the reason for socket opening failure and return.
LOG_WARN
(
dhcp6_logger
,
DHCP6_OPEN_SOCKET_FAIL
).
arg
(
errmsg
);
}
};
};
src/bin/dhcp6/dhcp6_srv.h
View file @
af5eada1
// Copyright (C) 2011-201
3
Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-201
4
Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
...
...
@@ -534,6 +534,16 @@ protected:
size_t
*
relay_msg_len
);
private:
/// @brief Implements the error handler for socket open failure.
///
/// This callback function is installed on the @c isc::dhcp::IfaceMgr
/// when IPv6 sockets are being open. When socket fails to open for
/// any reason, this function is called. It simply logs the error message.
///
/// @param errmsg An error message containing a cause of the failure.
static
void
ifaceMgrSocket6ErrorHandler
(
const
std
::
string
&
errmsg
);
/// @brief Allocation Engine.
/// Pointer to the allocation engine that we are currently using
/// It must be a pointer, because we will support changing engines
...
...
src/lib/dhcp/iface_mgr.cc
View file @
af5eada1
// Copyright (C) 2011-201
3
Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-201
4
Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
...
...
@@ -37,6 +37,40 @@
#include
<string.h>
#include
<sys/select.h>
/// @brief A macro which handles an error in IfaceMgr.
///
/// There are certain cases when IfaceMgr may hit an error which shouldn't
/// result in interruption of the function processing. A typical case is
/// the function which opens sockets on available interfaces for a DHCP
/// server. If this function fails to open a socket on a specific interface
/// (for example, there is another socket already open on this interface
/// and bound to the same address and port), it is desired that the server
/// logs a warning but will try to open sockets on other interfaces. In order
/// to log an error, the IfaceMgr will use the error handler function provided
/// by the server and pass an error string to it. When the handler function
/// returns, the IfaceMgr will proceed to open other sockets. It is allowed
/// that the error handler function is not installed (is NULL). In these
/// cases it is expected that the exception is thrown instead. A possible
/// solution would be to enclose this conditional behavior in a function.
/// However, despite the hate for macros, the macro seems to be a bit
/// better solution in this case as it allows to convenietly pass an
/// error string in a stream (not as a string).
///
/// @param ex_type Exception to be thrown if error_handler is NULL.
/// @param handler Error handler function to be called or NULL to indicate
/// that exception should be thrown instead.
/// @param stream stream object holding an error string.
#define IFACEMGR_ERROR(ex_type, handler, stream) \
{ \
std::ostringstream oss__; \
oss__ << stream; \
if (handler) { \
handler(oss__.str()); \
} else { \
isc_throw(ex_type, oss__); \
} \
} \
using
namespace
std
;
using
namespace
isc
::
asiolink
;
using
namespace
isc
::
util
::
io
::
internal
;
...
...
@@ -366,7 +400,6 @@ IfaceMgr::openSockets4(const uint16_t port, const bool use_bcast,
continue
;
}
int
sock
=
-
1
;
// If selected interface is broadcast capable set appropriate
// options on the socket so as it can receive and send broadcast
// messages.
...
...
@@ -376,22 +409,24 @@ IfaceMgr::openSockets4(const uint16_t port, const bool use_bcast,
// bind to INADDR_ANY address but we can do it only once. Thus,
// if one socket has been bound we can't do it any further.
if
(
!
bind_to_device
&&
bcast_num
>
0
)
{
handle
SocketConfigError
(
"SO_BINDTODEVICE socket option is"
" not supported on this OS;
"
" therefore, DHCP server can only
"
" listen broadcast traffic
on
a
"
" single interface"
,
error_handler
);
IFACEMGR_ERROR
(
SocketConfigError
,
error_handler
,
"SO_BINDTODEVICE socket option is
"
" not supported on this OS;
"
" therefore, DHCP server can
on
ly
"
" listen broadcast traffic on a"
" single interface"
);
continue
;
}
else
{
try
{
// We haven't open any broadcast sockets yet, so we can
// open at least one more.
sock
=
openSocket
(
iface
->
getName
(),
*
addr
,
port
,
true
,
true
);
openSocket
(
iface
->
getName
(),
*
addr
,
port
,
true
,
true
);
}
catch
(
const
Exception
&
ex
)
{
handleSocketConfigError
(
ex
.
what
(),
error_handler
);
IFACEMGR_ERROR
(
SocketConfigError
,
error_handler
,
"failed to open socket on interface "
<<
iface
->
getName
()
<<
", reason: "
<<
ex
.
what
());
continue
;
}
...
...
@@ -406,30 +441,26 @@ IfaceMgr::openSockets4(const uint16_t port, const bool use_bcast,
}
else
{
try
{
// Not broadcast capable, do not set broadcast flags.
sock
=
openSocket
(
iface
->
getName
(),
*
addr
,
port
,
false
,
false
);
openSocket
(
iface
->
getName
(),
*
addr
,
port
,
false
,
false
);
}
catch
(
const
Exception
&
ex
)
{
handleSocketConfigError
(
ex
.
what
(),
error_handler
);
IFACEMGR_ERROR
(
SocketConfigError
,
error_handler
,
"failed to open socket on interface "
<<
iface
->
getName
()
<<
", reason: "
<<
ex
.
what
());
continue
;
}
}
if
(
sock
<
0
)
{
const
char
*
errstr
=
strerror
(
errno
);
handleSocketConfigError
(
std
::
string
(
"failed to open IPv4 socket,"
" reason:"
)
+
errstr
,
error_handler
);
}
else
{
++
count
;
}
++
count
;
}
}
return
(
count
>
0
);
}
bool
IfaceMgr
::
openSockets6
(
const
uint16_t
port
)
{
int
sock
;
bool
IfaceMgr
::
openSockets6
(
const
uint16_t
port
,
IfaceMgrErrorMsgCallback
error_handler
)
{
int
count
=
0
;
for
(
IfaceCollection
::
iterator
iface
=
ifaces_
.
begin
();
...
...
@@ -448,12 +479,15 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
for
(
Iface
::
AddressCollection
::
iterator
addr
=
unicasts
.
begin
();
addr
!=
unicasts
.
end
();
++
addr
)
{
sock
=
openSocket
(
iface
->
getName
(),
*
addr
,
port
);
if
(
sock
<
0
)
{
const
char
*
errstr
=
strerror
(
errno
);
isc_throw
(
SocketConfigError
,
"failed to open unicast socket on "
<<
addr
->
toText
()
<<
" on interface "
<<
iface
->
getName
()
<<
", reason: "
<<
errstr
);
try
{
openSocket
(
iface
->
getName
(),
*
addr
,
port
);
}
catch
(
const
Exception
&
ex
)
{
IFACEMGR_ERROR
(
SocketConfigError
,
error_handler
,
"Failed to open unicast socket on interface "
<<
iface
->
getName
()
<<
", reason: "
<<
ex
.
what
());
continue
;
}
count
++
;
...
...
@@ -487,13 +521,28 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
// it for some odd use cases which may utilize non-multicast
// interfaces. Perhaps a warning should be emitted if the
// interface is not a multicast one.
sock
=
openSocket
(
iface
->
getName
(),
*
addr
,
port
,
iface
->
flag_multicast_
);
if
(
sock
<
0
)
{
const
char
*
errstr
=
strerror
(
errno
);
isc_throw
(
SocketConfigError
,
"failed to open link-local"
" socket on "
<<
addr
->
toText
()
<<
" on interface "
<<
iface
->
getName
()
<<
", reason: "
<<
errstr
);
// The sock variable will hold a socket descriptor. It may be
// used to close a socket if the function fails to bind to
// multicast address on Linux systems. Because we only bind
// a socket to multicast address on Linux, on other systems
// the sock variable will be initialized but unused. We have
// to suppress the cppcheck warning which shows up on non-Linux
// systems.
// cppcheck-suppress variableScope
int
sock
;
try
{
// cppcheck-suppress unreadVariable
sock
=
openSocket
(
iface
->
getName
(),
*
addr
,
port
,
iface
->
flag_multicast_
);
}
catch
(
const
Exception
&
ex
)
{
IFACEMGR_ERROR
(
SocketConfigError
,
error_handler
,
"Failed to open link-local socket on "
" interface "
<<
iface
->
getName
()
<<
": "
<<
ex
.
what
());
continue
;
}
count
++
;
...
...
@@ -503,16 +552,18 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
// To receive multicast traffic, Linux requires binding socket to
// a multicast group. That in turn doesn't work on NetBSD.
if
(
iface
->
flag_multicast_
)
{
int
sock2
=
try
{
openSocket
(
iface
->
getName
(),
IOAddress
(
ALL_DHCP_RELAY_AGENTS_AND_SERVERS
),
port
);
if
(
sock2
<
0
)
{
const
char
*
errstr
=
strerror
(
errno
);
isc_throw
(
SocketConfigError
,
"Failed to open multicast"
" socket on interface "
<<
iface
->
getFullName
()
<<
", reason:"
<<
errstr
);
iface
->
delSocket
(
sock
);
// delete previously opened socket
}
catch
(
const
Exception
&
ex
)
{
// Delete previously opened socket.
iface
->
delSocket
(
sock
);
IFACEMGR_ERROR
(
SocketConfigError
,
error_handler
,
"Failed to open multicast socket on"
" interface "
<<
iface
->
getName
()
<<
", reason: "
<<
ex
.
what
());
continue
;
}
}
#endif
...
...
@@ -521,20 +572,6 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
return
(
count
>
0
);
}
void
IfaceMgr
::
handleSocketConfigError
(
const
std
::
string
&
errmsg
,
IfaceMgrErrorMsgCallback
handler
)
{
// If error handler is installed, we don't want to throw an exception, but
// rather call this handler.
if
(
handler
!=
NULL
)
{
handler
(
errmsg
);
}
else
{
isc_throw
(
SocketConfigError
,
errmsg
);
}
}
void
IfaceMgr
::
printIfaces
(
std
::
ostream
&
out
/*= std::cout*/
)
{
for
(
IfaceCollection
::
const_iterator
iface
=
ifaces_
.
begin
();
...
...
src/lib/dhcp/iface_mgr.h
View file @
af5eada1
// Copyright (C) 2011-201
3
Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-201
4
Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
...
...
@@ -643,24 +643,43 @@ public:
/// @brief Opens IPv6 sockets on detected interfaces.
///
/// @todo This function will throw an exception immediately when a socket
/// fails to open. This is undersired behavior because it will preclude
/// other sockets from opening. We should strive to provide similar mechanism
/// that has been introduced for V4 sockets. If socket creation fails the
/// appropriate error handler is called and once the handler returns the
/// function contnues to open other sockets. The change in the IfaceMgr
/// is quite straight forward and it is proven to work for V4. However,
/// unit testing it is a bit involved, because for unit testing we need
/// a replacement of the openSocket6 function which will mimic the
/// behavior of the real socket opening. For the V4 we have the means to
/// to achieve that with the replaceable PktFilter class. For V6, the
/// implementation is hardcoded in the openSocket6.
/// On the systems with multiple interfaces, it is often desired that the
/// failure to open a socket on a particular interface doesn't cause a
/// fatal error and sockets should be opened on remaining interfaces.
/// However, the warning about the failure for the particular socket should
/// be communicated to the caller. The libdhcp++ is a common library with
/// no logger associated with it. Most of the functions in this library
/// communicate errors via exceptions. In case of openSockets6 function
/// exception must not be thrown if the function is supposed to continue
/// opening sockets, despite an error. Therefore, if such a behavior is
/// desired, the error handler function can be passed as a parameter.
/// This error handler is called (if present) with an error string.
/// Typically, error handler will simply log an error using an application
/// logger, but it can do more sophisticated error handling too.
///
/// @todo It is possible that additional parameters will have to be added
/// to the error handler, e.g. Iface if it was really supposed to do
/// some more sophisticated error handling.
///
/// If the error handler is not installed (is NULL), the exception is thrown
/// for each failure (default behavior).
///
/// @warning This function does not check if there has been any sockets
/// already open by the @c IfaceMgr. Therefore a caller should call
/// @c IfaceMgr::closeSockets(AF_INET6) before calling this function.
/// If there are any sockets open, the function may either throw an
/// exception or invoke an error handler on attempt to bind the new socket
/// to the same address and port.
///
/// @param port specifies port number (usually DHCP6_SERVER_PORT)
/// @param error_handler A pointer to an error handler function which is
/// called by the openSockets6 when it fails to open a socket. This
/// parameter can be NULL to indicate that the callback should not be used.
///
/// @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
);
bool
openSockets6
(
const
uint16_t
port
=
DHCP6_SERVER_PORT
,
IfaceMgrErrorMsgCallback
error_handler
=
NULL
);
/// @brief Opens IPv4 sockets on detected interfaces.
///
...
...
@@ -715,6 +734,13 @@ public:
/// If the error handler is not installed (is NULL), the exception is thrown
/// for each failure (default behavior).
///
/// @warning This function does not check if there has been any sockets
/// already open by the @c IfaceMgr. Therefore a caller should call
/// @c IfaceMgr::closeSockets(AF_INET) before calling this function.
/// If there are any sockets open, the function may either throw an
/// exception or invoke an error handler on attempt to bind the new socket
/// to the same address and port.
///
/// @param port specifies port number (usually DHCP4_SERVER_PORT)
/// @param use_bcast configure sockets to support broadcast messages.
/// @param error_handler A pointer to an error handler function which is
...
...
@@ -957,23 +983,6 @@ private:
getLocalAddress
(
const
isc
::
asiolink
::
IOAddress
&
remote_addr
,
const
uint16_t
port
);
/// @brief Handles an error which occurs during configuration of a socket.
///
/// If the handler callback is specified (non-NULL), this handler is
/// called and the specified error message is passed to it. If the
/// handler is not specified, the @c isc::dhcpSocketConfigError exception
/// is thrown with the specified message.
///
/// This function should be called to handle errors which occur during
/// socket opening, binding or configuration (e.g. setting socket options
/// etc).
///
/// @param errmsg An error message to be passed to a handlder function or
/// to the @c isc::dhcp::SocketConfigError exception.
/// @param handler An error handler function or NULL.
void
handleSocketConfigError
(
const
std
::
string
&
errmsg
,
IfaceMgrErrorMsgCallback
handler
);
/// @brief Checks if there is at least one socket of the specified family
/// open.
///
...
...
src/lib/dhcp/libdhcp++.dox
View file @
af5eada1
// Copyright (C) 2012-201
3
Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-201
4
Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
...
...
@@ -231,4 +231,33 @@ functions.
Use \ref isc::dhcp::IfaceMgr::setPacketFilter function to set the custom packet
filter object to be used by Interface Manager.
@section libdhcpErrorLogging Logging non-fatal errors in IfaceMgr
The libdhcp++ is a common library, meant to be used by various components,
such as DHCP servers, relays and clients. It is also used by a perfdhcp
benchmarking application. It provides a basic capabilities for these
applications to perform operations on DHCP messages such as encoding
or decoding them. It also provides capabilities to perform low level
operations on sockets. Since libdhcp++ is a common library, its dependency
on other BINDX modules should be minimal. In particular, errors occurring
in the libdhcp++ are reported using exceptions, not a BINDX logger. This
works well in most cases, but there are some cases in which it is
undesired for a function to throw an exception in case of non-fatal error.
The typical case, when exception should not be thrown, is when the \ref
isc::dhcp::IfaceMgr::openSockets4 or \ref isc::dhcp::IfaceMgr::openSockets6
fails to open a socket on one of the interfaces. This should not preclude
the function from attempting to open sockets on other interfaces, which
would be the case if exception was thrown.
In such cases the IfaceMgr makes use of error handler callback function
which may be installed by a caller. This function must implement the
isc::dhcp::IfaceMgrErrorMsgCallback. Note that it is allowed to pass a NULL
value instead, which would result falling back to a default behavior and
exception will be thrown. If non-NULL value is provided, the
\ref isc::dhcp::IfaceMgr will call error handler function and pass an
error string as an argument. The handler function may use its logging
mechanism to log this error message. In particular, the DHCP server
will use BINDX logger to log the error message.
*/
src/lib/dhcp/tests/iface_mgr_unittest.cc
View file @
af5eada1
// Copyright (C) 2011-201
3
Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-201
4
Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
...
...
@@ -1465,7 +1465,7 @@ TEST_F(IfaceMgrTest, openSockets4NoErrorHandler) {
// Test that the external error handler is called when trying to bind a new
// socket to the address and port being in use. The sockets on the other
// interfaces should open just fine.
.
// interfaces should open just fine.
TEST_F
(
IfaceMgrTest
,
openSocket4ErrorHandler
)
{
NakedIfaceMgr
ifacemgr
;
...
...
@@ -1476,9 +1476,7 @@ TEST_F(IfaceMgrTest, openSocket4ErrorHandler) {
ASSERT_TRUE
(
custom_packet_filter
);
ASSERT_NO_THROW
(
ifacemgr
.
setPacketFilter
(
custom_packet_filter
));
// Open socket on eth0. The openSockets4 should detect that this
// socket has been already open and an attempt to open another socket
// and bind to this address and port should fail.
// Open socket on eth0.
ASSERT_NO_THROW
(
ifacemgr
.
openSocket
(
"eth0"
,
IOAddress
(
"10.0.0.1"
),
DHCP4_SERVER_PORT
));
...
...
@@ -1486,6 +1484,9 @@ TEST_F(IfaceMgrTest, openSocket4ErrorHandler) {
// should be called when the IfaceMgr fails to open socket on eth0.
isc
::
dhcp
::
IfaceMgrErrorMsgCallback
error_handler
=
boost
::
bind
(
&
IfaceMgrTest
::
ifaceMgrErrorHandler
,
this
,
_1
);
// The openSockets4 should detect that there is another socket already
// open and bound to the same address and port. An attempt to open
// another socket and bind to this address and port should fail.
ASSERT_NO_THROW
(
ifacemgr
.
openSockets4
(
DHCP4_SERVER_PORT
,
true
,
error_handler
));
// We expect that an error occured when we tried to open a socket on
// eth0, but the socket on eth1 should open just fine.
...
...
@@ -1829,6 +1830,73 @@ TEST_F(IfaceMgrTest, openSockets6NoIfaces) {
EXPECT_FALSE
(
socket_open
);
}
// Test that exception is thrown when trying to bind a new socket to the port
// and address which is already in use by another socket.
TEST_F
(
IfaceMgrTest
,
openSockets6NoErrorHandler
)
{
NakedIfaceMgr
ifacemgr
;
// Remove all real interfaces and create a set of dummy interfaces.
ifacemgr
.
createIfaces
();
boost
::
shared_ptr
<
PktFilter6Stub
>
filter
(
new
PktFilter6Stub
());
ASSERT_TRUE
(
filter
);
ASSERT_NO_THROW
(
ifacemgr
.
setPacketFilter
(
filter
));
// Open socket on eth0. The openSockets6 should detect that this
// socket has been already open and an attempt to open another socket
// and bind to this address and port should fail.
ASSERT_NO_THROW
(
ifacemgr
.
openSocket
(
"eth0"
,
IOAddress
(
"fe80::3a60:77ff:fed5:cdef"
),
DHCP6_SERVER_PORT
));
// The function throws an exception when it tries to open a socket
// and bind it to the address in use.
EXPECT_THROW
(
ifacemgr
.
openSockets6
(
DHCP6_SERVER_PORT
),
isc
::
dhcp
::
SocketConfigError
);
}
// Test that the external error handler is called when trying to bind a new
// socket to the address and port being in use. The sockets on the other
// interfaces should open just fine.
TEST_F
(
IfaceMgrTest
,
openSocket6ErrorHandler
)
{
NakedIfaceMgr
ifacemgr
;
// Remove all real interfaces and create a set of dummy interfaces.
ifacemgr
.
createIfaces
();
boost
::
shared_ptr
<
PktFilter6Stub
>
filter
(
new
PktFilter6Stub
());
ASSERT_TRUE
(
filter
);
ASSERT_NO_THROW
(
ifacemgr
.
setPacketFilter
(
filter
));
// Open socket on eth0.
ASSERT_NO_THROW
(
ifacemgr
.
openSocket
(
"eth0"
,
IOAddress
(
"fe80::3a60:77ff:fed5:cdef"
),
DHCP6_SERVER_PORT
));
// Install an error handler before trying to open sockets. This handler
// should be called when the IfaceMgr fails to open socket on eth0.
isc
::
dhcp
::
IfaceMgrErrorMsgCallback
error_handler
=
boost
::
bind
(
&
IfaceMgrTest
::
ifaceMgrErrorHandler
,
this
,
_1
);
// The openSockets6 should detect that a socket has been already
// opened on eth0 and an attempt to open another socket and bind to
// the same address and port should fail.
ASSERT_NO_THROW
(
ifacemgr
.
openSockets6
(
DHCP6_SERVER_PORT
,
error_handler
));
// We expect that an error occured when we tried to open a socket on
// eth0, but the socket on eth1 should open just fine.
EXPECT_EQ
(
1
,
errors_count_
);
// Reset errors count.
errors_count_
=
0
;
// Now that we have two sockets open, we can try this again but this time
// we should get two errors: one when opening a socket on eth0, another one
// when opening a socket on eth1.
ASSERT_NO_THROW
(
ifacemgr
.
openSockets6
(
DHCP6_SERVER_PORT
,
error_handler
));
EXPECT_EQ
(
2
,
errors_count_
);
}
// Test the Iface structure itself
TEST_F
(
IfaceMgrTest
,
iface
)
{
boost
::
scoped_ptr
<
Iface
>
iface
;
...
...
src/lib/dhcp/tests/pkt_filter6_test_utils.cc
View file @
af5eada1
// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2013
-2014
Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
...
...
@@ -181,8 +181,17 @@ PktFilter6Stub::PktFilter6Stub()
}
SocketInfo
PktFilter6Stub
::
openSocket
(
const
Iface
&
,
const
isc
::
asiolink
::
IOAddress
&
addr
,
PktFilter6Stub
::
openSocket
(
const
Iface
&
iface
,
const
isc
::
asiolink
::
IOAddress
&
addr
,
const
uint16_t
port
,
const
bool
)
{
// Check if there is any other socket bound to the specified address
// and port on this interface.
const
Iface
::
SocketCollection
&
sockets
=
iface
.
getSockets
();
for
(
Iface
::
SocketCollection
::
const_iterator
socket
=
sockets
.
begin
();
socket
!=
sockets
.
end
();
++
socket
)
{
if
((
socket
->
addr_
==
addr
)
&&
(
socket
->
port_
==
port
))
{
isc_throw
(
SocketConfigError
,
"test socket bind error"
);
}
}
++
open_socket_count_
;
return
(
SocketInfo
(
addr
,
port
,
0
));
}
...
...
src/lib/dhcp/tests/pkt_filter6_test_utils.h
View file @
af5eada1
// Copyright (C) 2013
Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2013
-2014
Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
...
...
@@ -109,6 +109,11 @@ public:
/// always set to 0. On each call to this function, the counter of
/// invocations is increased by one. This is useful to check if packet
/// filter object has been correctly installed and is used by @c IfaceMgr.
/// As in the case of opening a real socket, this function will check
/// if there is another fake socket "bound" to the same address and port.
/// If there is, it will throw an exception. This allows to simulate the
/// conditions when one of the sockets can't be open because there is
/// a socket already open and test how IfaceMgr will handle it.
///
/// @param iface Interface descriptor.
/// @param addr Address on the interface to be used to send packets.
...
...
Write
Preview
Supports