diff --git a/incs/server.hpp b/incs/server.hpp index 55d7a49..ca8e079 100644 --- a/incs/server.hpp +++ b/incs/server.hpp @@ -7,6 +7,8 @@ #include "DccServer.hpp" #include "DccClient.hpp" #include +#include +#include class Client; class Channel; @@ -26,6 +28,9 @@ class Server std::vector channels; std::vector dccServers; std::vector dccClients; + std::map > outQueues; + std::map outOffsets; + std::map inBuffers; public: Server(); @@ -53,6 +58,12 @@ class Server void SetupSocketOptions(); void BindAndListenSocket(struct sockaddr_in &add); void HandlePollEvents(); + void FlushClient(int fd); + void EnablePollout(int fd); + void DisablePollout(int fd); + void AppendAndParseClientInput(int fd, const char* data, size_t length); + void ParseBufferedLines(int fd, std::vector& outLines); + void ProcessClientLine(std::string& line); Client* FindClientByFd(int fd); Client* FindClientByNickname(const std::string &nickname); @@ -61,6 +72,7 @@ class Server bool IsNicknameInUse(const std::string &nickname); void CheckClientAuthentication(Client* client); void SendToClient(int fd, const std::string& message); + void QueueSend(int fd, const std::string& message); void SendWelcomeMessage(int fd); void SendRegistrationCompleteMessage(Client* client); diff --git a/srcs/channel.cpp b/srcs/channel.cpp index 21fe1a3..0d00bcd 100644 --- a/srcs/channel.cpp +++ b/srcs/channel.cpp @@ -195,12 +195,7 @@ void Channel::broadcastMessage(const std::string& message, Client* sender, Serve } std::cout << "DEBUG broadcastMessage: Sending to client FD " << clientFd << std::endl; - ssize_t result = send(clientFd, message.c_str(), message.length(), 0); - if (result == -1) { - std::cout << "DEBUG: Error sending message to client " << clientFd << " - " << strerror(errno) << std::endl; - } else { - std::cout << "DEBUG broadcastMessage: Successfully sent " << result << " bytes to FD " << clientFd << std::endl; - } + server->SendToClient(clientFd, message); } } diff --git a/srcs/server.cpp b/srcs/server.cpp index 65e042e..cffbe61 100644 --- a/srcs/server.cpp +++ b/srcs/server.cpp @@ -5,6 +5,7 @@ bool Server::HasSignal = false; Server::Server() : ServerSocketFd(-1){ serverName = "ft_irc.42.fr"; } + Server::~Server() { for (size_t i = 0; i < channels.size(); i++) { delete channels[i]; @@ -85,6 +86,9 @@ void Server::HandlePollEvents() { else HandleDccEvents(fds[i].fd); } + if (fds[i].revents & POLLOUT) { + FlushClient(fds[i].fd); + } } } @@ -125,27 +129,24 @@ void Server::AcceptNewClient() { if (!validateNewConnection(incofd)) return ; - connectClient(incofd, cliadd, clients, fds); - this->SendWelcomeMessage(incofd); + connectClient(incofd, cliadd, clients, fds); + this->SendWelcomeMessage(incofd); + inBuffers[incofd] = std::string(); } void Server::ReceiveNewData(int fd) { - char buff[1024]; - - memset(buff, 0, sizeof(buff)); - ssize_t bytes = recv(fd, buff, sizeof(buff) - 1, 0); - - if (bytes <= 0) { - if (bytes == 0) { - std::cout << RED << "Cliente <" << fd << "> Desconectado (conexão fechada pelo cliente)" << WHI << std::endl; - } else { - std::cout << RED << "Cliente <" << fd << "> Desconectado (erro na recepção: " << strerror(errno) << ")" << WHI << std::endl; - } - ClearClients(fd); - return (close(fd), void()); - } - std::cout << "DEBUG: Received from client " << fd << ": " << buff << std::endl; - Parser::MainParser(this, buff, fd); + char tmp[1024]; + ssize_t bytes = recv(fd, tmp, sizeof(tmp), 0); + if (bytes <= 0) { + if (bytes == 0) { + std::cout << RED << "Cliente <" << fd << "> Desconectado (conexão fechada pelo cliente)" << WHI << std::endl; + } else { + std::cout << RED << "Cliente <" << fd << "> Desconectado (erro na recepção: " << strerror(errno) << ")" << WHI << std::endl; + } + ClearClients(fd); + return; + } + AppendAndParseClientInput(fd, tmp, static_cast(bytes)); } void Server::SignalHandler(int signum) { @@ -193,10 +194,53 @@ void Server::ClearClients(int fd) { } } - CloseClientFd(fd); - CloseFd(fd); + CloseClientFd(fd); + CloseFd(fd); + outQueues.erase(fd); + outOffsets.erase(fd); + inBuffers.erase(fd); } +void Server::AppendAndParseClientInput(int fd, const char* data, size_t length) +{ + std::string &buffer = inBuffers[fd]; + buffer.append(data, data + length); + const size_t MAX_INBUF = 8192; + if (buffer.size() > MAX_INBUF) { + ClearClients(fd); + return; + } + std::vector lines; + ParseBufferedLines(fd, lines); + for (size_t i = 0; i < lines.size(); i++) { + std::string &line = lines[i]; + ProcessClientLine(line); + std::vector cmd(line.begin(), line.end()); + cmd.push_back('\0'); + Parser::MainParser(this, &cmd[0], fd); + } +} + +void Server::ParseBufferedLines(int fd, std::vector& outLines) +{ + std::string &buffer = inBuffers[fd]; + for (;;) { + size_t newlinePos = buffer.find('\n'); + if (newlinePos == std::string::npos) break; + std::string line = buffer.substr(0, newlinePos); + buffer.erase(0, newlinePos + 1); + outLines.push_back(line); + } +} + +void Server::ProcessClientLine(std::string& line) +{ + if (!line.empty() && line[line.size() - 1] == '\r') { + line.erase(line.size() - 1); + } +} + + void Server::CloseClientFd(int fd) { for (size_t i = 0; i < clients.size(); i++) { if (clients[i].GetFd() == fd) { @@ -217,7 +261,61 @@ void Server::CloseFd(int fd) { void Server::SendToClient(int fd, const std::string& message) { - send(fd, message.c_str(), message.length(), 0); + QueueSend(fd, message); +} + +void Server::QueueSend(int fd, const std::string& message) +{ + outQueues[fd].push_back(message); + EnablePollout(fd); +} + +void Server::FlushClient(int fd) +{ + std::deque &queue = outQueues[fd]; + size_t &offset = outOffsets[fd]; + while (!queue.empty()) { + const std::string ¤t = queue.front(); + const char *data = current.c_str() + offset; + size_t remaining = current.size() - offset; + ssize_t written = send(fd, data, remaining, 0); + if (written > 0) { + offset += static_cast(written); + if (offset == current.size()) { + queue.pop_front(); + offset = 0; + } + continue; + } + if (written == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { + break; + } + ClearClients(fd); + return; + } + if (queue.empty()) { + DisablePollout(fd); + } +} + +void Server::EnablePollout(int fd) +{ + for (size_t i = 0; i < fds.size(); i++) { + if (fds[i].fd == fd) { + fds[i].events |= POLLOUT; + return; + } + } +} + +void Server::DisablePollout(int fd) +{ + for (size_t i = 0; i < fds.size(); i++) { + if (fds[i].fd == fd) { + fds[i].events &= ~POLLOUT; + return; + } + } } void Server::SendWelcomeMessage(int fd)