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_);
{
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_);
+ }
}
}
}
// 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));
}
// 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;
}
}
}
}
- 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
{
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_);
+ }
}
}
}
// 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));
}
// 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;
}
}
}
}
- 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
{
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_);
+ }
}
}
}
// 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));
}
// 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;
}
}
}
}
- 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
{
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_);
+ }
}
}
}
// 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));
}
// 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;
}
}
}
}
- 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
/// 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
/// @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();
}
/// @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;
// 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();
}
/// @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;
// 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();
}
// 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
}
// 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.
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
// 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]);
ssize_t bytes_written = write(fds[1], &locked, sizeof(locked));
EXPECT_EQ(sizeof(locked), bytes_written);
+ sleep(1);
+
close(fds[1]);
exit(0);
} else {
close(fds[0]);
EXPECT_EQ(1, locked);
+
+ waitpid(pid, &status, 0);
}
}
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]);
ssize_t bytes_written = write(fds[1], &locked, sizeof(locked));
EXPECT_EQ(sizeof(locked), bytes_written);
+ sleep(1);
+
close(fds[1]);
exit(0);
} else {
}
EXPECT_EQ (0, remove(TEST_DATA_TOPBUILDDIR "/test2_lockfile"));
+
+ waitpid(pid, &status, 0);
}
EXPECT_TRUE(locker.unlock());
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())) {
// 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;
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);
return (-1);
}
- return (util::selectCheck(socket_fd_, timeout_sec, read_check, write_check));
+ return (util::selectCheck(socket_fd_, timeout_sec));
}
}
/// @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_;
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);
}
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_) {
errno = saved_errno;
}
if (errors_.size()) {
- return (errors_.size());
+ return (-1);
}
return (result);
}
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();
/// @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.
///
/// @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();
return (type_);
}
-bool FDEventHandler::hasError(int /* fd */) {
- return (false);
-}
-
} // end of namespace isc::util
} // end of namespace isc
/// @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.
///
/// @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;
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 */,
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_) {
errno = saved_errno;
}
if (errors_.size()) {
- return (errors_.size());
+ return (-1);
}
return (result);
}
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();
/// @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.
///
/// @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();
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);
}
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) {
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();
/// @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.
///
/// @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();
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));
}
/// @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
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;
}
}
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;
}
/// @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.
///
/// @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();
/// @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;
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());
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);
}
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));
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);
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);
// 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());