diff --git a/.vscode/settings.json b/.vscode/settings.json index 5b9128d..1d2e293 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -57,51 +57,53 @@ "C_Cpp_Runner.useLinkTimeOptimization": false, "C_Cpp_Runner.msvcSecureNoWarnings": false, "files.associations": { - "array": "cpp", - "atomic": "cpp", - "bit": "cpp", - "*.tcc": "cpp", - "cctype": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "compare": "cpp", - "concepts": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "deque": "cpp", - "string": "cpp", - "unordered_map": "cpp", - "vector": "cpp", - "exception": "cpp", - "algorithm": "cpp", - "functional": "cpp", - "iterator": "cpp", - "memory": "cpp", - "memory_resource": "cpp", - "numeric": "cpp", - "random": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "initializer_list": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "new": "cpp", - "numbers": "cpp", - "ostream": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "typeinfo": "cpp" - } + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "typeinfo": "cpp", + "ctime": "cpp", + "map": "cpp" +} } \ No newline at end of file diff --git a/ft_irc/build/Client.o b/ft_irc/build/Client.o index 82b2d77..b8346e7 100644 Binary files a/ft_irc/build/Client.o and b/ft_irc/build/Client.o differ diff --git a/ft_irc/build/CommandHandler.o b/ft_irc/build/CommandHandler.o index 57e7d6a..baeca9c 100644 Binary files a/ft_irc/build/CommandHandler.o and b/ft_irc/build/CommandHandler.o differ diff --git a/ft_irc/build/Server.o b/ft_irc/build/Server.o index 0baa7a9..f460d38 100644 Binary files a/ft_irc/build/Server.o and b/ft_irc/build/Server.o differ diff --git a/ft_irc/build/main.o b/ft_irc/build/main.o index 384cf5e..dad8106 100644 Binary files a/ft_irc/build/main.o and b/ft_irc/build/main.o differ diff --git a/ft_irc/build/utilities.o b/ft_irc/build/utilities.o index 7efbe16..6f59157 100644 Binary files a/ft_irc/build/utilities.o and b/ft_irc/build/utilities.o differ diff --git a/ft_irc/include/Channel.hpp b/ft_irc/include/Channel.hpp index ec30245..f0b3895 100644 --- a/ft_irc/include/Channel.hpp +++ b/ft_irc/include/Channel.hpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/09 14:07:50 by fgras-ca #+# #+# */ -/* Updated: 2024/05/09 14:33:01 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/11 16:20:58 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -18,6 +18,9 @@ #include #include +class Client; + + class Channel { public: Channel(const std::string& name); diff --git a/ft_irc/include/Client.hpp b/ft_irc/include/Client.hpp index b550e0e..844db13 100644 --- a/ft_irc/include/Client.hpp +++ b/ft_irc/include/Client.hpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/09 14:07:00 by fgras-ca #+# #+# */ -/* Updated: 2024/05/10 14:10:35 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/11 19:14:26 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -18,10 +18,14 @@ #include #include #include +#include "Server.hpp" + + class Client { public: - Client(int socket, const std::string& nickname, const std::string& username); + Client(); + Client(int socket, const std::string& nickname = "defaultNickName", const std::string& username = "defaultUserName"); ~Client(); void sendMessage(const std::string& message); @@ -29,13 +33,14 @@ public: void setNickname(const std::string& newNickname); std::string getNickname() const; // Ajout de la méthode getNickname int getSocket() const; + void setUsername(const std::string& newUsername); + void setRealname(const std::string& newRealname); private: + int socket; std::string nickname; // Assurez-vous que cette donnée membre est accessible via getNickname std::string username; }; #endif - - diff --git a/ft_irc/include/CommandHandler.hpp b/ft_irc/include/CommandHandler.hpp index 0d841c3..8e14428 100644 --- a/ft_irc/include/CommandHandler.hpp +++ b/ft_irc/include/CommandHandler.hpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/09 14:19:30 by fgras-ca #+# #+# */ -/* Updated: 2024/05/09 14:49:16 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/12 17:09:20 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -21,22 +21,25 @@ #include #include -class CommandHandler { +class Client; +class Channel; + +class CommandHandler +{ public: - CommandHandler(); - ~CommandHandler(); - void handleCommand(const std::string& command, Client* client); + CommandHandler(); + ~CommandHandler(); + void handleCommand(const std::string& commandLine, Client* client); private: - std::map channels; + std::map channels; + std::vector split(const std::string& s, char delimiter); - void handleJoin(const std::string& command, Client* client); - void handlePart(const std::string& command, Client* client); - void handleNick(const std::string& command, Client* client); - void handlePrivmsg(const std::string& command, Client* client); - void handleQuit(Client* client); - - std::vector split(const std::string& s, char delimiter); + void handleJoin(const std::string& command, Client* client); + void handlePart(const std::string& command, Client* client); + void handleNick(const std::string& command, Client* client); + void handlePrivmsg(const std::string& command, Client* client); + //void handleQuit(Client* client); }; #endif // COMMANDHANDLER_HPP diff --git a/ft_irc/include/Server.hpp b/ft_irc/include/Server.hpp index 5d395d2..47bf8eb 100644 --- a/ft_irc/include/Server.hpp +++ b/ft_irc/include/Server.hpp @@ -6,54 +6,60 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/09 14:01:12 by fgras-ca #+# #+# */ -/* Updated: 2024/05/10 14:10:44 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/12 17:14:30 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ #ifndef SERVER_HPP #define SERVER_HPP +#include +#include +#include #include #include -#include -#include -#include +#include #include #include -#include -#include -#include +#include +#include +#include +#include +#include +#include -#include "Client.hpp" // Assurez-vous que Client est inclus avant Server +#include "color.hpp" +#include "Client.hpp" #include "CommandHandler.hpp" -class Server; // Déclaration anticipée de Server si nécessaire +class Client; +class CommandHandler; -// Structure pour passer des données aux threads -struct ClientContext { - Client* client; - Server* server; - CommandHandler* cmdHandler; - - ClientContext(Client* c, Server* s, CommandHandler* ch) : client(c), server(s), cmdHandler(ch) {} -}; -class Server { +class Server +{ public: - Server(int port, const std::string& password); - ~Server(); - bool initialize(); - void run(); + Server(int port, const std::string& password); + ~Server(); + void run(); + bool initialize(); + void closeClient(int sockfd); private: - int listener; // Socket descriptor for the server - int port; // Port number to bind the server - std::string password; // Server password for client connections - bool running; // Server running status - std::vector threads; // List of threads for client management + int port; // Port d'écoute + std::string password; // Mot de passe pour les clients se connectant - static void *manageClient(void *clientContext); // Static to be compatible with pthread + bool running; // État d'exécution du serveur + int listener; // Socket d'écoute du serveur + int fdmax; + fd_set master_set; // Ensemble principal des descripteurs de fichiers pour select + std::map clients; // Mapping de socket à Client + std::map handlers; // CommandHandler pour chaque client + + void acceptNewClient(); + bool handleClientActivity(int sockfd); + bool getlineFromClient(Client* client, std::string& line); + void handleIRCMessages(Client* client, CommandHandler& cmdHandler); + bool processInitialCommands(Client* client); }; #endif // SERVER_HPP - - diff --git a/ft_irc/include/Utilities.hpp b/ft_irc/include/Utilities.hpp index ca3e665..0b5ef13 100644 --- a/ft_irc/include/Utilities.hpp +++ b/ft_irc/include/Utilities.hpp @@ -1,12 +1,12 @@ /* ************************************************************************** */ /* */ /* ::: :::::::: */ -/* utilities.hpp :+: :+: :+: */ +/* Utilities.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/09 14:22:54 by fgras-ca #+# #+# */ -/* Updated: 2024/05/09 14:35:04 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/11 13:34:54 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -22,10 +22,7 @@ namespace Utilities { // Split a string by a delimiter and return a vector of substrings - std::vector split(const std::string& s, char delimiter); - - // Trim whitespace from the start and end of a string - std::string trim(const std::string& s); + std::vector split(const std::string& str, char delimiter); } #endif // UTILITIES_HPP diff --git a/ft_irc/include/color.hpp b/ft_irc/include/color.hpp new file mode 100644 index 0000000..09ee27d --- /dev/null +++ b/ft_irc/include/color.hpp @@ -0,0 +1,27 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* color.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: fgras-ca +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/05/12 16:31:27 by fgras-ca #+# #+# */ +/* Updated: 2024/05/12 16:35:03 by fgras-ca ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef COLOR_HPP +#define COLOR_HPP + +# define RESET "\033[0m" +# define GRAY "\033[0;90m" +# define RED "\033[0;91m" +# define GREEN "\033[0;92m" +# define YELLOW "\033[0;93m" +# define BLUE "\033[0;94m" +# define MAGENTA "\033[0;95m" +# define CYAN "\033[0;96m" +# define WHITE "\033[0;97m" +# define ORANGE "\033[38;5;214m" + +#endif \ No newline at end of file diff --git a/ft_irc/ircserv b/ft_irc/ircserv index e37856d..1505a2c 100755 Binary files a/ft_irc/ircserv and b/ft_irc/ircserv differ diff --git a/ft_irc/src/Client.cpp b/ft_irc/src/Client.cpp index 22355da..44365da 100644 --- a/ft_irc/src/Client.cpp +++ b/ft_irc/src/Client.cpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/09 14:07:27 by fgras-ca #+# #+# */ -/* Updated: 2024/05/10 13:33:20 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/11 16:11:10 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -14,6 +14,8 @@ #include #include +Client::Client() {} + Client::Client(int socket, const std::string& nickname, const std::string& username) : socket(socket), nickname(nickname), username(username) {} @@ -57,3 +59,11 @@ int Client::getSocket() const { return socket; } +void Client::setUsername(const std::string& newUsername) { + nickname = newUsername; +} + +void Client::setRealname(const std::string& newRealname) { + // Assurez-vous d'avoir un membre `realname` dans Client + username = newRealname; +} \ No newline at end of file diff --git a/ft_irc/src/CommandHandler.cpp b/ft_irc/src/CommandHandler.cpp index 0ad09b2..a4a5a60 100644 --- a/ft_irc/src/CommandHandler.cpp +++ b/ft_irc/src/CommandHandler.cpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/09 14:19:15 by fgras-ca #+# #+# */ -/* Updated: 2024/05/10 12:33:00 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/12 17:11:00 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -14,28 +14,42 @@ CommandHandler::CommandHandler() {} -CommandHandler::~CommandHandler() { - for (std::map::iterator it = channels.begin(); it != channels.end(); ++it) { +CommandHandler::~CommandHandler() +{ + for (std::map::iterator it = channels.begin(); it != channels.end(); ++it) + { delete it->second; } channels.clear(); } -void CommandHandler::handleCommand(const std::string& command, Client* client) { - if (command.find("JOIN ") == 0) { - handleJoin(command, client); - } else if (command.find("PART ") == 0) { - handlePart(command, client); - } else if (command.find("NICK ") == 0) { - handleNick(command, client); - } else if (command.find("PRIVMSG ") == 0) { - handlePrivmsg(command, client); - } else if (command == "QUIT") { +void CommandHandler::handleCommand(const std::string& commandLine, Client* client) +{ + std::istringstream stream(commandLine); + std::string command; + stream >> command; + + if (command == "JOIN") { + std::cout << "Commande Join reconnue" << std::endl; + handleJoin(commandLine, client); + } else if (command == "PART") { + std::cout << "Commande part reconnue" << std::endl; + handlePart(commandLine, client); + } else if (command == "NICK") { + std::cout << "Commande nick reconnue" << std::endl; + handleNick(commandLine, client); + } else if (command == "PRIVMSG") { + std::cout << "Commande privmsg reconnue" << std::endl; + handlePrivmsg(commandLine, client); + } /*else if (command == "QUIT") { + std::cout << "Commande quit reconnue" << std::endl; handleQuit(client); - } + }*/ + // Ajoutez d'autres commandes IRC ici } void CommandHandler::handleJoin(const std::string& command, Client* client) { + std::cout << "Lancement fonction Join reconnue" << std::endl; std::vector tokens = split(command, ' '); if (tokens.size() > 1) { std::string channelName = tokens[1]; @@ -78,11 +92,11 @@ void CommandHandler::handlePrivmsg(const std::string& command, Client* client) { } } -void CommandHandler::handleQuit(Client* client) { +/*void CommandHandler::handleQuit(Client* client) { for (std::map::iterator it = channels.begin(); it != channels.end(); ++it) { it->second->removeClient(client); } -} +}*/ std::vector CommandHandler::split(const std::string& s, char delimiter) { std::vector tokens; diff --git a/ft_irc/src/Server.cpp b/ft_irc/src/Server.cpp index f487f5e..7dd6f6a 100644 --- a/ft_irc/src/Server.cpp +++ b/ft_irc/src/Server.cpp @@ -6,115 +6,321 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/09 14:01:34 by fgras-ca #+# #+# */ -/* Updated: 2024/05/10 14:13:02 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/12 17:07:02 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ -// Server.cpp #include "Server.hpp" -Server::Server(int port, const std::string& password) : port(port), password(password), running(false) {} +Server::Server(int port, const std::string& password) : port(port), password(password), running(false) + { + FD_ZERO(&master_set); + std::cout << GREEN << "Server constructed for port: " << RESET << port << std::endl; + } -Server::~Server() { - for (size_t i = 0; i < threads.size(); ++i) { - if (threads[i]) pthread_join(threads[i], NULL); - } - close(listener); +Server::~Server() +{ + std::map::iterator it; + for (it = clients.begin(); it != clients.end(); ++it) + { + delete it->second; + close(it->first); + } + std::map::iterator itHandler; + for (itHandler = handlers.begin(); itHandler != handlers.end(); ++itHandler) + { + delete itHandler->second; + } + std::cout << RED << "Server destroyed, all clients closed." << RESET << std::endl; } -bool Server::initialize() { - struct sockaddr_in server_addr; - listener = socket(AF_INET, SOCK_STREAM, 0); - if (listener == -1) { - std::cerr << "Error creating socket: " << strerror(errno) << std::endl; - return false; - } +bool Server::initialize() +{ + struct sockaddr_in server_addr; + listener = socket(AF_INET, SOCK_STREAM, 0); + if (listener == -1) + { + std::cerr << RED << "Error creating socket: " << strerror(errno) << RESET << std::endl; + return false; + } - memset(&server_addr, 0, sizeof(server_addr)); - server_addr.sin_family = AF_INET; - server_addr.sin_addr.s_addr = INADDR_ANY; - server_addr.sin_port = htons(port); + int opt = 1; + if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) + { + std::cerr << RED << "Error setting socket options: " << strerror(errno) << RESET << std::endl; + close(listener); + return false; + } - if (bind(listener, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { - std::cerr << "Error binding socket: " << strerror(errno) << std::endl; - close(listener); - return false; - } + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = INADDR_ANY; + server_addr.sin_port = htons(port); - if (listen(listener, 10) == -1) { - std::cerr << "Error listening: " << strerror(errno) << std::endl; - close(listener); - return false; - } + if (bind(listener, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) + { + std::cerr << RED << "Error binding socket: " << strerror(errno) << RESET << std::endl; + close(listener); + return false; + } - std::cout << "Server initialized and listening on port " << port << std::endl; - running = true; - return true; + if (listen(listener, 10) == -1) + { + std::cerr << RED << "Error listening: " << strerror(errno) << RESET << std::endl; + close(listener); + return false; + } + + FD_SET(listener, &master_set); + fdmax = listener; // Set the initial max file descriptor to listener + running = true; + + std::cout << GREEN << "Server initialized and listening on port: " << RESET << port << std::endl; + return true; } -void Server::run() { - if (!running) { - std::cerr << "Server not initialized or already running." << std::endl; - return; - } +bool Server::getlineFromClient(Client* client, std::string& line) +{ + char buffer[1024]; + memset(buffer, 0, sizeof(buffer)); + int len = recv(client->getSocket(), buffer, sizeof(buffer) - 1, 0); - CommandHandler cmdHandler; - while (running) { - struct sockaddr_in client_addr; - socklen_t client_len = sizeof(client_addr); - int client_sock = accept(listener, (struct sockaddr *)&client_addr, &client_len); - if (client_sock == -1) { - std::cerr << "Error accepting connection: " << strerror(errno) << std::endl; - continue; - } - - Client* newClient = new Client(client_sock, "DefaultNickname", "DefaultUsername"); - ClientContext* context = new ClientContext(newClient, this, &cmdHandler); - pthread_t thread; - pthread_create(&thread, NULL, &Server::manageClient, context); - pthread_detach(thread); - threads.push_back(thread); - } + if (len > 0) + { + buffer[len] = '\0'; // Ensure null termination + line = std::string(buffer); + line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); + line.erase(std::remove(line.begin(), line.end(), '\n'), line.end()); + return true; + } + else if (len == 0) + { + std::cout << RED << "Client disconnected." << RESET << std::endl; + return false; // Connection is closed + } + else + { + std::cerr << RED << "Error reading from client socket: " << strerror(errno) << RESET << std::endl; + return false; // An error occurred + } } -void* Server::manageClient(void *clientContext) { - ClientContext* ctx = static_cast(clientContext); - Client* client = ctx->client; - Server* server = ctx->server; +bool Server::processInitialCommands(Client* client) +{ + std::string line; + bool isAuthenticated = false; // Pour garder une trace de l'authentification - client->sendMessage("Welcome to the IRC Server!\n"); - client->sendMessage("Password required:\n"); + while (getlineFromClient(client, line) && !line.empty()) + { + std::cout << MAGENTA << "Processing line: " << RESET << line << std::endl; + // Extraction et traitement de la commande PASS + size_t passEnd = line.find("NICK"); + if (passEnd != std::string::npos) + { + std::string passCommand = line.substr(0, passEnd); + std::istringstream passIss(passCommand); + std::string passToken, extractedPassword; + passIss >> passToken >> extractedPassword; + if (extractedPassword != this->password) + { + client->sendMessage("ERROR :Wrong password\r\n"); + std::cout << RED << "Authentication failed for password: " << RESET << extractedPassword << std::endl; + return false; + } + else + { + std::cout << "CLIENT Socket: " << client->getSocket() << GREEN << " :Authentication successful." << RESET << std::endl; + isAuthenticated = true; + } + } - std::string passwordInput = client->receiveMessage(); - std::cout << "Received password: [" << passwordInput << "]" << std::endl; - - if (passwordInput != server->password) { - client->sendMessage("Incorrect password.\n"); - std::cout << "Password mismatch." << std::endl; - close(client->getSocket()); - delete client; - delete ctx; - return NULL; - } - - client->sendMessage("Password correct.\n"); - - std::string command; - while ((command = client->receiveMessage()) != "") { - ctx->cmdHandler->handleCommand(command, client); - if (command == "QUIT") break; - } - - close(client->getSocket()); - delete client; - delete ctx; - return NULL; + // Traitement des commandes NICK et USER + if (isAuthenticated) + { // Seulement si authentifié + size_t nickEnd = line.find("USER"); + if (nickEnd != std::string::npos) + { + std::string nickCommand = line.substr(passEnd, nickEnd - passEnd); + std::istringstream nickIss(nickCommand); + std::string nickToken, nickname; + nickIss >> nickToken >> nickname; + client->setNickname(nickname); + std::cout << BLUE << "NickName SET: " << RESET << nickname << std::endl; + std::string userCommand = line.substr(nickEnd); + std::istringstream userIss(userCommand); + std::string userToken, username, realname; + userIss >> userToken >> username; + size_t realnameStart = userCommand.find(":"); + if (realnameStart != std::string::npos) + { + realname = userCommand.substr(realnameStart + 1); + client->setUsername(username); + client->setRealname(realname); + std::cout << GREEN << "CLIENT: " << "SET NickName: " << nickname << "; UserName: " << username << "; Socket: " << client->getSocket() << RESET << std::endl; + break; + } + } + } + } + // Après une authentification réussie, passez à la gestion des messages IRC + if (isAuthenticated) + { + handleIRCMessages(client, *new CommandHandler()); // Attention à la gestion de la mémoire ici + } + return isAuthenticated; +} +// Handle IRC commands +void Server::handleIRCMessages(Client* client, CommandHandler& cmdHandler) +{ + std::string line; + while (getlineFromClient(client, line) && !line.empty()) + { + std::cout << YELLOW << "Handling IRC message: " << RESET << line << std::endl; + cmdHandler.handleCommand(line, client); + if (line.find("QUIT") != std::string::npos) + { + std::cout << RED << "Client Socket (" << client->getSocket() << ") requested to quit." << RESET << std::endl; + closeClient(client->getSocket()); // Assuming you have a method to close clients + break; + } + } } +void Server::run() +{ + fd_set read_fds; + struct timeval timeout; + if (!initialize()) + { + std::cerr << RED << "Server initialization failed. Exiting..." << RESET << std::endl; + return; + } + std::cout << GREEN << "Server is running on port: " << RESET << port << std::endl; + while (running) + { + FD_ZERO(&read_fds); + FD_SET(listener, &read_fds); + std::map::iterator it; + for (it = clients.begin(); it != clients.end(); ++it) + { + FD_SET(it->first, &read_fds); + } + timeout.tv_sec = 5; + timeout.tv_usec = 0; + std::cout << ORANGE << "Waiting for select..." << RESET << std::endl; + int selectResult = select(fdmax + 1, &read_fds, NULL, NULL, &timeout); + if (selectResult == -1) + { + perror("Select error"); + continue; + } + else if (selectResult == 0) + { + std::cout << GRAY << "Select timeout occurred, no activity." << RESET << std::endl; + continue; + } + if (FD_ISSET(listener, &read_fds)) + { + acceptNewClient(); + } + for (int i = 0; i <= fdmax; i++) + { + if (i != listener && FD_ISSET(i, &read_fds)) + { + if (!handleClientActivity(i)) + { + closeClient(i); + } + } + } + } +} + +void Server::acceptNewClient() +{ + struct sockaddr_in client_addr; + socklen_t addrlen = sizeof(client_addr); + std::cout << CYAN << "Ready to accept new connection..." << RESET << std::endl; + int newfd = accept(listener, (struct sockaddr *)&client_addr, &addrlen); + + if (newfd == -1) + { + perror("Accept failed"); + return; + } + + clients[newfd] = new Client(newfd); + FD_SET(newfd, &master_set); + if (newfd > fdmax) + { + fdmax = newfd; + } + + std::cout << GREEN << "Accepted new client: " << inet_ntoa(client_addr.sin_addr) << " on fd: " << newfd << RESET << std::endl; +} + +bool Server::handleClientActivity(int sockfd) +{ + Client* client = clients[sockfd]; + if (!client) + { + std::cerr << RED << "Client not found for socket " << RESET << sockfd << std::endl; + return false; + } + + std::string line; + if (getlineFromClient(client, line) && !line.empty()) + { + std::cout << GREEN << "Received message: [" << line << "]" << RESET << std::endl; + CommandHandler* cmdHandler = handlers[sockfd]; + cmdHandler->handleCommand(line, client); + return true; + } + else + { + std::cerr << RED << "Client disconnected or error on socket: " << RESET << sockfd << std::endl; + return false; + } +} + +void Server::closeClient(int sockfd) +{ + std::map::iterator it = clients.find(sockfd); + if (it != clients.end()) + { + delete it->second; + clients.erase(it); + } + + std::map::iterator handlerIt = handlers.find(sockfd); + if (handlerIt != handlers.end()) + { + delete handlerIt->second; + handlers.erase(handlerIt); + } + + close(sockfd); // Close the socket + FD_CLR(sockfd, &master_set); // Remove from the master set + + // Recalculate fdmax + if (sockfd == fdmax) + { + fdmax = listener; // Reset fdmax to the listener's socket + for (it = clients.begin(); it != clients.end(); ++it) + { + if (it->first > fdmax) + { + fdmax = it->first; + } + } + } + + std::cout << RED << "Closed client on socket: " << RESET << sockfd << std::endl; +} diff --git a/ft_irc/src/main.cpp b/ft_irc/src/main.cpp index 366aabf..da2371e 100644 --- a/ft_irc/src/main.cpp +++ b/ft_irc/src/main.cpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/09 14:00:46 by fgras-ca #+# #+# */ -/* Updated: 2024/05/09 14:00:52 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/11 17:16:28 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -21,11 +21,7 @@ int main(int argc, char* argv[]) { std::string password = argv[2]; Server ircServer(port, password); - if (!ircServer.initialize()) { - std::cerr << "Failed to initialize server." << std::endl; - return 1; - } - ircServer.run(); + ircServer.run(); // initialize() sera appelée au début de run() return 0; } diff --git a/ft_irc/src/utilities.cpp b/ft_irc/src/utilities.cpp index cf22ea1..c48b07c 100644 --- a/ft_irc/src/utilities.cpp +++ b/ft_irc/src/utilities.cpp @@ -6,7 +6,7 @@ /* By: fgras-ca +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/09 14:23:12 by fgras-ca #+# #+# */ -/* Updated: 2024/05/09 14:34:50 by fgras-ca ### ########.fr */ +/* Updated: 2024/05/11 13:35:49 by fgras-ca ### ########.fr */ /* */ /* ************************************************************************** */ @@ -14,22 +14,14 @@ namespace Utilities { -std::vector split(const std::string& s, char delimiter) { +std::vector split(const std::string& str, char delimiter) { std::vector tokens; + std::stringstream ss(str); std::string token; - std::istringstream tokenStream(s); - while (std::getline(tokenStream, token, delimiter)) { - tokens.push_back(trim(token)); + while (getline(ss, token, delimiter)) { + tokens.push_back(token); } return tokens; } -std::string trim(const std::string& str) { - size_t first = str.find_first_not_of(' '); - if (first == std::string::npos) - return ""; - size_t last = str.find_last_not_of(' '); - return str.substr(first, (last - first + 1)); -} - }