Commit 4e225668 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[2765] Added fallback socket descriptor to SocketInfo structure.

parent 0119b50f
......@@ -20,6 +20,7 @@
#define DHCP4_TEST_UTILS_H
#include <gtest/gtest.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt_filter.h>
#include <dhcp/pkt_filter_inet.h>
......@@ -52,9 +53,10 @@ public:
}
/// Does nothing.
virtual int openSocket(const Iface&, const isc::asiolink::IOAddress&,
const uint16_t, const bool, const bool) {
return (0);
virtual SocketInfo openSocket(const Iface&,
const isc::asiolink::IOAddress& addr,
const uint16_t port, const bool, const bool) {
return (SocketInfo(addr, port, 0));
}
/// Does nothing.
......
......@@ -741,7 +741,7 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) {
}
}
SocketInfo info(sock, addr, port);
SocketInfo info(addr, port, sock);
iface.addSocket(info);
return (sock);
......@@ -754,13 +754,11 @@ int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr,
// Skip checking if the packet_filter_ is non-NULL because this check
// has been already done when packet filter object was set.
int sock = packet_filter_->openSocket(iface, addr, port,
receive_bcast, send_bcast);
SocketInfo info(sock, addr, port);
SocketInfo info = packet_filter_->openSocket(iface, addr, port,
receive_bcast, send_bcast);
iface.addSocket(info);
return (sock);
return (info.sockfd_);
}
bool
......
......@@ -72,19 +72,49 @@ public:
/// Holds information about socket.
struct SocketInfo {
uint16_t sockfd_; /// socket descriptor
isc::asiolink::IOAddress addr_; /// bound address
uint16_t port_; /// socket port
uint16_t family_; /// IPv4 or IPv6
/// @brief Socket descriptor (a.k.a. primary socket).
int sockfd_;
/// @brief Fallback socket descriptor.
///
/// This socket descriptor holds the handle to the fallback socket.
/// The fallback socket is created when there is a need for the regular
/// datagram socket to be bound to an IP address and port, besides
/// primary socket (sockfd_) which is actually used to receive and process
/// the DHCP messages. The fallback socket (if exists) is always associated
/// with the primary socket. In particular, the need for the fallback socket
/// arises when raw socket is a primary one. When primary socket is open,
/// it is bound to an interface not the address and port. The implications
/// include the possibility that the other process (e.g. the other instance
/// of DHCP server) will bind to the same address and port through which the
/// raw socket receives the DHCP messages.Another implication is that the
/// kernel, being unaware of the DHCP server operating through the raw
/// socket, will respond with the ICMP "Destination port unreachable"
/// messages when DHCP messages are only received through the raw socket.
/// In order to workaround the issues mentioned here, the fallback socket
/// should be opened so as/ the kernel is aware that the certain address
/// and port is in use.
///
/// The fallback description is supposed to be set to a negative value if
/// the fallback socket is closed (not open).
int fallbackfd_;
/// @brief SocketInfo constructor.
///
/// @param sockfd socket descriptor
/// @param addr an address the socket is bound to
/// @param port a port the socket is bound to
SocketInfo(uint16_t sockfd, const isc::asiolink::IOAddress& addr,
uint16_t port)
:sockfd_(sockfd), addr_(addr), port_(port), family_(addr.getFamily()) { }
/// @param addr An address the socket is bound to.
/// @param port A port the socket is bound to.
/// @param sockfd Socket descriptor.
/// @param fallbackfd A descriptor of the fallback socket.
SocketInfo(const isc::asiolink::IOAddress& addr, const uint16_t port,
const int sockfd, const int fallbackfd = -1)
: addr_(addr), port_(port), family_(addr.getFamily()),
sockfd_(sockfd), fallbackfd_(fallbackfd) { }
};
......
......@@ -67,20 +67,30 @@ public:
/// @return true of the direct response is supported.
virtual bool isDirectResponseSupported() const = 0;
/// @brief Open socket.
/// @brief Open primary and fallback socket.
///
/// @param iface interface descriptor
/// @param addr address on the interface to be used to send packets.
/// @param port port number.
/// @param receive_bcast configure socket to receive broadcast messages
/// A method implementation in the derived class may open one or two
/// sockets:
/// - a primary socket - used for communication with clients. DHCP messages
/// received using this socket are processed and the same socket is used
/// to send a response to the client.
/// - a fallback socket which is optionally opened if there is a need for
/// the presence of the socket which can be bound to a specific IP address
/// and UDP port (e.g. raw primary socket can't be). For the details, see
/// the documentation of @c isc::dhcp::SocketInfo.
///
/// @param iface Interface descriptor.
/// @param addr Address on the interface to be used to send packets.
/// @param port Port number.
/// @param receive_bcast Configure socket to receive broadcast messages
/// @param send_bcast configure socket to send broadcast messages.
///
/// @return created socket's descriptor
virtual int openSocket(const Iface& iface,
const isc::asiolink::IOAddress& addr,
const uint16_t port,
const bool receive_bcast,
const bool send_bcast) = 0;
/// @return A structure describing a primary and fallback socket.
virtual SocketInfo openSocket(const Iface& iface,
const isc::asiolink::IOAddress& addr,
const uint16_t port,
const bool receive_bcast,
const bool send_bcast) = 0;
/// @brief Receive packet over specified socket.
///
......
......@@ -28,11 +28,12 @@ PktFilterInet::PktFilterInet()
{
}
int PktFilterInet::openSocket(const Iface& iface,
const isc::asiolink::IOAddress& addr,
const uint16_t port,
const bool receive_bcast,
const bool send_bcast) {
SocketInfo
PktFilterInet::openSocket(const Iface& iface,
const isc::asiolink::IOAddress& addr,
const uint16_t port,
const bool receive_bcast,
const bool send_bcast) {
struct sockaddr_in addr4;
memset(&addr4, 0, sizeof(sockaddr));
......@@ -90,7 +91,8 @@ int PktFilterInet::openSocket(const Iface& iface,
}
#endif
return (sock);
SocketInfo sock_desc(addr, port, sock);
return (sock_desc);
}
......
......@@ -44,20 +44,20 @@ public:
return (false);
}
/// @brief Open socket.
/// @brief Open primary and fallback socket.
///
/// @param iface interface descriptor
/// @param addr address on the interface to be used to send packets.
/// @param port port number.
/// @param receive_bcast configure socket to receive broadcast messages
/// @param send_bcast configure socket to send broadcast messages.
/// @param iface Interface descriptor.
/// @param addr Address on the interface to be used to send packets.
/// @param port Port number.
/// @param receive_bcast Configure socket to receive broadcast messages
/// @param send_bcast Configure socket to send broadcast messages.
///
/// @return created socket's descriptor
virtual int openSocket(const Iface& iface,
const isc::asiolink::IOAddress& addr,
const uint16_t port,
const bool receive_bcast,
const bool send_bcast);
/// @return A structure describing a primary and fallback socket.
virtual SocketInfo openSocket(const Iface& iface,
const isc::asiolink::IOAddress& addr,
const uint16_t port,
const bool receive_bcast,
const bool send_bcast);
/// @brief Receive packet over specified socket.
///
......
......@@ -102,7 +102,7 @@ using namespace isc::util;
namespace isc {
namespace dhcp {
int
SocketInfo
PktFilterLPF::openSocket(const Iface& iface,
const isc::asiolink::IOAddress& addr,
const uint16_t port, const bool,
......@@ -123,7 +123,7 @@ PktFilterLPF::openSocket(const Iface& iface,
// We return negative, the proper error message will be displayed
// by the IfaceMgr ...
close(sock_check);
return (-1);
return (SocketInfo(addr, port, -1));
}
close(sock_check);
......@@ -166,7 +166,8 @@ PktFilterLPF::openSocket(const Iface& iface,
<< "' to interface '" << iface.getName() << "'");
}
return (sock);
SocketInfo sock_desc(addr, port, sock);
return (sock_desc);
}
......
......@@ -41,21 +41,20 @@ public:
return (true);
}
/// @brief Open socket.
/// @brief Open primary and fallback socket.
///
/// @param iface interface descriptor
/// @param addr address on the interface to be used to send packets.
/// @param port port number.
/// @param receive_bcast configure socket to receive broadcast messages
/// @param send_bcast configure socket to send broadcast messages.
/// @param iface Interface descriptor.
/// @param addr Address on the interface to be used to send packets.
/// @param port Port number.
/// @param receive_bcast Configure socket to receive broadcast messages
/// @param send_bcast Configure socket to send broadcast messages.
///
/// @throw isc::NotImplemented always
/// @return created socket's descriptor
virtual int openSocket(const Iface& iface,
const isc::asiolink::IOAddress& addr,
const uint16_t port,
const bool receive_bcast,
const bool send_bcast);
/// @return A structure describing a primary and fallback socket.
virtual SocketInfo openSocket(const Iface& iface,
const isc::asiolink::IOAddress& addr,
const uint16_t port,
const bool receive_bcast,
const bool send_bcast);
/// @brief Receive packet over specified socket.
///
......
......@@ -84,13 +84,13 @@ public:
/// (because real values are rather less than 255). Values greater
/// than 255 are not recommended because they cause warnings to be
/// reported by Valgrind when invoking close() on them.
virtual int openSocket(const Iface&,
const isc::asiolink::IOAddress&,
const uint16_t,
const bool,
const bool) {
virtual SocketInfo openSocket(const Iface&,
const isc::asiolink::IOAddress& addr,
const uint16_t port,
const bool,
const bool) {
open_socket_called_ = true;
return (255);
return (SocketInfo(addr, port, 255));
}
/// Does nothing
......@@ -1152,18 +1152,28 @@ TEST_F(IfaceMgrTest, iface_methods) {
TEST_F(IfaceMgrTest, socketInfo) {
// Check that socketinfo for IPv4 socket is functional
SocketInfo sock1(7, IOAddress("192.0.2.56"), DHCP4_SERVER_PORT + 7);
SocketInfo sock1(IOAddress("192.0.2.56"), DHCP4_SERVER_PORT + 7, 7);
EXPECT_EQ(7, sock1.sockfd_);
EXPECT_EQ(-1, sock1.fallbackfd_);
EXPECT_EQ("192.0.2.56", sock1.addr_.toText());
EXPECT_EQ(AF_INET, sock1.family_);
EXPECT_EQ(DHCP4_SERVER_PORT + 7, sock1.port_);
// Check that non-default value of the fallback socket descriptor is set
SocketInfo sock2(IOAddress("192.0.2.53"), DHCP4_SERVER_PORT + 8, 8, 10);
EXPECT_EQ(8, sock2.sockfd_);
EXPECT_EQ(10, sock2.fallbackfd_);
EXPECT_EQ("192.0.2.53", sock2.addr_.toText());
EXPECT_EQ(AF_INET, sock2.family_);
EXPECT_EQ(DHCP4_SERVER_PORT + 8, sock2.port_);
// Check that socketinfo for IPv6 socket is functional
SocketInfo sock2(9, IOAddress("2001:db8:1::56"), DHCP4_SERVER_PORT + 9);
EXPECT_EQ(9, sock2.sockfd_);
EXPECT_EQ("2001:db8:1::56", sock2.addr_.toText());
EXPECT_EQ(AF_INET6, sock2.family_);
EXPECT_EQ(DHCP4_SERVER_PORT + 9, sock2.port_);
SocketInfo sock3(IOAddress("2001:db8:1::56"), DHCP4_SERVER_PORT + 9, 9);
EXPECT_EQ(9, sock3.sockfd_);
EXPECT_EQ(-1, sock3.fallbackfd_);
EXPECT_EQ("2001:db8:1::56", sock3.addr_.toText());
EXPECT_EQ(AF_INET6, sock3.family_);
EXPECT_EQ(DHCP4_SERVER_PORT + 9, sock3.port_);
// Now let's test if IfaceMgr handles socket info properly
scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
......@@ -1171,6 +1181,7 @@ TEST_F(IfaceMgrTest, socketInfo) {
ASSERT_TRUE(loopback);
loopback->addSocket(sock1);
loopback->addSocket(sock2);
loopback->addSocket(sock3);
Pkt6 pkt6(DHCPV6_REPLY, 123456);
......@@ -1225,6 +1236,7 @@ TEST_F(IfaceMgrTest, socketInfo) {
EXPECT_NO_THROW(
ifacemgr->getIface(LOOPBACK)->delSocket(7);
ifacemgr->getIface(LOOPBACK)->delSocket(8);
);
// It should throw again, there's no usable socket anymore.
......
......@@ -112,7 +112,7 @@ TEST_F(PktFilterInetTest, openSocket) {
// Try to open socket.
PktFilterInet pkt_filter;
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false).sockfd_;
// Check that socket has been opened.
ASSERT_GE(socket_, 0);
......@@ -170,7 +170,7 @@ TEST_F(PktFilterInetTest, send) {
// Open socket. We don't check that the socket has appropriate
// options and family set because we have checked that in the
// openSocket test already.
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false).sockfd_;
ASSERT_GE(socket_, 0);
// Send the packet over the socket.
......@@ -249,14 +249,14 @@ TEST_F(PktFilterInetTest, receive) {
// Open socket. We don't check that the socket has appropriate
// options and family set because we have checked that in the
// openSocket test already.
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false).sockfd_;
ASSERT_GE(socket_, 0);
// Send the packet over the socket.
ASSERT_NO_THROW(pkt_filter.send(iface, socket_, pkt));
// Receive the packet.
SocketInfo socket_info(socket_, IOAddress("127.0.0.1"), PORT);
SocketInfo socket_info(IOAddress("127.0.0.1"), PORT, socket_);
Pkt4Ptr rcvd_pkt = pkt_filter.receive(iface, socket_info);
// Check that the packet has been correctly received.
ASSERT_TRUE(rcvd_pkt);
......
......@@ -124,7 +124,7 @@ TEST_F(PktFilterLPFTest, DISABLED_openSocket) {
// Try to open socket.
PktFilterLPF pkt_filter;
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false).sockfd_;
// Check that socket has been opened.
ASSERT_GE(socket_, 0);
......@@ -183,7 +183,7 @@ TEST_F(PktFilterLPFTest, DISABLED_send) {
// Open socket. We don't check that the socket has appropriate
// options and family set because we have checked that in the
// openSocket test already.
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false).sockfd_;
ASSERT_GE(socket_, 0);
// Send the packet over the socket.
......@@ -273,7 +273,7 @@ TEST_F(PktFilterLPFTest, DISABLED_receive) {
// Open socket. We don't check that the socket has appropriate
// options and family set because we have checked that in the
// openSocket test already.
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
socket_ = pkt_filter.openSocket(iface, addr, PORT, false, false).sockfd_;
ASSERT_GE(socket_, 0);
// Send the packet over the socket.
......
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