From: Marcin Siodelski Date: Mon, 25 Nov 2013 19:33:40 +0000 (+0100) Subject: [2765] Added fallback socket descriptor to SocketInfo structure. X-Git-Tag: bind10-1.2.0beta1-release~102^2~5^2~22 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4e225668a62a8fde0edb28a2938d968989f3cbc4;p=thirdparty%2Fkea.git [2765] Added fallback socket descriptor to SocketInfo structure. --- diff --git a/src/bin/dhcp4/tests/dhcp4_test_utils.h b/src/bin/dhcp4/tests/dhcp4_test_utils.h index ee19728ce5..208d342901 100644 --- a/src/bin/dhcp4/tests/dhcp4_test_utils.h +++ b/src/bin/dhcp4/tests/dhcp4_test_utils.h @@ -20,6 +20,7 @@ #define DHCP4_TEST_UTILS_H #include +#include #include #include #include @@ -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. diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc index 0ad35a508e..3b33671bcf 100644 --- a/src/lib/dhcp/iface_mgr.cc +++ b/src/lib/dhcp/iface_mgr.cc @@ -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 diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h index 2f48813cc2..bae67cc426 100644 --- a/src/lib/dhcp/iface_mgr.h +++ b/src/lib/dhcp/iface_mgr.h @@ -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) { } + }; diff --git a/src/lib/dhcp/pkt_filter.h b/src/lib/dhcp/pkt_filter.h index 204b25e6b6..f2a028d59b 100644 --- a/src/lib/dhcp/pkt_filter.h +++ b/src/lib/dhcp/pkt_filter.h @@ -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. /// diff --git a/src/lib/dhcp/pkt_filter_inet.cc b/src/lib/dhcp/pkt_filter_inet.cc index 62695e5949..79f318d161 100644 --- a/src/lib/dhcp/pkt_filter_inet.cc +++ b/src/lib/dhcp/pkt_filter_inet.cc @@ -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); } diff --git a/src/lib/dhcp/pkt_filter_inet.h b/src/lib/dhcp/pkt_filter_inet.h index 95c9224847..0a506f0a0d 100644 --- a/src/lib/dhcp/pkt_filter_inet.h +++ b/src/lib/dhcp/pkt_filter_inet.h @@ -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. /// diff --git a/src/lib/dhcp/pkt_filter_lpf.cc b/src/lib/dhcp/pkt_filter_lpf.cc index 8616ad7c9b..7faa341425 100644 --- a/src/lib/dhcp/pkt_filter_lpf.cc +++ b/src/lib/dhcp/pkt_filter_lpf.cc @@ -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); } diff --git a/src/lib/dhcp/pkt_filter_lpf.h b/src/lib/dhcp/pkt_filter_lpf.h index d36719fbae..279c86451f 100644 --- a/src/lib/dhcp/pkt_filter_lpf.h +++ b/src/lib/dhcp/pkt_filter_lpf.h @@ -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. /// diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc index 85ea491c09..f2bb773488 100644 --- a/src/lib/dhcp/tests/iface_mgr_unittest.cc +++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc @@ -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 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. diff --git a/src/lib/dhcp/tests/pkt_filter_inet_unittest.cc b/src/lib/dhcp/tests/pkt_filter_inet_unittest.cc index eaf2e62ef2..81ac0e740d 100644 --- a/src/lib/dhcp/tests/pkt_filter_inet_unittest.cc +++ b/src/lib/dhcp/tests/pkt_filter_inet_unittest.cc @@ -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); diff --git a/src/lib/dhcp/tests/pkt_filter_lpf_unittest.cc b/src/lib/dhcp/tests/pkt_filter_lpf_unittest.cc index 742a7c98c3..1b5fc4b738 100644 --- a/src/lib/dhcp/tests/pkt_filter_lpf_unittest.cc +++ b/src/lib/dhcp/tests/pkt_filter_lpf_unittest.cc @@ -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.