From bfe88daf3e000f417ca79242b27ce0f3041ad55f Mon Sep 17 00:00:00 2001 From: ouafabulous Date: Wed, 21 May 2025 21:52:20 +0200 Subject: [PATCH] I broke something with displaying the clients input plainly --- Makefile | 33 ++++++----- diagram.puml | 4 +- include/PollManager.hpp | 26 ++++----- include/core/core.hpp | 15 +++-- include/server.hpp | 14 +++-- include/user.hpp | 54 ++++++++++-------- sources/core/PollManager.cpp | 96 ++++++++++++++++++------------- sources/core/Server.cpp | 52 +++++++++++++++-- sources/core/user.cpp | 108 +++++++++++++++++++++++++++++++++++ sources/user/user.cpp | 76 ------------------------ 10 files changed, 292 insertions(+), 186 deletions(-) create mode 100644 sources/core/user.cpp delete mode 100644 sources/user/user.cpp diff --git a/Makefile b/Makefile index 3ad7c51..86e4656 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,14 @@ -# **************************************************************************** # +#******************************************************************************# # # # ::: :::::::: # # Makefile :+: :+: :+: # # +:+ +:+ +:+ # -# By: sben-tay +#+ +:+ +#+ # +# By: omoudni +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2025/05/02 15:40:00 by rparodi #+# #+# # -# Updated: 2025/05/21 13:01:09 by rparodi ### ########.fr # +# Updated: 2025/05/21 21:51:13 by omoudni ### ########.fr # # # -# **************************************************************************** # +#******************************************************************************# # Name @@ -30,7 +30,7 @@ SRC = sources/core/logs.cpp \ sources/core/parser.cpp \ sources/core/main.cpp \ sources/core/Server.cpp \ - sources/user/user.cpp \ + sources/core/user.cpp \ sources/channel/channel.cpp INC_DIR = include/core \ @@ -85,30 +85,37 @@ debug: CXXFLAGS += -g # debug: CXXFLAGS += -fsanitize=address debug: re +PORT ?= 4243 + test: debug - @printf '$(GREY) now running with\n\t- Port:\t\t$(GREEN)4243$(GREY)\n\t- Password:\t$(GREEN)irc$(END)\n' + @printf '$(GREY) now running with\n\t- Port:\t\t$(GREEN)$(PORT)$(GREY)\n\t- Password:\t$(GREEN)irc$(END)\n' @if tmux has-session -t $(SESSION) 2>/dev/null; then \ tmux kill-session -t $(SESSION); \ fi @tmux new-session -d -s $(SESSION) \ - 'bash -lc "./$(NAME) 4243 irc; exec bash"' + 'bash -lc "./$(NAME) $(PORT) irc; exec bash"' @tmux split-window -h -p 70 -t $(SESSION):0 \ - 'bash -lc "irssi -c localhost -p 4243 -w irc || exec yes \"irssi exit code: $?\""' + 'bash -lc "irssi -c localhost -p $(PORT) -w irc || exec yes \"irssi exit code: $?\""' @tmux split-window -v -p 50 -t $(SESSION):0.1 \ - 'bash -lc "nc localhost 4243 || exec yes \"netcat exit code: $?\""' + 'bash -lc "nc localhost $(PORT) || exec yes \"netcat exit code: $?\""' + @tmux split-window -v -p 50 -t $(SESSION):0.2 \ + 'bash -lc "nc localhost $(PORT) || exec yes \"netcat exit code: $?\""' + @tmux split-window -v -p 50 -t $(SESSION):0.3 \ + 'bash -lc "nc localhost $(PORT) || exec yes \"netcat exit code: $?\""' @tmux attach -t $(SESSION) + run: re - @printf '$(GREY) now running with\n\t- Port:\t\t$(GREEN)4243$(GREY)\n\t- Password:\t$(GREEN)irc$(END)\n' + @printf '$(GREY) now running with\n\t- Port:\t\t$(GREEN)$(PORT)$(GREY)\n\t- Password:\t$(GREEN)irc$(END)\n' @if tmux has-session -t $(SESSION) 2>/dev/null; then \ tmux kill-session -t $(SESSION); \ fi @tmux new-session -d -s $(SESSION) \ - 'bash -lc "./$(NAME) 4243 irc; exec bash"' + 'bash -lc "./$(NAME) $(PORT) irc; exec bash"' @tmux split-window -h -p 70 -t $(SESSION):0 \ - 'bash -lc "irssi -c localhost -p 4243 -w irc || exec yes \"irssi exit code: $?\""' + 'bash -lc "irssi -c localhost -p $(PORT) -w irc || exec yes \"irssi exit code: $?\""' @tmux split-window -v -p 50 -t $(SESSION):0.1 \ - 'bash -lc "nc localhost 4243 || exec yes \"netcat exit code: $?\""' + 'bash -lc "nc localhost $(PORT) || exec yes \"netcat exit code: $?\""' @tmux attach -t $(SESSION) # Header diff --git a/diagram.puml b/diagram.puml index 05ae631..93491fb 100644 --- a/diagram.puml +++ b/diagram.puml @@ -13,6 +13,7 @@ class Server { - _password : string - _server_fd : int - _poll : PollManager + - _users : map + Server(port : int, password : string) + start() : void @@ -25,12 +26,11 @@ class Server { ' ============================ class PollManager { - _fds : vector - - _users : map + addUser(fd : int) : void + removeUser(fd : int) : void + updateUser(fd : int, events : short) : void - + pollLoop(server_fd : int) : void + + pollLoop(server_fd : int, newClients : std::vector, disconnected : std::vector) : void + readFromUser(fd : int) : void + writeToUser(fd : int) : void } diff --git a/include/PollManager.hpp b/include/PollManager.hpp index 008f843..4b7623a 100644 --- a/include/PollManager.hpp +++ b/include/PollManager.hpp @@ -1,14 +1,14 @@ -/* ************************************************************************** */ +/******************************************************************************/ /* */ /* ::: :::::::: */ /* PollManager.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: sben-tay +#+ +:+ +#+ */ +/* By: omoudni +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/19 19:15:13 by omoudni #+# #+# */ -/* Updated: 2025/05/20 17:22:59 by sben-tay ### ########.fr */ +/* Updated: 2025/05/21 21:34:20 by omoudni ### ########.fr */ /* */ -/* ************************************************************************** */ +/******************************************************************************/ #pragma once @@ -16,19 +16,17 @@ #include #include -class PollManager { +class PollManager +{ public: - PollManager(); - ~PollManager(); + PollManager(); + ~PollManager(); - void addClient(int fd); - void removeClient(int fd); - void updateServer(int fd); - void pollLoop(int server_fd); + void addClient(short unsigned fd); + void removeClient(short unsigned fd); + void updateServer(short unsigned fd); + void pollLoop(int server_fd, std::vector &newClients, std::vector &disconnected, std::vector > &readyClients); private: - std::vector _fds; - std::map _buffers; - }; diff --git a/include/core/core.hpp b/include/core/core.hpp index a50d333..a837f41 100644 --- a/include/core/core.hpp +++ b/include/core/core.hpp @@ -1,14 +1,14 @@ -/* ************************************************************************** */ +/******************************************************************************/ /* */ /* ::: :::::::: */ /* core.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: sben-tay +#+ +:+ +#+ */ +/* By: omoudni +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/12 14:16:03 by rparodi #+# #+# */ -/* Updated: 2025/05/20 17:23:41 by sben-tay ### ########.fr */ +/* Updated: 2025/05/21 21:18:22 by omoudni ### ########.fr */ /* */ -/* ************************************************************************** */ +/******************************************************************************/ #pragma once @@ -28,8 +28,13 @@ enum e_state { CMD, MSG }; - + +// INCLUDES (not to repeat) +#include +#include +#include +#include "user.hpp" #include "PollManager.hpp" #include "color.hpp" #include "server.hpp" diff --git a/include/server.hpp b/include/server.hpp index 96a78b0..27ab3a3 100644 --- a/include/server.hpp +++ b/include/server.hpp @@ -1,26 +1,28 @@ -/* ************************************************************************** */ +/******************************************************************************/ /* */ /* ::: :::::::: */ /* server.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: rparodi +#+ +:+ +#+ */ +/* By: omoudni +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/20 21:50:32 by rparodi #+# #+# */ -/* Updated: 2025/05/21 13:03:01 by rparodi ### ########.fr */ +/* Updated: 2025/05/21 21:19:47 by omoudni ### ########.fr */ /* */ -/* ************************************************************************** */ +/******************************************************************************/ #pragma once -#include -#include "PollManager.hpp" +#include "core.hpp" +class User; class Server { private: int _port; int _serverFd; std::string _password; PollManager _pollManager; + std::map _users; + public: Server(int port, const std::string &password); ~Server(); diff --git a/include/user.hpp b/include/user.hpp index b40bfee..4e7b326 100644 --- a/include/user.hpp +++ b/include/user.hpp @@ -1,36 +1,42 @@ -/* ************************************************************************** */ +/******************************************************************************/ /* */ /* ::: :::::::: */ /* user.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: rparodi +#+ +:+ +#+ */ +/* By: omoudni +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/20 21:57:49 by rparodi #+# #+# */ -/* Updated: 2025/05/20 22:13:41 by rparodi ### ########.fr */ +/* Updated: 2025/05/21 21:16:56 by omoudni ### ########.fr */ /* */ -/* ************************************************************************** */ +/******************************************************************************/ #pragma once -#include -#include -#include "color.hpp" +#include "core.hpp" -class User { - private: - int _fd; - bool _registered; - std::string _nickname; - std::string _hostname; - std::string _read_buffer; - std::string _write_buffer; - public: - int getFd() const; - bool isReadyToSend() const; - bool isRegistered() const; - std::string getNickname() const; - std::string extractFullCommand(); - void appendToReadBuffer(const std::string &data); - void appendToWriteBuffer(const std::string &data); - void setNickname(const std::string &nickname); +class User +{ +private: + short unsigned int _fd; + bool _registered; + std::string _nickname; + std::string _hostname; + std::string _read_buffer; + std::string _write_buffer; + std::string _username; + bool _hasNick; + bool _hasUser; + +public: + User(short unsigned fd); + short unsigned int getFd() const; + bool isReadyToSend() const; + bool isRegistered() const; + std::string getNickname() const; + std::string extractFullCommand(); + void appendToReadBuffer(const std::string &data); + void appendToWriteBuffer(const std::string &data); + void setNickname(const std::string &nickname); + void setUsername(const std::string &username); + void checkRegistration(); }; diff --git a/sources/core/PollManager.cpp b/sources/core/PollManager.cpp index 29d8485..9e916be 100644 --- a/sources/core/PollManager.cpp +++ b/sources/core/PollManager.cpp @@ -10,72 +10,86 @@ PollManager::PollManager() {} -PollManager::~PollManager() { - for (size_t i = 0; i < _fds.size(); ++i) { - close(_fds[i].fd); - } +PollManager::~PollManager() +{ + for (size_t i = 0; i < _fds.size(); ++i) + { + close(_fds[i].fd); + } } -void PollManager::pollLoop(int server_fd) { +void PollManager::pollLoop(int server_fd, std::vector &newClients, std::vector &disconnected, std::vector > &readyClients) +{ - struct pollfd server_pollfd; + struct pollfd server_pollfd; server_pollfd.fd = server_fd; server_pollfd.events = POLLIN; _fds.push_back(server_pollfd); std::cout << "Serveur prêt à accepter des connexions..." << std::endl; - while (true) { - int poll_count = poll(&_fds[0], _fds.size(), -1); - if (poll_count == -1) { - std::cerr << "poll error\n" << std::endl; - continue; - } - for (size_t i = 0; i < _fds.size(); ++i) { - int fd = _fds[i].fd; + // while (true) { + int poll_count = poll(&_fds[0], _fds.size(), -1); + if (poll_count == -1) + { + std::cerr << "poll error\n" + << std::endl; + return; + } + for (size_t i = 0; i < _fds.size(); ++i) + { + short unsigned fd = _fds[i].fd; - if ((fd == server_fd) && (_fds[i].revents & POLLIN)) { - int client_fd = accept(server_fd, NULL, NULL); - if (client_fd == -1) { - std::cerr << "Error accept()" << std::endl; - continue; - } - addClient(client_fd); + if ((fd == server_fd) && (_fds[i].revents & POLLIN)) + { + int client_fd = accept(server_fd, NULL, NULL); + if (client_fd == -1) + { + std::cerr << "Error accept()" << std::endl; + continue; } - else if (_fds[i].revents & POLLIN) { - char buffer[1024]; - ssize_t bytes = recv(fd, buffer, sizeof(buffer) -1, 0); - if (bytes > 0) { - buffer[bytes] = '\0'; - _buffers[fd] += buffer; - std::cout << "Client " << fd << " send : " << buffer; - } else { - std::cout << "Client " << fd << " disconected." << std::endl; - // removeClient(fd); - --i; - } + addClient(client_fd); + newClients.push_back(client_fd); + } + else if (_fds[i].revents & POLLIN) + { + char buffer[1024]; + ssize_t bytes = recv(fd, buffer, sizeof(buffer) - 1, 0); + if (bytes > 0) + { + buffer[bytes] = '\0'; + readyClients.push_back(std::make_pair(fd, std::string(buffer))); + } + else + { + removeClient(fd); + disconnected.push_back(fd); + --i; } } } + // } } -void PollManager::addClient(int fd) { +void PollManager::addClient(short unsigned fd) +{ struct pollfd pfd; pfd.fd = fd; pfd.events = POLLIN; _fds.push_back(pfd); - _buffers[fd] = ""; - std::cout << "Client connecté (fd " << fd << ")" << std::endl; + std::cout << "Client connected (fd " << fd << ")" << std::endl; } -void PollManager::removeClient(int fd) { - for (size_t i = 0; i < _fds.size(); ++i) { - if (_fds[i].fd == fd) { +void PollManager::removeClient(short unsigned fd) +{ + for (size_t i = 0; i < _fds.size(); ++i) + { + if (_fds[i].fd == fd) + { _fds.erase(_fds.begin() + i); break; } } - _buffers.erase(fd); close(fd); - std::cout << "Client retiré (fd " << fd << ")" << std::endl; + std::cout << "Client disconnected (fd " << fd << ")" << std::endl; } diff --git a/sources/core/Server.cpp b/sources/core/Server.cpp index 5f0cdbd..a371d15 100644 --- a/sources/core/Server.cpp +++ b/sources/core/Server.cpp @@ -1,14 +1,14 @@ -/* ************************************************************************** */ +/******************************************************************************/ /* */ /* ::: :::::::: */ /* Server.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: sben-tay +#+ +:+ +#+ */ +/* By: omoudni +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/13 11:11:07 by rparodi #+# #+# */ -/* Updated: 2025/05/21 13:03:51 by rparodi ### ########.fr */ +/* Updated: 2025/05/21 21:50:03 by omoudni ### ########.fr */ /* */ -/* ************************************************************************** */ +/******************************************************************************/ #include "color.hpp" #include "server.hpp" @@ -37,6 +37,9 @@ Server::Server(int port, const std::string &password) : _port(port), _password(p */ Server::~Server() { std::cout << CLR_GREY << "Info: Server destructor called" << CLR_RESET << std::endl; + if (_serverFd != -1) { + close(_serverFd); + } } @@ -61,8 +64,47 @@ void Server::start() { } std::cout << "Serveur lancé sur le port " << _port << std::endl; + std::vector newClients; + std::vector disconnected; + std::vector > readyClients; + while (true) + { + newClients.clear(); + disconnected.clear(); + readyClients.clear(); + _pollManager.pollLoop(_serverFd, newClients, disconnected, readyClients); - _pollManager.pollLoop(_serverFd); + // Handle new clients + for (size_t i = 0; i < newClients.size(); ++i) + _users[newClients[i]] = new User(newClients[i]); + // Handle disconnected clients + for (size_t i = 0; i < disconnected.size(); ++i) + { + delete _users[disconnected[i]]; + _users.erase(disconnected[i]); + } + for (size_t i = 0; i < readyClients.size(); ++i) + { + int fd = readyClients[i].first; + const std::string &data = readyClients[i].second; + if (_users.count(fd)) + { + _users[fd]->appendToReadBuffer(data); + //print users + std::cout << "User " << fd << " is registered: " << _users[fd]->isRegistered() << std::endl; + std::cout << "Received data from fd " << fd << ": " << data << std::endl; + std::string cmd; + while (!(cmd = _users[fd]->extractFullCommand()).empty()) + { + // This prints every command/message received from any client + std::cout << "Client " << fd << " says: " << cmd << std::endl; + + } + } + } + + // Optionally: handle server shutdown, signals, etc. + } close(_serverFd); } diff --git a/sources/core/user.cpp b/sources/core/user.cpp new file mode 100644 index 0000000..2ae0172 --- /dev/null +++ b/sources/core/user.cpp @@ -0,0 +1,108 @@ +/******************************************************************************/ +/* */ +/* ::: :::::::: */ +/* user.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: omoudni +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/05/21 20:37:12 by omoudni #+# #+# */ +/* Updated: 2025/05/21 21:44:58 by omoudni ### ########.fr */ +/* */ +/******************************************************************************/ + +#include "core.hpp" + +// Constructor +User::User(short unsigned int fd) : _fd(fd), _registered(false), _hasNick(false), _hasUser(false) {} + +// Getter for fd +short unsigned int User::getFd() const +{ + return _fd; +} + +// Getter for nickname +std::string User::getNickname() const +{ + return _nickname; +} + +void User::setUsername(const std::string &username) +{ + _username = username; + _hasUser = true; + checkRegistration(); +} + +// Setter for nickname (with basic checks) +void User::setNickname(const std::string &nickname) +{ + if (nickname.empty()) + { + throw std::invalid_argument("Nickname cannot be empty"); + } + else if (nickname == "anonymous") + { + throw std::invalid_argument("Nickname cannot be 'anonymous'"); + } + else if (nickname.length() > 9) + { + throw std::length_error("Nickname is too long"); + } + else if (nickname == _nickname) + { + throw std::invalid_argument("The nickname is the same"); + } + else + { + _nickname = nickname; + _hasNick = true; + checkRegistration(); + } +} + +// Registration state +bool User::isRegistered() const +{ + return _registered; +} + +// Append to read buffer +void User::appendToReadBuffer(const std::string &data) +{ + _read_buffer += data; +} + +// Append to write buffer +void User::appendToWriteBuffer(const std::string &data) +{ + _write_buffer += data; +} + +// Check registration +void User::checkRegistration() +{ + if (!_registered && _hasNick && _hasUser) + { + _registered = true; + } +} + +// Check if the user is ready to send +bool User::isReadyToSend() const +{ + return !_write_buffer.empty(); +} + +// Extract full command from read buffer +std::string User::extractFullCommand() +{ + std::string command; + size_t pos = _read_buffer.find("\r\n"); + if (pos != std::string::npos) + { + command = _read_buffer.substr(0, pos); + _read_buffer.erase(0, pos + 2); + } + return command; +} \ No newline at end of file diff --git a/sources/user/user.cpp b/sources/user/user.cpp deleted file mode 100644 index 80e1adb..0000000 --- a/sources/user/user.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* user.cpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: rparodi +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2025/05/20 22:03:36 by rparodi #+# #+# */ -/* Updated: 2025/05/20 22:15:14 by rparodi ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#include "user.hpp" - -/** - * @brief Getter for the fd of the user - * - * @return the actual fd of the user - */ -int User::getFd() const { - return this->_fd; -} - -/** - * @brief Getter for the nickname of the user - * - * @return the actual nickname of the user - */ -std::string User::getNickname() const { - return this->_nickname; -} - -/** - * @brief Setter for the nickname of the user (also checker) - * - * @param nickname the nickname given to set to the user - */ -void User::setNickname(const std::string &nickname) { - if (nickname.empty()) { - throw std::invalid_argument("Nickname cannot be empty"); - } else if (nickname == "anonymous") { - throw std::invalid_argument("Nickname cannot be 'anonymous'"); - } else if (nickname.length() > 9) { - throw std::length_error("Nickname is too long"); - } else if (nickname == this->_nickname) { - throw std::invalid_argument("The nickname is the same"); - } else { - this->_nickname = nickname; - } -} - -/** - * @brief Getter for the state of the user - * - * @return true if the user is registered, false otherwise - */ -bool User::isRegistered() const { - return this->_registered; -} -void User::appendToReadBuffer(const std::string &data) { - std::cerr << CLR_RED << "Error: Method not found (" << __FILE_NAME__ ":" << __LINE__ << ")" << CLR_RESET << std::endl; - (void)data; -} -void User::appendToWriteBuffer(const std::string &data) { - std::cerr << CLR_RED << "Error: Method not found (" << __FILE_NAME__ ":" << __LINE__ << ")" << CLR_RESET << std::endl; - (void)data; -} -std::string User::extractFullCommand() { - std::cerr << CLR_RED << "Error: Method not found (" << __FILE_NAME__ ":" << __LINE__ << ")" << CLR_RESET << std::endl; - return nullptr; -} - -bool User::isReadyToSend() const { - std::cerr << CLR_RED << "Error: Method not found (" << __FILE_NAME__ ":" << __LINE__ << ")" << CLR_RESET << std::endl; - return (false); -}