diff --git a/.gitignore b/.gitignore index 536ac9e..606ba8b 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ tests/test_runner # Docker / local secrets .env + +.claude/workflow/tasks/* \ No newline at end of file diff --git a/include/Server.hpp b/include/Server.hpp index e5aa575..703ea6b 100644 --- a/include/Server.hpp +++ b/include/Server.hpp @@ -74,6 +74,7 @@ class Server void handleClientOutput(int fd); void handleMessage(Client *client, const std::string &raw); void checkTimeouts(); + void updateEpollInterest(Client *client); bool dispatchExtensionFd(int fd, uint32_t events); /* ─── Command dispatch ─── */ @@ -125,6 +126,7 @@ class Server ** stays below in run() (src/Server.cpp). */ libcpp98::Reactor _reactor; std::map _clients; + std::map _epollMask; std::map _channels; std::vector _extensions; time_t _lastPingCheck; diff --git a/src/Server.cpp b/src/Server.cpp index a29821f..aaebf20 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -193,6 +193,10 @@ void Server::run() time_t now = std::time(NULL); for (size_t i = 0; i < _extensions.size(); ++i) _extensions[i]->onTick(*this, now); + + for (std::map::iterator it = _clients.begin(); + it != _clients.end(); ++it) + updateEpollInterest(it->second); } } @@ -264,7 +268,8 @@ void Server::acceptClient() } _clients[clientFd] = client; - addToEpoll(clientFd, EPOLLIN | EPOLLOUT); + addToEpoll(clientFd, EPOLLIN); + _epollMask[clientFd] = EPOLLIN; Log::info("new connection from " + hostname + " (fd " + libcpp::str::to_string(clientFd) + ")"); @@ -339,6 +344,17 @@ void Server::handleMessage(Client *client, const std::string &raw) dispatchCommand(client, msg); } +void Server::updateEpollInterest(Client *client) +{ + int fd = client->getFd(); + uint32_t want = EPOLLIN | (client->hasPendingData() ? EPOLLOUT : 0u); + std::map::iterator it = _epollMask.find(fd); + if (it != _epollMask.end() && it->second == want) + return; + modifyEpoll(fd, want); + _epollMask[fd] = want; +} + void Server::checkTimeouts() { time_t now = std::time(NULL); @@ -487,6 +503,7 @@ void Server::disconnectClient(int fd, const std::string &reason) send(fd, pending.c_str(), pending.size(), 0); } + _epollMask.erase(fd); removeFromEpoll(fd); close(fd); Log::info("client disconnected: " + client->getNickname()