]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#4141] addressed review comments
authorRazvan Becheriu <razvan@isc.org>
Fri, 14 Nov 2025 08:22:40 +0000 (10:22 +0200)
committerRazvan Becheriu <razvan@isc.org>
Fri, 21 Nov 2025 13:02:43 +0000 (13:02 +0000)
20 files changed:
src/lib/dhcp/iface_mgr.cc
src/lib/dhcp/iface_mgr.h
src/lib/dhcp/tests/iface_mgr_unittest.cc
src/lib/log/interprocess/tests/interprocess_sync_file_unittest.cc
src/lib/testutils/unix_control_client.cc
src/lib/testutils/unix_control_client.h
src/lib/util/epoll_event_handler.cc
src/lib/util/epoll_event_handler.h
src/lib/util/fd_event_handler.cc
src/lib/util/fd_event_handler.h
src/lib/util/kqueue_event_handler.cc
src/lib/util/kqueue_event_handler.h
src/lib/util/poll_event_handler.cc
src/lib/util/poll_event_handler.h
src/lib/util/ready_check.cc
src/lib/util/ready_check.h
src/lib/util/select_event_handler.cc
src/lib/util/select_event_handler.h
src/lib/util/tests/fd_event_handler_unittests.h
src/lib/util/tests/watch_socket_unittests.cc

index 41da10d7efbe786a867a8e97e7640cf3ab93468a..6ae7a51ff8c1e2087a490f1a3caa5451a2b81c90 100644 (file)
@@ -377,24 +377,6 @@ IfaceMgr::isExternalSocket(int fd) {
     return (false);
 }
 
-int
-IfaceMgr::purgeBadSockets() {
-    std::lock_guard<std::mutex> lock(callbacks_mutex_);
-    std::vector<int> bad_fds;
-    for (const SocketCallbackInfo& s : callbacks_) {
-        errno = 0;
-        if (fcntl(s.socket_, F_GETFD) < 0 && (errno == EBADF)) {
-            bad_fds.push_back(s.socket_);
-        }
-    }
-
-    for (auto bad_fd : bad_fds) {
-        deleteExternalSocketInternal(bad_fd);
-    }
-
-    return (bad_fds.size());
-}
-
 void
 IfaceMgr::deleteAllExternalSockets() {
     std::lock_guard<std::mutex> lock(callbacks_mutex_);
@@ -1143,9 +1125,14 @@ Pkt4Ptr IfaceMgr::receive4Indirect(uint32_t timeout_sec, uint32_t timeout_usec /
     {
         std::lock_guard<std::mutex> lock(callbacks_mutex_);
         if (!callbacks_.empty()) {
-            for (const SocketCallbackInfo& s : callbacks_) {
-                // Add this socket to listening set
-                fd_event_handler_->add(s.socket_);
+            for (SocketCallbackInfo& s : callbacks_) {
+                errno = 0;
+                if (fcntl(s.socket_, F_GETFD) < 0 && (errno == EBADF)) {
+                    s.unusable_ = true;
+                } else if (!s.unusable_) {
+                    // Add this socket to listening set
+                    fd_event_handler_->add(s.socket_);
+                }
             }
         }
     }
@@ -1185,11 +1172,6 @@ Pkt4Ptr IfaceMgr::receive4Indirect(uint32_t timeout_sec, uint32_t timeout_usec /
         // signal or for some other reason.
         if (errno == EINTR) {
             isc_throw(SignalInterruptOnSelect, strerror(errno));
-        } else if (errno == EBADF) {
-            int cnt = purgeBadSockets();
-            isc_throw(SocketReadError,
-                      "Event handler interrupted by one invalid sockets, purged "
-                       << cnt << " socket descriptors");
         } else {
             isc_throw(SocketReadError, strerror(errno));
         }
@@ -1207,14 +1189,9 @@ Pkt4Ptr IfaceMgr::receive4Indirect(uint32_t timeout_sec, uint32_t timeout_usec /
         // Let's find out which external socket has the data
         SocketCallbackInfo ex_sock;
         bool found = false;
-        bool fd_error = false;
         {
             std::lock_guard<std::mutex> lock(callbacks_mutex_);
             for (const SocketCallbackInfo& s : callbacks_) {
-                if (fd_event_handler_->hasError(s.socket_)) {
-                    fd_error = true;
-                    break;
-                }
                 if (!fd_event_handler_->readReady(s.socket_)) {
                     continue;
                 }
@@ -1229,12 +1206,6 @@ Pkt4Ptr IfaceMgr::receive4Indirect(uint32_t timeout_sec, uint32_t timeout_usec /
                 }
             }
         }
-        if (fd_error) {
-            int cnt = purgeBadSockets();
-            isc_throw(SocketReadError,
-                      "Event handler interrupted by one invalid sockets, purged "
-                       << cnt << " socket descriptors");
-        }
 
         if (ex_sock.callback_) {
             // Calling the external socket's callback provides its service
@@ -1286,9 +1257,14 @@ Pkt4Ptr IfaceMgr::receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec /*
     {
         std::lock_guard<std::mutex> lock(callbacks_mutex_);
         if (!callbacks_.empty()) {
-            for (const SocketCallbackInfo& s : callbacks_) {
-                // Add this socket to listening set
-                fd_event_handler_->add(s.socket_);
+            for (SocketCallbackInfo& s : callbacks_) {
+                errno = 0;
+                if (fcntl(s.socket_, F_GETFD) < 0 && (errno == EBADF)) {
+                    s.unusable_ = true;
+                } else if (!s.unusable_) {
+                    // Add this socket to listening set
+                    fd_event_handler_->add(s.socket_);
+                }
             }
         }
     }
@@ -1311,11 +1287,6 @@ Pkt4Ptr IfaceMgr::receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec /*
         // signal or for some other reason.
         if (errno == EINTR) {
             isc_throw(SignalInterruptOnSelect, strerror(errno));
-        } else if (errno == EBADF) {
-            int cnt = purgeBadSockets();
-            isc_throw(SocketReadError,
-                      "Event handler interrupted by one invalid sockets, purged "
-                       << cnt << " socket descriptors");
         } else {
             isc_throw(SocketReadError, strerror(errno));
         }
@@ -1324,14 +1295,9 @@ Pkt4Ptr IfaceMgr::receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec /*
     // Let's find out which socket has the data
     SocketCallbackInfo ex_sock;
     bool found = false;
-    bool fd_error = false;
     {
         std::lock_guard<std::mutex> lock(callbacks_mutex_);
         for (const SocketCallbackInfo& s : callbacks_) {
-            if (fd_event_handler_->hasError(s.socket_)) {
-                fd_error = true;
-                break;
-            }
             if (!fd_event_handler_->readReady(s.socket_)) {
                 continue;
             }
@@ -1346,12 +1312,6 @@ Pkt4Ptr IfaceMgr::receive4Direct(uint32_t timeout_sec, uint32_t timeout_usec /*
             }
         }
     }
-    if (fd_error) {
-        int cnt = purgeBadSockets();
-        isc_throw(SocketReadError,
-                  "Event handler interrupted by one invalid sockets, purged "
-                   << cnt << " socket descriptors");
-    }
 
     if (ex_sock.callback_) {
         // Calling the external socket's callback provides its service
@@ -1428,9 +1388,14 @@ IfaceMgr::receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ )
     {
         std::lock_guard<std::mutex> lock(callbacks_mutex_);
         if (!callbacks_.empty()) {
-            for (const SocketCallbackInfo& s : callbacks_) {
-                // Add this socket to listening set
-                fd_event_handler_->add(s.socket_);
+            for (SocketCallbackInfo& s : callbacks_) {
+                errno = 0;
+                if (fcntl(s.socket_, F_GETFD) < 0 && (errno == EBADF)) {
+                    s.unusable_ = true;
+                } else if (!s.unusable_) {
+                    // Add this socket to listening set
+                    fd_event_handler_->add(s.socket_);
+                }
             }
         }
     }
@@ -1453,11 +1418,6 @@ IfaceMgr::receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ )
         // signal or for some other reason.
         if (errno == EINTR) {
             isc_throw(SignalInterruptOnSelect, strerror(errno));
-        } else if (errno == EBADF) {
-            int cnt = purgeBadSockets();
-            isc_throw(SocketReadError,
-                      "Event handler interrupted by one invalid sockets, purged "
-                       << cnt << " socket descriptors");
         } else {
             isc_throw(SocketReadError, strerror(errno));
         }
@@ -1466,14 +1426,9 @@ IfaceMgr::receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ )
     // Let's find out which socket has the data
     SocketCallbackInfo ex_sock;
     bool found = false;
-    bool fd_error = false;
     {
         std::lock_guard<std::mutex> lock(callbacks_mutex_);
         for (const SocketCallbackInfo& s : callbacks_) {
-            if (fd_event_handler_->hasError(s.socket_)) {
-                fd_error = true;
-                break;
-            }
             if (!fd_event_handler_->readReady(s.socket_)) {
                 continue;
             }
@@ -1488,12 +1443,6 @@ IfaceMgr::receive6Direct(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */ )
             }
         }
     }
-    if (fd_error) {
-        int cnt = purgeBadSockets();
-        isc_throw(SocketReadError,
-                  "Event handler interrupted by one invalid sockets, purged "
-                   << cnt << " socket descriptors");
-    }
 
     if (ex_sock.callback_) {
         // Calling the external socket's callback provides its service
@@ -1540,9 +1489,14 @@ IfaceMgr::receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
     {
         std::lock_guard<std::mutex> lock(callbacks_mutex_);
         if (!callbacks_.empty()) {
-            for (const SocketCallbackInfo& s : callbacks_) {
-                // Add this socket to listening set
-                fd_event_handler_->add(s.socket_);
+            for (SocketCallbackInfo& s : callbacks_) {
+                errno = 0;
+                if (fcntl(s.socket_, F_GETFD) < 0 && (errno == EBADF)) {
+                    s.unusable_ = true;
+                } else if (!s.unusable_) {
+                    // Add this socket to listening set
+                    fd_event_handler_->add(s.socket_);
+                }
             }
         }
     }
@@ -1582,11 +1536,6 @@ IfaceMgr::receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
         // signal or for some other reason.
         if (errno == EINTR) {
             isc_throw(SignalInterruptOnSelect, strerror(errno));
-        } else if (errno == EBADF) {
-            int cnt = purgeBadSockets();
-            isc_throw(SocketReadError,
-                      "Event handler interrupted by one invalid sockets, purged "
-                       << cnt << " socket descriptors");
         } else {
             isc_throw(SocketReadError, strerror(errno));
         }
@@ -1604,14 +1553,9 @@ IfaceMgr::receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
         // Let's find out which external socket has the data
         SocketCallbackInfo ex_sock;
         bool found = false;
-        bool fd_error = false;
         {
             std::lock_guard<std::mutex> lock(callbacks_mutex_);
             for (const SocketCallbackInfo& s : callbacks_) {
-                if (fd_event_handler_->hasError(s.socket_)) {
-                    fd_error = true;
-                    break;
-                }
                 if (!fd_event_handler_->readReady(s.socket_)) {
                     continue;
                 }
@@ -1626,12 +1570,6 @@ IfaceMgr::receive6Indirect(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
                 }
             }
         }
-        if (fd_error) {
-            int cnt = purgeBadSockets();
-            isc_throw(SocketReadError,
-                      "Event handler interrupted by one invalid sockets, purged "
-                       << cnt << " socket descriptors");
-        }
 
         if (ex_sock.callback_) {
             // Calling the external socket's callback provides its service
index 7a5f27f92eaf8120541e2babfc74eedb3ff18bf7..00cb6aa58215c7f6f3754df1e22ba73c4f09e291 100644 (file)
@@ -676,6 +676,14 @@ public:
 
         /// A callback that will be called when data arrives over socket_.
         SocketCallback callback_;
+
+        /// @brief Indicates if the socket can no longer be used for normal
+        /// operations.
+        bool unusable_;
+
+        /// @brief Constructor.
+        SocketCallbackInfo() : socket_(-1), unusable_(false) {
+        }
     };
 
     /// Defines storage container for callbacks for external sockets
@@ -1167,17 +1175,6 @@ public:
     /// @param socketfd socket descriptor
     void deleteExternalSocket(int socketfd);
 
-    /// @brief Scans registered socket set and removes any that are invalid.
-    ///
-    /// Walks the list of registered external sockets and tests each for
-    /// validity.  If any are found to be invalid they are removed. This is
-    /// primarily a self-defense mechanism against hook libs or other users
-    /// of external sockets that may leave a closed socket registered by
-    /// mistake.
-    ///
-    /// @return A count of the sockets purged.
-    int purgeBadSockets();
-
     /// @brief Deletes all external sockets.
     void deleteAllExternalSockets();
 
index 95c2820938e6efe2fe3aa0fc10803036a1094ebb..d69d93b6b3b4adbdcb1acae758cef64981b06688 100644 (file)
@@ -676,12 +676,12 @@ public:
     }
 
     /// @brief Verifies that IfaceMgr DHCPv4 receive calls detect and
-    /// purge external sockets that have gone bad without affecting
+    /// ignore external sockets that have gone bad without affecting
     /// affecting normal operations.  It can be run with or without
     /// packet queuing.
     ///
     /// @param use_queue determines if packet queuing is used or not.
-    void purgeExternalSockets4Test(bool use_queue = false) {
+    void unusableExternalSockets4Test(bool use_queue = false) {
         bool callback_ok = false;
         bool callback2_ok = false;
 
@@ -734,10 +734,8 @@ public:
         // We call receive4() which should detect and remove the invalid socket.
         try {
             pkt4 = ifacemgr->receive4(RECEIVE_WAIT_MS(10));
-            ADD_FAILURE() << "receive4 should have failed";
         } catch (const SocketReadError& ex) {
-            EXPECT_EQ(std::string("Event handler interrupted by one invalid sockets,"
-                                  " purged 1 socket descriptors"),
+            EXPECT_EQ(std::string("Bad file descriptor"),
                       std::string(ex.what()));
         } catch (const std::exception& ex) {
             ADD_FAILURE() << "wrong exception thrown: " << ex.what();
@@ -766,12 +764,12 @@ public:
     }
 
     /// @brief Verifies that IfaceMgr DHCPv6 receive calls detect and
-    /// purge external sockets that have gone bad without affecting
+    /// ignore external sockets that have gone bad without affecting
     /// affecting normal operations.  It can be run with or without
     /// packet queuing.
     ///
     /// @param use_queue determines if packet queuing is used or not.
-    void purgeExternalSockets6Test(bool use_queue = false) {
+    void unusableExternalSockets6Test(bool use_queue = false) {
         bool callback_ok = false;
         bool callback2_ok = false;
 
@@ -824,10 +822,8 @@ public:
         // We call receive6() which should detect and remove the invalid socket.
         try {
             pkt6 = ifacemgr->receive6(RECEIVE_WAIT_MS(10));
-            ADD_FAILURE() << "receive6 should have failed";
         } catch (const SocketReadError& ex) {
-            EXPECT_EQ(std::string("Event handler interrupted by one invalid sockets,"
-                                  " purged 1 socket descriptors"),
+            EXPECT_EQ(std::string("Bad file descriptor"),
                       std::string(ex.what()));
         } catch (const std::exception& ex) {
             ADD_FAILURE() << "wrong exception thrown: " << ex.what();
@@ -3164,18 +3160,18 @@ TEST_F(IfaceMgrTest, DeleteExternalSockets4) {
 }
 
 // Tests that an existing external socket that becomes invalid
-// is detected and purged, without affecting other sockets.
+// is detected and ignored, without affecting other sockets.
 // Tests uses receive4() without queuing.
-TEST_F(IfaceMgrTest, purgeExternalSockets4Direct) {
-    purgeExternalSockets4Test();
+TEST_F(IfaceMgrTest, unusableExternalSockets4Direct) {
+    unusableExternalSockets4Test();
 }
 
 
 // Tests that an existing external socket that becomes invalid
-// is detected and purged, without affecting other sockets.
+// is detected and ignored, without affecting other sockets.
 // Tests uses receive4() with queuing.
-TEST_F(IfaceMgrTest, purgeExternalSockets4Indirect) {
-    purgeExternalSockets4Test(true);
+TEST_F(IfaceMgrTest, unusableExternalSockets4Indirect) {
+    unusableExternalSockets4Test(true);
 }
 
 // Tests if a single external socket and its callback can be passed and
@@ -3347,18 +3343,18 @@ TEST_F(IfaceMgrTest, DeleteExternalSockets6) {
 }
 
 // Tests that an existing external socket that becomes invalid
-// is detected and purged, without affecting other sockets.
+// is detected and ignored, without affecting other sockets.
 // Tests uses receive6() without queuing.
-TEST_F(IfaceMgrTest, purgeExternalSockets6Direct) {
-    purgeExternalSockets6Test();
+TEST_F(IfaceMgrTest, unusableExternalSockets6Direct) {
+    unusableExternalSockets6Test();
 }
 
 
 // Tests that an existing external socket that becomes invalid
-// is detected and purged, without affecting other sockets.
+// is detected and ignored, without affecting other sockets.
 // Tests uses receive6() with queuing.
-TEST_F(IfaceMgrTest, purgeExternalSockets6Indirect) {
-    purgeExternalSockets6Test(true);
+TEST_F(IfaceMgrTest, unusableExternalSockets6Indirect) {
+    unusableExternalSockets6Test(true);
 }
 
 // Test checks if the unicast sockets can be opened.
index d80f288be36bb91afe13a4b85ba18b6926d0c333..b7babc4e23ae8fb5165960c99a2b07f4a125b7df 100644 (file)
@@ -37,6 +37,8 @@ TEST(InterprocessSyncFileTest, TestLock) {
     if (!isc::util::unittests::runningOnValgrind()) {
 
         int fds[2];
+        int pid;
+        int status;
 
         // Here, we check that a lock has been taken by forking and
         // checking from the child that a lock exists. This has to be
@@ -46,8 +48,8 @@ TEST(InterprocessSyncFileTest, TestLock) {
         // attempt must fail to pass our check.
 
         EXPECT_EQ(0, pipe(fds));
-
-        if (fork() == 0) {
+        pid = fork();
+        if (pid == 0) {
             unsigned char locked = 0;
             // Child writes to pipe
             close(fds[0]);
@@ -65,6 +67,8 @@ TEST(InterprocessSyncFileTest, TestLock) {
             ssize_t bytes_written = write(fds[1], &locked, sizeof(locked));
             EXPECT_EQ(sizeof(locked), bytes_written);
 
+            sleep(1);
+
             close(fds[1]);
             exit(0);
         } else {
@@ -76,6 +80,8 @@ TEST(InterprocessSyncFileTest, TestLock) {
             close(fds[0]);
 
             EXPECT_EQ(1, locked);
+
+            waitpid(pid, &status, 0);
         }
     }
 
@@ -111,10 +117,12 @@ TEST(InterprocessSyncFileTest, TestMultipleFilesForked) {
     if (!isc::util::unittests::runningOnValgrind()) {
 
         int fds[2];
+        int pid;
+        int status;
 
         EXPECT_EQ(0, pipe(fds));
-
-        if (fork() == 0) {
+        pid = fork();
+        if (pid == 0) {
             unsigned char locked = 0xff;
             // Child writes to pipe
             close(fds[0]);
@@ -129,6 +137,8 @@ TEST(InterprocessSyncFileTest, TestMultipleFilesForked) {
             ssize_t bytes_written = write(fds[1], &locked, sizeof(locked));
             EXPECT_EQ(sizeof(locked), bytes_written);
 
+            sleep(1);
+
             close(fds[1]);
             exit(0);
         } else {
@@ -143,6 +153,8 @@ TEST(InterprocessSyncFileTest, TestMultipleFilesForked) {
         }
 
         EXPECT_EQ (0, remove(TEST_DATA_TOPBUILDDIR "/test2_lockfile"));
+
+        waitpid(pid, &status, 0);
     }
 
     EXPECT_TRUE(locker.unlock());
index 3a426d84fdab2fa786000e10a3185be7d7163221..f561115a04d0dfe6022fb06c13bfe8a65080b45f 100644 (file)
@@ -78,18 +78,6 @@ bool UnixControlClient::sendCommand(const std::string& command) {
         ADD_FAILURE() << "send command with closed socket";
         return (false);
     }
-    switch (selectCheck(3, false, true)) {
-    case -1: {
-        const char* errmsg = strerror(errno);
-        ADD_FAILURE() << "sendCommand - select failed: " << errmsg;
-        return (false);
-    }
-    case 0:
-        return (false);
-
-    default:
-        break;
-    }
     // Send command
     int bytes_sent = send(socket_fd_, command.c_str(), command.length(), 0);
     if (bytes_sent < static_cast<int>(command.length())) {
@@ -108,7 +96,7 @@ bool UnixControlClient::getResponse(std::string& response,
     // Receive response
     char buf[65536];
     memset(buf, 0, sizeof(buf));
-    switch (selectCheck(timeout_sec, true, false)) {
+    switch (selectCheck(timeout_sec)) {
     case -1: {
         const char* errmsg = strerror(errno);
         ADD_FAILURE() << "getResponse - select failed: " << errmsg;
@@ -134,9 +122,7 @@ bool UnixControlClient::getResponse(std::string& response,
     return (true);
 }
 
-int UnixControlClient::selectCheck(const unsigned int timeout_sec,
-                                   bool read_check,
-                                   bool write_check) {
+int UnixControlClient::selectCheck(const unsigned int timeout_sec) {
     if (socket_fd_ < 0) {
         ADD_FAILURE() << "select check with closed socket";
         return (-1);
@@ -146,7 +132,7 @@ int UnixControlClient::selectCheck(const unsigned int timeout_sec,
         return (-1);
     }
 
-    return (util::selectCheck(socket_fd_, timeout_sec, read_check, write_check));
+    return (util::selectCheck(socket_fd_, timeout_sec));
 }
 
 }
index d0a58a72641c1168bab265211a05cdc60e39fe69..c62b5fc5fcab1b4788e5b08a32b1ade960c1e5c1 100644 (file)
@@ -52,11 +52,8 @@ public:
     /// @brief Uses select to poll the Control Channel for data waiting
     ///
     /// @param timeout_sec Select timeout in seconds
-    /// @param read_check flag to check socket for read ready state
-    /// @param write_check flag to check socket for write ready state
     /// @return -1 on error, 0 if no data is available, 1 if data is ready
-    int selectCheck(const unsigned int timeout_sec, bool read_check,
-                    bool write_check);
+    int selectCheck(const unsigned int timeout_sec);
 
     /// @brief Retains the fd of the open socket
     int socket_fd_;
index b16715a344abcba31d39ea7d5034e721ac0f694b..985eea7e3f7ab8e224917cc75214ca2e40851a1a 100644 (file)
@@ -36,21 +36,15 @@ EPollEventHandler::~EPollEventHandler() {
     close(pipefd_[0]);
 }
 
-void EPollEventHandler::add(int fd, bool read /* = true */, bool write /* = false */) {
+void EPollEventHandler::add(int fd) {
     if (fd < 0) {
         isc_throw(BadValue, "invalid negative value for fd");
     }
     struct epoll_event data;
     memset(&data, 0, sizeof(data));
     data.data.fd = fd;
-    if (read) {
-        // Add this socket to read events
-        data.events |= EPOLLIN;
-    }
-    if (write) {
-        // Add this socket to write events
-        data.events |= EPOLLOUT;
-    }
+    // Add this socket to read events
+    data.events |= EPOLLIN;
     data_.push_back(data);
 }
 
@@ -89,6 +83,9 @@ int EPollEventHandler::waitEvent(uint32_t timeout_sec, uint32_t timeout_usec /*
         result = epoll_wait(epollfd_, used_data_.data(), used_data_.size(), timeout);
         for (int i = 0; i < result; ++i) {
              map_[used_data_[i].data.fd] = &used_data_[i];
+             if (used_data_[i].events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP)) {
+                 errors_.insert(used_data_[i].data.fd);
+             }
         }
     }
     for (auto data : data_) {
@@ -99,7 +96,7 @@ int EPollEventHandler::waitEvent(uint32_t timeout_sec, uint32_t timeout_usec /*
         errno = saved_errno;
     }
     if (errors_.size()) {
-        return (errors_.size());
+        return (-1);
     }
     return (result);
 }
@@ -111,23 +108,6 @@ bool EPollEventHandler::readReady(int fd) {
     return (map_[fd]->events & EPOLLIN);
 }
 
-bool EPollEventHandler::writeReady(int fd) {
-    if (map_.find(fd) == map_.end()) {
-        return (false);
-    }
-    return (map_[fd]->events & EPOLLOUT);
-}
-
-bool EPollEventHandler::hasError(int fd) {
-    if (errors_.count(fd)) {
-        return (true);
-    }
-    if (map_.find(fd) == map_.end()) {
-        return (false);
-    }
-    return (map_[fd]->events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP));
-}
-
 void EPollEventHandler::clear() {
     data_.clear();
     used_data_.clear();
index 69c28faf9045474493e57ffe891eb96609207152..23bde2475786a3f7224f21c1840956a22a4d600e 100644 (file)
@@ -31,11 +31,7 @@ public:
     /// @brief Add file descriptor to watch for events.
     ///
     /// @param fd The file descriptor.
-    /// @param read The flag indicating if the file descriptor should be
-    /// registered for read ready events.
-    /// @param write The flag indicating if the file descriptor should be
-    /// registered for write ready events.
-    void add(int fd, bool read = true, bool write = false);
+    void add(int fd);
 
     /// @brief Wait for events on registered file descriptors.
     ///
@@ -55,20 +51,6 @@ public:
     /// @return True if file descriptor is ready for reading.
     bool readReady(int fd);
 
-    /// @brief Check if file descriptor is ready for write operation.
-    ///
-    /// @param fd The file descriptor.
-    ///
-    /// @return True if file descriptor is ready for writing.
-    bool writeReady(int fd);
-
-    /// @brief Check if file descriptor has error.
-    ///
-    /// @param fd The file descriptor.
-    ///
-    /// @return True if file descriptor has error.
-    virtual bool hasError(int fd);
-
     /// @brief Clear registered file descriptors.
     void clear();
 
index bc8d0d4ecf17b4aed2dd14c81b80a6e9d67dd272..9f9b778e0997f07db8f4bd265e758c046057f4f9 100644 (file)
@@ -18,9 +18,5 @@ FDEventHandler::HandlerType FDEventHandler::type() {
     return (type_);
 }
 
-bool FDEventHandler::hasError(int /* fd */) {
-    return (false);
-}
-
 } // end of namespace isc::util
 } // end of namespace isc
index 671c29c9139b5d637a0a4e77313b889df5da64b3..8cd1b7e13fa2d6e1b802df4aebbcdf0f7f185435 100644 (file)
@@ -36,11 +36,7 @@ public:
     /// @brief Add file descriptor to watch for events.
     ///
     /// @param fd The file descriptor.
-    /// @param read The flag indicating if the file descriptor should be
-    /// registered for read ready events.
-    /// @param write The flag indicating if the file descriptor should be
-    /// registered for write ready events.
-    virtual void add(int fd, bool read = true, bool write = false) = 0;
+    virtual void add(int fd) = 0;
 
     /// @brief Wait for events on registered file descriptors.
     ///
@@ -60,20 +56,6 @@ public:
     /// @return True if file descriptor is ready for reading.
     virtual bool readReady(int fd) = 0;
 
-    /// @brief Check if file descriptor is ready for write operation.
-    ///
-    /// @param fd The file descriptor.
-    ///
-    /// @return True if file descriptor is ready for writing.
-    virtual bool writeReady(int fd) = 0;
-
-    /// @brief Check if file descriptor has error.
-    ///
-    /// @param fd The file descriptor.
-    ///
-    /// @return True if file descriptor has error.
-    virtual bool hasError(int fd);
-
     /// @brief Clear registered file descriptors.
     virtual void clear() = 0;
 
index 3a97aee8acb595715480a19f64daabf1d270c05f..2fa48daa37e15094e6913f757c4531ebefdecb1c 100644 (file)
@@ -36,24 +36,15 @@ KQueueEventHandler::~KQueueEventHandler() {
     close(pipefd_[0]);
 }
 
-void KQueueEventHandler::add(int fd, bool read /* = true */, bool write /* = false */) {
+void KQueueEventHandler::add(int fd) {
     if (fd < 0) {
         isc_throw(BadValue, "invalid negative value for fd");
     }
-    if (read) {
-        // Add this socket to read events
-        struct kevent data;
-        memset(&data, 0, sizeof(data));
-        EV_SET(&data, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
-        data_.push_back(data);
-    }
-    if (write) {
-        // Add this socket to write events
-        struct kevent data;
-        memset(&data, 0, sizeof(data));
-        EV_SET(&data, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
-        data_.push_back(data);
-    }
+    struct kevent data;
+    memset(&data, 0, sizeof(data));
+    // Add this socket to read events
+    EV_SET(&data, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
+    data_.push_back(data);
 }
 
 int KQueueEventHandler::waitEvent(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */,
@@ -93,6 +84,9 @@ int KQueueEventHandler::waitEvent(uint32_t timeout_sec, uint32_t timeout_usec /*
         result = kevent(kqueuefd_, 0, 0, used_data_.data(), used_data_.size(), select_timeout_p);
         for (int i = 0; i < result; ++i) {
             map_.emplace(used_data_[i].ident, &used_data_[i]);
+             if (used_data_[i].flags & EV_EOF || used_data_[i].filter == EV_ERROR) {
+                 errors_.insert(used_data_[i].ident);
+             }
         }
     }
     for (auto data : data_) {
@@ -105,7 +99,7 @@ int KQueueEventHandler::waitEvent(uint32_t timeout_sec, uint32_t timeout_usec /*
         errno = saved_errno;
     }
     if (errors_.size()) {
-        return (errors_.size());
+        return (-1);
     }
     return (result);
 }
@@ -120,29 +114,6 @@ bool KQueueEventHandler::readReady(int fd) {
     return (false);
 }
 
-bool KQueueEventHandler::writeReady(int fd) {
-    auto range = map_.equal_range(fd);
-    for (auto it = range.first; it != range.second; ++it) {
-        if (it->second->filter == EVFILT_WRITE) {
-            return (true);
-        }
-    }
-    return (false);
-}
-
-bool KQueueEventHandler::hasError(int fd) {
-    if (errors_.count(fd)) {
-        return (true);
-    }
-    auto range = map_.equal_range(fd);
-    for (auto it = range.first; it != range.second; ++it) {
-        if ((it->second->flags & EV_EOF) || (it->second->filter == EV_ERROR)) {
-            return (true);
-        }
-    }
-    return (false);
-}
-
 void KQueueEventHandler::clear() {
     data_.clear();
     used_data_.clear();
index 1123c0b02ae83f5d533f0ccbe1ca52e8991ae518..3eac6f2f5c09875ed7da8d1264a9c440aad2ce4a 100644 (file)
@@ -33,11 +33,7 @@ public:
     /// @brief Add file descriptor to watch for events.
     ///
     /// @param fd The file descriptor.
-    /// @param read The flag indicating if the file descriptor should be
-    /// registered for read ready events.
-    /// @param write The flag indicating if the file descriptor should be
-    /// registered for write ready events.
-    void add(int fd, bool read = true, bool write = false);
+    void add(int fd);
 
     /// @brief Wait for events on registered file descriptors.
     ///
@@ -57,20 +53,6 @@ public:
     /// @return True if file descriptor is ready for reading.
     bool readReady(int fd);
 
-    /// @brief Check if file descriptor is ready for write operation.
-    ///
-    /// @param fd The file descriptor.
-    ///
-    /// @return True if file descriptor is ready for writing.
-    bool writeReady(int fd);
-
-    /// @brief Check if file descriptor has error.
-    ///
-    /// @param fd The file descriptor.
-    ///
-    /// @return True if file descriptor has error.
-    virtual bool hasError(int fd);
-
     /// @brief Clear registered file descriptors.
     void clear();
 
index 6f6a0cd6c61dcf0c9ce7957d1405f930a3b934df..41c320642905dbbb984453acc138733c54fc2299 100644 (file)
@@ -18,21 +18,15 @@ PollEventHandler::PollEventHandler() : FDEventHandler(TYPE_POLL) {
     clear();
 }
 
-void PollEventHandler::add(int fd, bool read /* = true */, bool write /* = false */) {
+void PollEventHandler::add(int fd) {
     if (fd < 0) {
         isc_throw(BadValue, "invalid negative value for fd");
     }
     struct pollfd data;
     memset(&data, 0, sizeof(data));
     data.fd = fd;
-    if (read) {
-        // Add this socket to read events
-        data.events |= POLLIN;
-    }
-    if (write) {
-        // Add this socket to write events
-        data.events |= POLLOUT;
-    }
+    // Add this socket to read events
+    data.events |= POLLIN;
     data_.push_back(data);
 }
 
@@ -51,7 +45,13 @@ int PollEventHandler::waitEvent(uint32_t timeout_sec, uint32_t timeout_usec /* =
     for (size_t i = 0; i < data_.size(); ++i) {
         map_[data_[i].fd] = &data_[i];
     }
-    return (poll(data_.data(), data_.size(), timeout));
+    int result = poll(data_.data(), data_.size(), timeout);
+    for (auto data : data_) {
+        if (data.revents & (POLLHUP | POLLERR | POLLNVAL)) {
+            return (-1);
+        }
+    }
+    return (result);
 }
 
 bool PollEventHandler::readReady(int fd) {
@@ -61,20 +61,6 @@ bool PollEventHandler::readReady(int fd) {
     return (map_[fd]->revents & POLLIN);
 }
 
-bool PollEventHandler::writeReady(int fd) {
-    if (map_.find(fd) == map_.end()) {
-        return (false);
-    }
-    return (map_[fd]->revents & POLLOUT);
-}
-
-bool PollEventHandler::hasError(int fd) {
-    if (map_.find(fd) == map_.end()) {
-        return (false);
-    }
-    return (map_[fd]->revents & (POLLHUP | POLLERR | POLLNVAL));
-}
-
 void PollEventHandler::clear() {
     data_.clear();
     map_.clear();
index f102a0fc09dd565f2b7bfc54822dded645b2931a..6bee3175ac674f1a88bee1b4c4f74bbf06d144d2 100644 (file)
@@ -31,11 +31,7 @@ public:
     /// @brief Add file descriptor to watch for events.
     ///
     /// @param fd The file descriptor.
-    /// @param read The flag indicating if the file descriptor should be
-    /// registered for read ready events.
-    /// @param write The flag indicating if the file descriptor should be
-    /// registered for write ready events.
-    void add(int fd, bool read = true, bool write = false);
+    void add(int fd);
 
     /// @brief Wait for events on registered file descriptors.
     ///
@@ -55,20 +51,6 @@ public:
     /// @return True if file descriptor is ready for reading.
     bool readReady(int fd);
 
-    /// @brief Check if file descriptor is ready for write operation.
-    ///
-    /// @param fd The file descriptor.
-    ///
-    /// @return True if file descriptor is ready for writing.
-    bool writeReady(int fd);
-
-    /// @brief Check if file descriptor has error.
-    ///
-    /// @param fd The file descriptor.
-    ///
-    /// @return True if file descriptor has error.
-    virtual bool hasError(int fd);
-
     /// @brief Clear registered file descriptors.
     void clear();
 
index 703ee43dc87a7f3bada5948dfa45f0c419fdbb24..11f2705f2db3b8a88498cad57963315cdc00e199 100644 (file)
 namespace isc {
 namespace util {
 
-int selectCheck(const int fd_to_check, const unsigned int timeout_sec,
-                bool read_check, bool write_check) {
+int selectCheck(const int fd_to_check, const unsigned int timeout_sec) {
     FDEventHandlerPtr handler = FDEventHandlerFactory::factoryFDEventHandler();
-    handler->add(fd_to_check, read_check, write_check);
+    handler->add(fd_to_check);
     return (handler->waitEvent(timeout_sec, 0));
 }
 
index f06765dc6d453e094051a3ac85a084a12d365e9b..9b5d82126d77ab60736a22c61d2c0b0a3988670a 100644 (file)
@@ -12,11 +12,8 @@ namespace util {
 
 /// @param fd_to_check The file descriptor to test
 /// @param timeout_sec Select timeout in seconds
-/// @param read_check flag to check socket for read ready state
-/// @param write_check flag to check socket for write ready state
 /// @return -1 on error, 0 if no data is available, 1 if data is ready
-int selectCheck(const int fd_to_check, const unsigned int timeout_sec = 0,
-                bool read_check = true, bool write_check = false);
+int selectCheck(const int fd_to_check, const unsigned int timeout_sec = 0);
 
 } // end of isc::util namespace
 } // end of isc namespace
index 6334bc73c61c1fb2b427c5bcf988b7fba0c832fe..13f4377822ab40535e81cc31f46f4fc5393e4239 100644 (file)
@@ -25,21 +25,15 @@ SelectEventHandler::SelectEventHandler() : FDEventHandler(TYPE_SELECT), max_fd_(
     clear();
 }
 
-void SelectEventHandler::add(int fd, bool read /* = true */, bool write /* = false */) {
+void SelectEventHandler::add(int fd) {
     if (fd < 0) {
         isc_throw(BadValue, "invalid negative value for fd");
     }
     if (fd >= FD_SETSIZE) {
         isc_throw(BadValue, "invalid value for fd exceeds maximum allowed " << FD_SETSIZE);
     }
-    if (read) {
-        // Add this socket to read set
-        FD_SET(fd, &read_fd_set_);
-    }
-    if (write) {
-        // Add this socket to write set
-        FD_SET(fd, &write_fd_set_);
-    }
+    // Add this socket to read set
+    FD_SET(fd, &read_fd_set_);
     if (fd > max_fd_) {
         max_fd_ = fd;
     }
@@ -61,22 +55,16 @@ int SelectEventHandler::waitEvent(uint32_t timeout_sec, uint32_t timeout_usec /*
     }
 
     FD_COPY(&read_fd_set_, &read_fd_set_data_);
-    FD_COPY(&write_fd_set_, &write_fd_set_data_);
 
-    return (select(max_fd_ + 1, &read_fd_set_data_, &write_fd_set_data_, 0, select_timeout_p));
+    return (select(max_fd_ + 1, &read_fd_set_data_, 0, 0, select_timeout_p));
 }
 
 bool SelectEventHandler::readReady(int fd) {
     return (FD_ISSET(fd, &read_fd_set_data_));
 }
 
-bool SelectEventHandler::writeReady(int fd) {
-    return (FD_ISSET(fd, &write_fd_set_data_));
-}
-
 void SelectEventHandler::clear() {
     FD_ZERO(&read_fd_set_);
-    FD_ZERO(&write_fd_set_);
     max_fd_ = 0;
 }
 
index 45f9e96f0f961a4ca066b0f1b4a75891eb22694d..d0cfe8f872f18e892553ab6da95e6f4c1999f269 100644 (file)
@@ -27,11 +27,7 @@ public:
     /// @brief Add file descriptor to watch for events.
     ///
     /// @param fd The file descriptor.
-    /// @param read The flag indicating if the file descriptor should be
-    /// registered for read ready events.
-    /// @param write The flag indicating if the file descriptor should be
-    /// registered for write ready events.
-    void add(int fd, bool read = true, bool write = false);
+    void add(int fd);
 
     /// @brief Wait for events on registered file descriptors.
     ///
@@ -51,13 +47,6 @@ public:
     /// @return True if file descriptor is ready for reading.
     bool readReady(int fd);
 
-    /// @brief Check if file descriptor is ready for write operation.
-    ///
-    /// @param fd The file descriptor.
-    ///
-    /// @return True if file descriptor is ready for writing.
-    bool writeReady(int fd);
-
     /// @brief Clear registered file descriptors.
     void clear();
 
@@ -68,14 +57,8 @@ private:
     /// @brief The read event FD set.
     fd_set read_fd_set_;
 
-    /// @brief The write event FD set.
-    fd_set write_fd_set_;
-
     /// @brief The read event FD set.
     fd_set read_fd_set_data_;
-
-    /// @brief The write event FD set.
-    fd_set write_fd_set_data_;
 };
 
 }  // namespace isc::util;
index 2916a0ebe6149e6bd25fb1682a543641357fac0a..1b4d96fceba3865730f2038a8755b73fb7d84613 100644 (file)
@@ -64,58 +64,45 @@ TEST_F(FDEventHandlerTest, events) {
 
     EXPECT_THROW(handler_->add(-1), BadValue);
 
-    EXPECT_NO_THROW(handler_->add(pipefd_[0], true, false));
-    EXPECT_NO_THROW(handler_->add(pipefd_[1], false, true));
+    EXPECT_NO_THROW(handler_->add(pipefd_[0]));
 
     EXPECT_FALSE(handler_->readReady(pipefd_[0]));
-    EXPECT_FALSE(handler_->writeReady(pipefd_[0]));
     EXPECT_FALSE(handler_->readReady(pipefd_[1]));
-    EXPECT_FALSE(handler_->writeReady(pipefd_[1]));
 
-    EXPECT_EQ(1, handler_->waitEvent(0, 1000));
+    EXPECT_EQ(0, handler_->waitEvent(0, 1000));
 
     EXPECT_FALSE(handler_->readReady(pipefd_[0]));
-    EXPECT_FALSE(handler_->writeReady(pipefd_[0]));
     EXPECT_FALSE(handler_->readReady(pipefd_[1]));
-    EXPECT_TRUE(handler_->writeReady(pipefd_[1]));
 
     EXPECT_EQ(1, write(pipefd_[1], &MARKER, sizeof(MARKER)));
 
-    EXPECT_EQ(2, handler_->waitEvent(0, 1000));
+    EXPECT_EQ(1, handler_->waitEvent(0, 1000));
 
     EXPECT_TRUE(handler_->readReady(pipefd_[0]));
-    EXPECT_FALSE(handler_->writeReady(pipefd_[0]));
     EXPECT_FALSE(handler_->readReady(pipefd_[1]));
-    EXPECT_TRUE(handler_->writeReady(pipefd_[1]));
 
     EXPECT_EQ(1, write(pipefd_[1], &MARKER, sizeof(MARKER)));
 
-    EXPECT_EQ(2, handler_->waitEvent(0, 1000));
+    EXPECT_EQ(1, handler_->waitEvent(0, 1000));
 
     EXPECT_TRUE(handler_->readReady(pipefd_[0]));
-    EXPECT_FALSE(handler_->writeReady(pipefd_[0]));
     EXPECT_FALSE(handler_->readReady(pipefd_[1]));
-    EXPECT_TRUE(handler_->writeReady(pipefd_[1]));
 
     unsigned char data;
 
     EXPECT_EQ(1, read(pipefd_[0], &data, sizeof(data)));
 
-    EXPECT_EQ(2, handler_->waitEvent(0, 1000));
+    EXPECT_EQ(1, handler_->waitEvent(0, 1000));
 
     EXPECT_TRUE(handler_->readReady(pipefd_[0]));
-    EXPECT_FALSE(handler_->writeReady(pipefd_[0]));
     EXPECT_FALSE(handler_->readReady(pipefd_[1]));
-    EXPECT_TRUE(handler_->writeReady(pipefd_[1]));
 
     EXPECT_EQ(1, read(pipefd_[0], &data, sizeof(data)));
 
-    EXPECT_EQ(1, handler_->waitEvent(0, 1000));
+    EXPECT_EQ(0, handler_->waitEvent(0, 1000));
 
     EXPECT_FALSE(handler_->readReady(pipefd_[0]));
-    EXPECT_FALSE(handler_->writeReady(pipefd_[0]));
     EXPECT_FALSE(handler_->readReady(pipefd_[1]));
-    EXPECT_TRUE(handler_->writeReady(pipefd_[1]));
 
     EXPECT_NO_THROW(handler_->clear());
 
@@ -184,17 +171,14 @@ TEST_F(FDEventHandlerTest, badFD) {
     if (handler_->type() == FDEventHandler::TYPE_SELECT) {
         EXPECT_EQ(-1, handler_->waitEvent(0, 1000));
         EXPECT_TRUE(handler_->readReady(fd));
-        EXPECT_FALSE(handler_->hasError(fd));
         EXPECT_EQ(EBADF, errno);
     } else if (handler_->type() == FDEventHandler::TYPE_POLL) {
-        EXPECT_EQ(1, handler_->waitEvent(0, 1000));
+        EXPECT_EQ(-1, handler_->waitEvent(0, 1000));
         EXPECT_FALSE(handler_->readReady(fd));
-        EXPECT_TRUE(handler_->hasError(fd));
         EXPECT_EQ(0, errno);
     } else {
-        EXPECT_EQ(1, handler_->waitEvent(0, 1000));
+        EXPECT_EQ(-1, handler_->waitEvent(0, 1000));
         EXPECT_FALSE(handler_->readReady(fd));
-        EXPECT_TRUE(handler_->hasError(fd));
         EXPECT_EQ(EBADF, errno);
     }
 
index 4346d738c693976f3279ab69d67d851241f788d7..97af67217e0b288881bdb9a0472d96c03da5d8d0 100644 (file)
@@ -119,12 +119,6 @@ TEST(WatchSocketTest, closedWhileReady) {
     EXPECT_EQ(1, selectCheck(select_fd));
     EXPECT_TRUE(watch->isReady());
 
-    // The epoll event handler must be created before closing the socket.
-    // It creates an internal pipe which will match the closed fd and the
-    // check for bad file descriptor will fail.
-    FDEventHandlerPtr handler = FDEventHandlerFactory::factoryFDEventHandler();
-    bool use_select = FDEventHandlerFactory::factoryFDEventHandler()->type() == FDEventHandler::TYPE_SELECT;
-
     // Interfere by closing the fd.
     ASSERT_EQ(0, close(select_fd));
 
@@ -138,13 +132,7 @@ TEST(WatchSocketTest, closedWhileReady) {
     ASSERT_NO_THROW(watch->clearReady());
 
     // Verify the select_fd fails as socket is invalid/closed.
-    if (use_select) {
-        ASSERT_EQ(-1, selectCheck(select_fd));
-    } else {
-        handler->add(select_fd);
-        EXPECT_EQ(1, handler->waitEvent(0, 0));
-        ASSERT_TRUE(handler->hasError(select_fd));
-    }
+    ASSERT_EQ(-1, selectCheck(select_fd));
 
     // Verify that subsequent attempts to mark it will fail.
     ASSERT_THROW(watch->markReady(), WatchSocketError);
@@ -203,12 +191,6 @@ TEST(WatchSocketTest, badReadOnClear) {
     EXPECT_TRUE(watch->isReady());
     EXPECT_EQ(1, selectCheck(select_fd));
 
-    // The epoll event handler must be created before closing the socket.
-    // It creates an internal pipe which will match the closed fd and the
-    // check for bad file descriptor will fail.
-    FDEventHandlerPtr handler = FDEventHandlerFactory::factoryFDEventHandler();
-    bool use_select = FDEventHandlerFactory::factoryFDEventHandler()->type() == FDEventHandler::TYPE_SELECT;
-
     // Interfere by reading the fd. This should empty the read pipe.
     uint32_t buf = 0;
     ASSERT_EQ((read (select_fd, &buf, 1)), 1);
@@ -221,13 +203,7 @@ TEST(WatchSocketTest, badReadOnClear) {
 
     // Verify the select_fd does not evaluate to ready.
     EXPECT_FALSE(watch->isReady());
-    if (use_select) {
-        EXPECT_EQ(-1, selectCheck(select_fd));
-    } else {
-        handler->add(select_fd);
-        EXPECT_EQ(1, handler->waitEvent(0, 0));
-        EXPECT_TRUE(handler->hasError(select_fd));
-    }
+    EXPECT_EQ(-1, selectCheck(select_fd));
 
     // Verify that getSelectFd() returns INVALID.
     ASSERT_EQ(WatchSocket::SOCKET_NOT_VALID, watch->getSelectFd());