Commit 76ace0c4 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[master] Merge branch 'trac3288'

Conflicts:
	src/lib/dhcp/iface_mgr.cc
parents 90460192 9f52928a
......@@ -19,6 +19,7 @@ libb10_dhcp___la_SOURCES += duid.cc duid.h
libb10_dhcp___la_SOURCES += hwaddr.cc hwaddr.h
libb10_dhcp___la_SOURCES += iface_mgr.cc iface_mgr.h
libb10_dhcp___la_SOURCES += iface_mgr_bsd.cc
libb10_dhcp___la_SOURCES += iface_mgr_error_handler.h
libb10_dhcp___la_SOURCES += iface_mgr_linux.cc
libb10_dhcp___la_SOURCES += iface_mgr_sun.cc
libb10_dhcp___la_SOURCES += libdhcp++.cc libdhcp++.h
......
......@@ -22,6 +22,7 @@
#include <dhcp/dhcp4.h>
#include <dhcp/dhcp6.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/iface_mgr_error_handler.h>
#include <dhcp/pkt_filter_inet.h>
#include <dhcp/pkt_filter_inet6.h>
#include <exceptions/exceptions.h>
......@@ -37,40 +38,6 @@
#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;
......@@ -183,7 +150,7 @@ bool Iface::delAddress(const isc::asiolink::IOAddress& addr) {
return (false);
}
bool Iface::delSocket(uint16_t sockfd) {
bool Iface::delSocket(const uint16_t sockfd) {
list<SocketInfo>::iterator sock = sockets_.begin();
while (sock!=sockets_.end()) {
if (sock->sockfd_ == sockfd) {
......@@ -530,59 +497,13 @@ IfaceMgr::openSockets6(const uint16_t port,
continue;
}
// Open socket and join multicast group only if the interface
// is multicast-capable.
// @todo The DHCPv6 requires multicast so we may want to think
// whether we want to open the socket on a multicast-incapable
// interface or not. For now, we prefer to be liberal and allow
// 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.
// 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;
// Run OS-specific function to open a socket on link-local address
// and join multicast group (non-Linux OSes), or open two sockets and
// bind one to link-local, another one to multicast address.
if (openMulticastSocket(*iface, *addr, port, error_handler)) {
++count;
}
count++;
/// @todo: Remove this ifdef once we start supporting BSD systems.
#if defined(OS_LINUX)
// To receive multicast traffic, Linux requires binding socket to
// a multicast group. That in turn doesn't work on NetBSD.
if (iface->flag_multicast_) {
try {
openSocket(iface->getName(),
IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
port);
} 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
}
}
return (count > 0);
......@@ -807,7 +728,6 @@ IfaceMgr::getLocalAddress(const IOAddress& remote_addr, const uint16_t port) {
return IOAddress(local_address);
}
int
IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port,
const bool join_multicast) {
......@@ -1129,6 +1049,5 @@ IfaceMgr::getSocket(isc::dhcp::Pkt4 const& pkt) {
<< " does not have any suitable IPv4 sockets open.");
}
} // end of namespace isc::dhcp
} // end of namespace isc
......@@ -34,6 +34,7 @@ namespace isc {
namespace dhcp {
/// @brief IfaceMgr exception thrown thrown when interface detection fails.
class IfaceDetectError : public Exception {
public:
......@@ -1002,6 +1003,29 @@ private:
const uint16_t port);
/// @brief Open an IPv6 socket with multicast support.
///
/// This function opens socket(s) to allow reception of the DHCPv6 sent
/// to multicast address. It opens an IPv6 socket, binds it to link-local
/// address and joins multicast group (on non-Linux systems) or opens two
/// IPv6 sockets and binds one of them to link-local address and another
/// one to multicast address (on Linux systems).
///
/// @note This function is intended to be called internally by the
/// @c IfaceMgr::openSockets6. It is not intended to be called from any
/// other function.
///
/// @param iface Interface on which socket should be open.
/// @param addr Link-local address to bind the socket to.
/// @param port Port number to bind socket to.
/// @param error_handler Error handler function to be called when an
/// error occurs during opening a socket, or NULL if exception should
/// be thrown upon error.
bool openMulticastSocket(Iface& iface,
const isc::asiolink::IOAddress addr,
const uint16_t port,
IfaceMgrErrorMsgCallback error_handler = NULL);
/// Holds instance of a class derived from PktFilter, used by the
/// IfaceMgr to open sockets and send/receive packets through these
/// sockets. It is possible to supply custom object using
......
// Copyright (C) 2011, 2013 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011, 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
......@@ -17,6 +17,7 @@
#if defined(OS_BSD)
#include <dhcp/iface_mgr.h>
#include <dhcp/iface_mgr_error_handler.h>
#include <dhcp/pkt_filter_inet.h>
#include <exceptions/exceptions.h>
......@@ -149,6 +150,28 @@ IfaceMgr::setMatchingPacketFilter(const bool /* direct_response_desired */) {
setPacketFilter(PktFilterPtr(new PktFilterInet()));
}
bool
IfaceMgr::openMulticastSocket(Iface& iface,
const isc::asiolink::IOAddress addr,
const uint16_t port,
IfaceMgrErrorMsgCallback error_handler) {
try {
// This should open a socket, bound it to link-local address
// and join multicast group.
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());
return (false);
}
return (true);
}
} // end of isc::dhcp namespace
} // end of dhcp namespace
......
// Copyright (C) 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef IFACE_MGR_ERROR_HANDLER_H
#define IFACE_MGR_ERROR_HANDLER_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__); \
} \
} \
#endif // IFACE_MGR_ERROR_HANDLER_H
// Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-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
......@@ -33,6 +33,7 @@
#include <asiolink/io_address.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/iface_mgr_error_handler.h>
#include <dhcp/pkt_filter_inet.h>
#include <dhcp/pkt_filter_lpf.h>
#include <exceptions/exceptions.h>
......@@ -533,6 +534,60 @@ bool IfaceMgr::os_receive4(struct msghdr&, Pkt4Ptr&) {
return (true);
}
bool
IfaceMgr::openMulticastSocket(Iface& iface,
const isc::asiolink::IOAddress addr,
const uint16_t port,
IfaceMgrErrorMsgCallback error_handler) {
// This variable will hold a descriptor of the socket bound to
// link-local address. It may be required for us to close this
// socket if an attempt to open and bind a socket to multicast
// address fails.
int sock;
try {
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());
return (false);
}
// To receive multicast traffic, Linux requires binding socket to
// the multicast address.
/// @todo The DHCPv6 requires multicast so we may want to think
/// whether we want to open the socket on a multicast-incapable
/// interface or not. For now, we prefer to be liberal and allow
/// 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.
if (iface.flag_multicast_) {
try {
openSocket(iface.getName(),
IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
port);
} catch (const Exception& ex) {
// An attempt to open and bind a socket to multicast addres
// has failed. We have to close the socket we previously
// bound to link-local address - this is everything or
// nothing strategy.
iface.delSocket(sock);
IFACEMGR_ERROR(SocketConfigError, error_handler,
"Failed to open multicast socket on"
" interface " << iface.getName()
<< ", reason: " << ex.what());
return (false);
}
}
// Both sockets have opened successfully.
return (true);
}
} // end of isc::dhcp namespace
} // end of isc namespace
......
// Copyright (C) 2011, 2013 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011, 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
......@@ -17,6 +17,7 @@
#if defined(OS_SUN)
#include <dhcp/iface_mgr.h>
#include <dhcp/iface_mgr_error_handler.h>
#include <dhcp/pkt_filter_inet.h>
#include <exceptions/exceptions.h>
......@@ -153,6 +154,28 @@ IfaceMgr::setMatchingPacketFilter(const bool /* direct_response_desired */) {
setPacketFilter(PktFilterPtr(new PktFilterInet()));
}
bool
IfaceMgr::openMulticastSocket(Iface& iface,
const isc::asiolink::IOAddress addr,
const uint16_t port,
IfaceMgrErrorMsgCallback error_handler) {
try {
// This should open a socket, bound it to link-local address
// and join multicast group.
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());
return (false);
}
return (true);
}
} // end of isc::dhcp namespace
} // end of dhcp namespace
......
Markdown is supported
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