Commit c3a1e566 authored by Marcin Siodelski's avatar Marcin Siodelski

[3970] Propagate errors emitted when closing the WatchSocket.

parent 1d8fe4c3
...@@ -89,14 +89,8 @@ caught in the application's send completion handler. This is a programmatic ...@@ -89,14 +89,8 @@ caught in the application's send completion handler. This is a programmatic
error that needs to be reported. Dependent upon the nature of the error the error that needs to be reported. Dependent upon the nature of the error the
client may or may not continue operating normally. client may or may not continue operating normally.
% DHCP_DDNS_WATCH_SINK_CLOSE_ERROR Sink-side watch socket failed to close: %1 % DHCP_DDNS_UDP_SENDER_WATCH_SOCKET_CLOSE_ERROR watch socket failed to close: %1
This is an error message that indicates the application was unable to close This is an error message that indicates the application was unable to close
the inbound side of a NCR sender's watch socket. While technically possible the inbound or outbound side of a NCR sender's watch socket. While technically
this error is highly unlikely to occur and should not impair the application's possible the error is highly unlikely to occur and should not impair the
ability to process requests. application's ability to process requests.
% DHCP_DDNS_WATCH_SOURCE_CLOSE_ERROR Source-side watch socket failed to close: %1
This is an error message that indicates the application was unable to close
the outbound side of a NCR sender's watch socket. While technically possible
this error is highly unlikely to occur and should not impair the application's
ability to process requests.
...@@ -260,6 +260,7 @@ NameChangeUDPSender::open(isc::asiolink::IOService& io_service) { ...@@ -260,6 +260,7 @@ NameChangeUDPSender::open(isc::asiolink::IOService& io_service) {
send_callback_->setDataSource(server_endpoint_); send_callback_->setDataSource(server_endpoint_);
closeWatchSocket();
watch_socket_.reset(new util::WatchSocket()); watch_socket_.reset(new util::WatchSocket());
} }
...@@ -288,6 +289,7 @@ NameChangeUDPSender::close() { ...@@ -288,6 +289,7 @@ NameChangeUDPSender::close() {
socket_.reset(); socket_.reset();
closeWatchSocket();
watch_socket_.reset(); watch_socket_.reset();
} }
...@@ -372,7 +374,17 @@ NameChangeUDPSender::ioReady() { ...@@ -372,7 +374,17 @@ NameChangeUDPSender::ioReady() {
return (false); return (false);
} }
void
NameChangeUDPSender::closeWatchSocket() {
if (watch_socket_) {
std::string error_string;
watch_socket_->closeSocket(error_string);
if (!error_string.empty()) {
LOG_ERROR(dhcp_ddns_logger, DHCP_DDNS_UDP_SENDER_WATCH_SOCKET_CLOSE_ERROR)
.arg(error_string);
}
}
}
}; // end of isc::dhcp_ddns namespace }; // end of isc::dhcp_ddns namespace
}; // end of isc namespace }; // end of isc namespace
...@@ -548,6 +548,13 @@ public: ...@@ -548,6 +548,13 @@ public:
virtual bool ioReady(); virtual bool ioReady();
private: private:
/// @brief Closes watch socket if the socket is open.
///
/// This method closes watch socket if its instance exists and if the
/// socket is open. An error message is logged when this operation fails.
void closeWatchSocket();
/// @brief IP address from which to send. /// @brief IP address from which to send.
isc::asiolink::IOAddress ip_address_; isc::asiolink::IOAddress ip_address_;
......
...@@ -231,4 +231,27 @@ TEST(WatchSocketTest, badReadOnClear) { ...@@ -231,4 +231,27 @@ TEST(WatchSocketTest, badReadOnClear) {
ASSERT_THROW(watch->markReady(), WatchSocketError); ASSERT_THROW(watch->markReady(), WatchSocketError);
} }
/// @brief Checks if the socket can be explicitly closed.
TEST(WatchSocketTest, explicitClose) {
WatchSocketPtr watch;
// Create new instance of the socket.
ASSERT_NO_THROW(watch.reset(new WatchSocket()));
ASSERT_TRUE(watch);
// Make sure it has been opened by checking that its descriptor
// is valid.
EXPECT_NE(watch->getSelectFd(), WatchSocket::SOCKET_NOT_VALID);
// Close the socket.
std::string error_string;
ASSERT_TRUE(watch->closeSocket(error_string));
// Make sure that the descriptor is now invalid which indicates
// that the socket has been closed.
EXPECT_EQ(WatchSocket::SOCKET_NOT_VALID, watch->getSelectFd());
// No errors should be reported.
EXPECT_TRUE(error_string.empty());
}
} // end of anonymous namespace } // end of anonymous namespace
...@@ -116,17 +116,19 @@ WatchSocket::clearReady() { ...@@ -116,17 +116,19 @@ WatchSocket::clearReady() {
} }
} }
void bool
WatchSocket::closeSocket() { WatchSocket::closeSocket(std::string& error_string) {
// Clear error string.
error_string.clear();
// Close the pipe fds. Technically a close can fail (hugely unlikely) // Close the pipe fds. Technically a close can fail (hugely unlikely)
// but there's no recovery for it either. If one does fail we log it // but there's no recovery for it either. If one does fail we log it
// and go on. Plus this is called by the destructor and no one likes // and go on. Plus this is called by the destructor and no one likes
// destructors that throw. // destructors that throw.
if (source_ != SOCKET_NOT_VALID) { if (source_ != SOCKET_NOT_VALID) {
if (close(source_)) { if (close(source_)) {
/* const char* errstr = strerror(errno); // An error occured.
LOG_ERROR(dhcp_ddns_logger, DHCP_DDNS_WATCH_SOURCE_CLOSE_ERROR) error_string = strerror(errno);
.arg(errstr); */
} }
source_ = SOCKET_NOT_VALID; source_ = SOCKET_NOT_VALID;
...@@ -134,13 +136,23 @@ WatchSocket::closeSocket() { ...@@ -134,13 +136,23 @@ WatchSocket::closeSocket() {
if (sink_ != SOCKET_NOT_VALID) { if (sink_ != SOCKET_NOT_VALID) {
if (close(sink_)) { if (close(sink_)) {
/* const char* errstr = strerror(errno); // An error occured.
LOG_ERROR(dhcp_ddns_logger, DHCP_DDNS_WATCH_SINK_CLOSE_ERROR) if (error_string.empty()) {
.arg(errstr); */ error_string = strerror(errno);
}
} }
sink_ = SOCKET_NOT_VALID; sink_ = SOCKET_NOT_VALID;
} }
// If any errors have been reported, return false.
return (error_string.empty() ? true : false);
}
void
WatchSocket::closeSocket() {
std::string error_string;
closeSocket(error_string);
} }
int int
......
...@@ -114,11 +114,23 @@ public: ...@@ -114,11 +114,23 @@ public:
/// pipe. /// pipe.
int getSelectFd(); int getSelectFd();
/// @brief Closes the descriptors associated with the socket.
///
/// This method is used to close the socket and capture errors that
/// may occur during this operation.
///
/// @param [out] error_string Holds the error string if closing
/// the socket failed. It will hold empty string otherwise.
///
/// @return true if the operation was successful, false otherwise.
bool closeSocket(std::string& error_string);
private: private:
/// @brief Closes the descriptors associated with the socket. /// @brief Closes the descriptors associated with the socket.
/// ///
/// Used internally in the destructor and if an error occurs marking or /// This method is called by the class destructor and it ignores
/// clearing the socket. /// any errors that may occur while closing the sockets.
void closeSocket(); void closeSocket();
/// @brief The end of the pipe to which the marker is written /// @brief The end of the pipe to which the marker is written
......
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