ft_irc/ft_irc3/src/Server.cpp
2024-06-06 14:16:52 +02:00

252 lines
5.8 KiB
C++

/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Server.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: fgras-ca <fgras-ca@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/15 12:17:12 by fgras-ca #+# #+# */
/* Updated: 2024/06/06 13:00:25 by fgras-ca ### ########.fr */
/* */
/* ************************************************************************** */
#include "Server.hpp"
Server::Server(int port, const std::string &password)
: _port(port), _password(password), _clientManager(new ClientManager(this)), _commandHandler(new CommandHandler(this)), _modeHandler(new ModeHandler(this)), _topicHandler(new TopicHandler(this))
{
initServer();
_botFilter = new BotFilter(this);
_botFilter->loadBadWords("badwords.txt");
}
Server::~Server()
{
delete _clientManager;
delete _commandHandler;
delete _topicHandler;
delete _botFilter;
for (std::map<int, Client*>::iterator it = _clients.begin(); it != _clients.end(); ++it)
{
delete it->second;
}
for (std::map<std::string, Channel*>::iterator it = _channels.begin(); it != _channels.end(); ++it)
{
delete it->second;
}
close(_server_fd);
}
void Server::initServer()
{
_server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (_server_fd == -1)
{
log("Failed to create socket.", RED);
exit(EXIT_FAILURE);
}
int opt = 1;
if (setsockopt(_server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1)
{
log("Failed to set socket options.", RED);
close(_server_fd);
exit(EXIT_FAILURE);
}
struct sockaddr_in server_addr;
std::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 (bind(_server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
{
log("Failed to bind socket.", RED);
close(_server_fd);
exit(EXIT_FAILURE);
}
if (listen(_server_fd, SOMAXCONN) == -1)
{
log("Failed to listen on socket.", RED);
close(_server_fd);
exit(EXIT_FAILURE);
}
log("Server initialized.", GREEN);
}
void Server::run()
{
struct pollfd server_pollfd;
server_pollfd.fd = _server_fd;
server_pollfd.events = POLLIN;
server_pollfd.revents = 0;
_poll_fds.push_back(server_pollfd);
struct pollfd stdin_pollfd;
stdin_pollfd.fd = STDIN_FILENO;
stdin_pollfd.events = POLLIN;
stdin_pollfd.revents = 0;
_poll_fds.push_back(stdin_pollfd);
while (true)
{
int poll_count = poll(&_poll_fds[0], _poll_fds.size(), -1);
if (poll_count == -1)
{
log("Poll error.", RED);
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < _poll_fds.size(); ++i)
{
if (_poll_fds[i].revents & POLLIN)
{
if (_poll_fds[i].fd == _server_fd)
{
_clientManager->acceptClient();
}
else if (_poll_fds[i].fd == STDIN_FILENO)
{
handleServerCommands();
}
else
{
_clientManager->handleClient(_poll_fds[i].fd);
}
}
}
}
}
std::map<std::string, Channel *> &Server::getChannels()
{
return _channels;
}
const std::string &Server::getPassword() const
{
return _password;
}
void Server::handleServerCommands()
{
std::string command;
std::getline(std::cin, command);
if (command == "quit")
{
log("Server shutting down.", YELLOW);
exit(EXIT_SUCCESS);
}
else if (command == "channels")
{
log("Listing all channels:", BLUE);
for (std::map<std::string, Channel*>::iterator it = _channels.begin(); it != _channels.end(); ++it)
{
log(it->first, BLUE);
}
}
else if (command == "clients")
{
log("Listing all clients:", BLUE);
for (std::map<int, Client*>::iterator it = _clients.begin(); it != _clients.end(); ++it)
{
log(it->second->getNickname(), BLUE);
}
}
else
{
log("Unknown server command.", RED);
}
}
void Server::log(const std::string &message, const std::string &color)
{
std::cout << color << message << std::endl;
}
void Server::sendToClient(int client_fd, const std::string &message)
{
int result = send(client_fd, message.c_str(), message.length(), 0);
if (result < 0)
{
std::stringstream ss;
ss << "Failed to send message to client " << client_fd;
log(ss.str(), RED);
}
else
{
std::stringstream ss;
ss << "Sent message to client " << client_fd << ": " << message;
log(ss.str(), YELLOW);
}
}
std::map<int, Client *> &Server::getClients()
{
return _clients;
}
void Server::broadcast(const std::string &message)
{
for (std::map<int, Client *>::iterator it = _clients.begin(); it != _clients.end(); ++it)
{
sendToClient(it->first, message);
}
}
Client* Server::getClientByName(const std::string &name)
{
for (std::map<int, Client *>::iterator it = _clients.begin(); it != _clients.end(); ++it)
{
if (it->second->getNickname() == name)
{
return it->second;
}
}
return NULL;
}
Channel* Server::getChannelByName(const std::string &name)
{
std::map<std::string, Channel *>::iterator it = _channels.find(name);
if (it != _channels.end())
{
return it->second;
}
return NULL;
}
bool Server::MatchFd(const pollfd& pfd, int clientFd)
{
return pfd.fd == clientFd;
}
void Server::removePollFd(int clientFd)
{
for (std::vector<struct pollfd>::iterator it = _poll_fds.begin(); it != _poll_fds.end(); ++it)
{
if (MatchFd(*it, clientFd))
{
_poll_fds.erase(it);
break;
}
}
}
void Server::disconnectClient(int clientFd)
{
close(clientFd);
_clients.erase(clientFd);
removePollFd(clientFd);
std::ostringstream oss;
oss << "Client disconnected: " << clientFd;
log(oss.str(), YELLOW);
}