From 6c90636f60e1ad174cbf120612284a7de01b3ed8 Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 28 Sep 2025 11:04:58 +0300 Subject: [PATCH] the eval form required the server to bu ffer the messages in case if one of the client have died unexpectedly, we had sigpipe and blocked clients in that case, which we fixed --- src/Channel.cpp | 9 +- src/Server.cpp | 264 ++++++++++++++++++++++++------------------------ src/main.cpp | 1 + 3 files changed, 137 insertions(+), 137 deletions(-) diff --git a/src/Channel.cpp b/src/Channel.cpp index 1914f2a..6e6e65d 100644 --- a/src/Channel.cpp +++ b/src/Channel.cpp @@ -230,6 +230,7 @@ bool Channel::kick(int op, int user) { bool Channel::message(int user, string msg, string type, string name) { string message; + bool ret = true; if (type.empty()) message = msg + "\r\n"; @@ -241,14 +242,14 @@ bool Channel::message(int user, string msg, string type, string name) { for (auto users : _users) { if (users == user) continue; - else if (-1 == send(users, message.data(), message.size(), 0)) - return false; + if (-1 == send(users, message.data(), message.size(), 0)) + ret = false; } for (auto users : _oper) { if (users == user) continue; if (-1 == send(users, message.data(), message.size(), 0)) - return false; + ret = false; } - return true; + return ret; } diff --git a/src/Server.cpp b/src/Server.cpp index c8984de..8e0a8ab 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -1,171 +1,169 @@ #include "Server.hpp" -Server::Server(std::string port, std::string passwd) : -_startTime(time(nullptr)), -_fd(epoll_create1(0)), -_sock(socket(AF_INET, SOCK_STREAM, 0)), -_checker(0), -_port(stoi(port, &_checker)), -_password(passwd) -{ - if(_fd == -1) - throw std::runtime_error("Server::Server: ERROR - Failed to create epoll file"); - else if (port[_checker]) - throw std::runtime_error("Server::Server: ERROR - Bad port number " + port); - auto optval = 1; - setsockopt(_sock, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); - struct sockaddr_in sa_bindy{}; - sa_bindy.sin_family = AF_INET; - sa_bindy.sin_port = htons(_port); - sa_bindy.sin_addr.s_addr = htonl(INADDR_ANY); - - if (bind(_sock, (struct sockaddr *)&sa_bindy, sizeof(sa_bindy))) { - close(_fd); - close(_sock); - throw std::runtime_error("Server::Server: ERROR - Binding failed to " + port); - } - - if (listen(_sock, 10)) { - close(_fd); - close(_sock); - throw std::runtime_error("Server::Server: ERROR - Failed listen on port " + port); - } - - struct epoll_event ev{}; - ev.data.fd = _sock; - ev.events = EPOLLIN; - epoll_ctl(this->_fd, EPOLL_CTL_ADD, _sock, &ev); - - _events.reserve(_max_events * sizeof(epoll_event)); +Server::Server(std::string port, std::string passwd) + : _startTime(time(nullptr)), _fd(epoll_create1(0)), + _sock(socket(AF_INET, SOCK_STREAM, 0)), _checker(0), + _port(stoi(port, &_checker)), _password(passwd) { + if (_fd == -1) + throw std::runtime_error( + "Server::Server: ERROR - Failed to create epoll file"); + else if (port[_checker]) + throw std::runtime_error("Server::Server: ERROR - Bad port number " + port); + auto optval = 1; + setsockopt(_sock, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); + struct sockaddr_in sa_bindy{}; + sa_bindy.sin_family = AF_INET; + sa_bindy.sin_port = htons(_port); + sa_bindy.sin_addr.s_addr = htonl(INADDR_ANY); + + if (bind(_sock, (struct sockaddr *)&sa_bindy, sizeof(sa_bindy))) { + close(_fd); + close(_sock); + throw std::runtime_error("Server::Server: ERROR - Binding failed to " + + port); + } + + if (listen(_sock, 10)) { + close(_fd); + close(_sock); + throw std::runtime_error("Server::Server: ERROR - Failed listen on port " + + port); + } + + struct epoll_event ev{}; + ev.data.fd = _sock; + ev.events = EPOLLIN; + epoll_ctl(this->_fd, EPOLL_CTL_ADD, _sock, &ev); + _events.resize(_max_events); } Server::~Server() { - close(_fd); - close(_sock); + close(_fd); + close(_sock); } bool Server::checkPassword(std::string password) const { - return _password == password; + return _password == password; } -int Server::getServerFd() const { - return _fd; -} +int Server::getServerFd() const { return _fd; } -Channel& Server::addChannel(std::string name) { - _channels.try_emplace(name, name); - return _channels.at(name); +Channel &Server::addChannel(std::string name) { + _channels.try_emplace(name, name); + return _channels.at(name); } -void Server::removeChannel(std::string name) { - _channels.erase(name); -} +void Server::removeChannel(std::string name) { _channels.erase(name); } bool Server::channelExists(std::string name) { - return _channels.contains(name); + return _channels.contains(name); } -Channel* Server::findChannel(std::string name) { - auto ret = _channels.find(name); - if (ret == _channels.end()) - return nullptr; - return &(ret->second); +Channel *Server::findChannel(std::string name) { + auto ret = _channels.find(name); + if (ret == _channels.end()) + return nullptr; + return &(ret->second); } void Server::addClient(int fd) { - _clients.try_emplace(fd, std::make_shared(fd)); + _clients.try_emplace(fd, std::make_shared(fd)); } void Server::removeClient(const int fd) { - if(not _clients.empty()) { - _clients.erase(fd); - } - close(fd); + if (not _clients.empty()) { + _clients.erase(fd); + } + close(fd); } void Server::_reloadHandler(Client &client) const { - uint32_t event = 0; - struct epoll_event ev{}; - ev.data.fd = client._fd; - bool firstEvent = true; - - for (uint32_t evt: eventTypes) { - if (client.handler(evt)) { - event = evt; - firstEvent = false; - } else { - event |= evt; - } - - if (firstEvent) - event = EPOLLET; - else - event |= EPOLLET; - - ev.events = event; - - if (client._initialized) { - epoll_ctl(this->_fd, EPOLL_CTL_MOD, client._fd, &ev); - } else { - epoll_ctl(this->_fd, EPOLL_CTL_ADD, client._fd, &ev); - client._initialized = true; - } - } + uint32_t event = 0; + struct epoll_event ev{}; + ev.data.fd = client._fd; + bool firstEvent = true; + + for (uint32_t evt : eventTypes) { + if (client.handler(evt)) { + event = evt; + firstEvent = false; + } else { + event |= evt; + } + + if (firstEvent) + event = EPOLLET; + else + event |= EPOLLET; + + ev.events = event; + + if (client._initialized) { + epoll_ctl(this->_fd, EPOLL_CTL_MOD, client._fd, &ev); + } else { + epoll_ctl(this->_fd, EPOLL_CTL_ADD, client._fd, &ev); + client._initialized = true; + } + } } void Server::poll(int tout) { - int nbrEvents = epoll_wait(_fd, &_events[0], _max_events, tout); - - for (int idx = 0; idx < nbrEvents; idx++) { - uint32_t event = _events[idx].events; - int fd = _events[idx].data.fd; - if (fd == _sock) { - Handler::acceptClient(_sock); - continue; - } - for (uint32_t type : eventTypes) { - if (_clients.count(fd) == 0) - return ; - if (_clients.at(fd)->handler(type & event)) { - [[maybe_unused]] - auto fut = std::async(std::launch::async, _clients.at(fd)->getHandler(type & event), fd); - } - } - - if (event & (EPOLLRDHUP & EPOLLHUP)) - removeClient(fd); - } -} - -void Server::registerHandler(const int fd, uint32_t eventType, std::function handler) { - if (_clients.count(fd) == 0) - throw std::runtime_error("Server::registerHandler: Error - no such file descriptor"); - - - Client *cli = _clients.at(fd).get(); - - for (uint32_t eventT: eventTypes) { - if (eventT & eventType) { - cli->setHandler(eventType, handler); - } - } - - _reloadHandler(*cli); + int nbrEvents = epoll_wait(_fd, &_events[0], _max_events, tout); + + for (int idx = 0; idx < nbrEvents; idx++) { + uint32_t event = _events[idx].events; + int fd = _events[idx].data.fd; + if (fd == _sock) { + Handler::acceptClient(_sock); + continue; + } + for (uint32_t type : eventTypes) { + if (_clients.count(fd) == 0) + return; + if (_clients.at(fd)->handler(type & event)) { + [[maybe_unused]] + auto fut = std::async(std::launch::async, + _clients.at(fd)->getHandler(type & event), fd); + } + } + + if (event & (EPOLLRDHUP & EPOLLHUP)) + removeClient(fd); + } +} + +void Server::registerHandler(const int fd, uint32_t eventType, + std::function handler) { + if (_clients.count(fd) == 0) + throw std::runtime_error( + "Server::registerHandler: Error - no such file descriptor"); + + Client *cli = _clients.at(fd).get(); + + for (uint32_t eventT : eventTypes) { + if (eventT & eventType) { + cli->setHandler(eventType, handler); + } + } + + _reloadHandler(*cli); } std::string Server::getTime(void) const { - string ret = ctime(&_startTime); - ret.pop_back(); - return ret; + string ret = ctime(&_startTime); + ret.pop_back(); + return ret; } -const std::unordered_map>& Server::getClients() const { - return (_clients); +const std::unordered_map> & +Server::getClients() const { + return (_clients); } -Client* Server::getClient(int fd) { - if (_clients.count(fd) == 0) - throw std::runtime_error("Server::getClient: Error - no such file descriptor"); +Client *Server::getClient(int fd) { + if (_clients.count(fd) == 0) + throw std::runtime_error( + "Server::getClient: Error - no such file descriptor"); - return (_clients.at(fd).get()); + return (_clients.at(fd).get()); } diff --git a/src/main.cpp b/src/main.cpp index b104870..fcf6ac4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,6 +28,7 @@ int main(int argc, char *argv[]) { signal(SIGINT, [](int) { gSigStatus = 1; }); signal(SIGQUIT, [](int) { gSigStatus = 1; }); + signal(SIGPIPE, SIG_IGN); try { if (argc == 3)