Files
MiniChat/Srcs/Server.cpp
2024-05-03 16:25:20 +01:00

240 lines
8.6 KiB
C++

#include "Server.hpp"
int opperatorfd = 0;
int issettop = 0;
int isinvited = 0;
int itHasPass = 0;
int channelLimit = 0;
int limitchannelforincrement = 0;
int abaaba = 0;
bool Server::_signal = false;
Server::Server() {}
Server::~Server() {}
std::string Server::getPassowrd() const {
return _password;
}
void Server::receiveSignal(int signum) {
_signal = true;
(void)signum;
}
Client& Server::getClientByFd(int fd) {
size_t i = 0;
for (; i < _clients.size(); ++i) {
if (_clients[i].getFd() == fd)
break;
}
return _clients[i];
}
void Server::setNickname(int fd, const std::string& nickname) {nicknames[fd] = nickname;}
void Server::setUsernames(int fd, const std::string& username) {usernames[fd] = username;}
void Server::init() {
signal(SIGINT, receiveSignal);
signal(SIGQUIT, receiveSignal);
createServerSocket();
std::cout << GREEN << ">>> SERVER STARTED <<<" << RESET << std::endl;
std::cout << CYAN <<"Waiting for connections..." << RESET << std::endl;
}
void Server::run() {
while (!_signal) {
int ret = poll(&_fds[0], _fds.size(), -1);
if (ret == -1 && !_signal)
throw std::runtime_error("Error: poll() failed");
for (size_t i = 0; i < _fds.size(); ++i) {
if (_fds[i].revents & POLLIN) {
if (_fds[i].fd == _serverSocketFd)
handleClientConnection();
else
handleClientData(_fds[i].fd);
}
}
}
closeFds();
}
void Server::createServerSocket() {
_serverSocketFd = socket(AF_INET, SOCK_STREAM, 0);
if (_serverSocketFd == -1)
throw std::runtime_error("Error: failed to create socket");
int optval = 1;
if (setsockopt(_serverSocketFd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1)
throw std::runtime_error("Error: setsockopt() failed");
if (fcntl(_serverSocketFd, F_SETFL, O_NONBLOCK) == -1)
throw std::runtime_error("Error: fcntl() failed");
bindServerSocket();
if (listen(_serverSocketFd, SOMAXCONN) == -1)
throw std::runtime_error("Error: listen() failed");
addPollfd(_serverSocketFd);
}
void Server::bindServerSocket() {
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = htons(_port);
sa.sin_addr.s_addr = INADDR_ANY;
if (bind(_serverSocketFd, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
throw std::runtime_error("Error: failed to bind socket");
}
}
void Server::addPollfd(int fd) {
struct pollfd newPollfd;
newPollfd.fd = fd;
newPollfd.events = POLLIN;
newPollfd.revents = 0;
_fds.push_back(newPollfd);
}
void Server::handleClientConnection() {
struct sockaddr_in client_addr;
socklen_t clientAddrSize = sizeof(sockaddr_in);
int newFd = accept(_serverSocketFd, (struct sockaddr *)&client_addr, &clientAddrSize);
if (newFd == -1)
throw std::runtime_error("Error: accept() failed");
if (fcntl(newFd, F_SETFL, O_NONBLOCK) == -1)
throw std::runtime_error("Error: fcntl() failed");
std::string passwordRequest = "Please Enter The password Of This Server :\n";
std::string art = MINICHAT;
send(newFd, art.c_str(), art.length(), 0);
send(newFd, passwordRequest.c_str(), passwordRequest.length(), 0);
addPollfd(newFd);
_clients.push_back(Client(newFd));
std::cout << "Client <" << newFd << "> Connected" << std::endl;
}
void Server::sendJoinMsg(const std::string& nickname, const std::string& channelName, int fd) {
std::string operators = channels[channelName].getOperatorNickname(opperatorfd);
std::string operators1 = channels[channelName].getOperatorNickname(abaaba);
std::string topic = channels[channelName].getTopic();
std::string creationTimeMessage = constructJoinedTimeMessage(channelName);
std::string joinMessage = JOIN_MESSAGE(nickname, channelName);
std::string topicMessage = TOPIC_MESSAGE(nickname, channelName, topic);
send(fd, joinMessage.c_str(), joinMessage.length(), 0);
send(fd, topicMessage.c_str(), topicMessage.length(), 0);
std::string namesMessage = NAMES_MESSAGE2(nickname, channelName);
const std::vector<std::string>& clients = channels[channelName].getClients();
for (size_t i = 0; i < clients.size(); ++i) {
const std::string& user = clients[i];
if (user == operators || user == operators1) {
namesMessage += "@" + user;
} else {
namesMessage += user;
}
if (i < clients.size() - 1)
namesMessage += " ";
}
namesMessage += "\n";
std::string endOfNamesMessage = END_OF_NAMES_MESSAGE(nickname, channelName);
std::string channelMessage = CHANNEL_MESSAGE(channelName, creationTimeMessage);
send(fd, namesMessage.c_str(), namesMessage.length(), 0);
send(fd, endOfNamesMessage.c_str(), endOfNamesMessage.length(), 0);
send(fd, channelMessage.c_str(), channelMessage.length(), 0);
smallbroadcastMessageforjoin(nickname, channelName);
}
// handling private msg between users only
void Server::handlePrivateMessage(int senderFd, const std::string& recipient, const std::string& message) {
int recipientFd = findUserFd1(recipient);
if (recipientFd != -1) {
std::string privateMessage = PRIVATE_MESSAGE(senderFd, recipient, message);
send(recipientFd, privateMessage.c_str(), privateMessage.length(), 0);
} else {
std::string errorMessage = ERROR_MESSAGE(senderFd, recipient);
send(senderFd, errorMessage.c_str(), errorMessage.length(), 0);
}
}
void Server::handleInvitation(int senderFd, const std::string& recipient, std::string channelName) {
int recipientFd = findUserFd1(recipient);
if (recipientFd != -1) {
std::string inviteMessage = INVITE_MESSAGE(senderFd, recipient, channelName);
send(recipientFd, inviteMessage.c_str(), inviteMessage.length(), 0);
} else {
std::string errorMessage = ERROR_MESSAGE(senderFd, recipient);
send(senderFd, errorMessage.c_str(), errorMessage.length(), 0);
}
}
void Server::handleClientData(int fd)
{
Client& client = getClientByFd(fd);
char buffer[BUFFER_SIZE];
memset(buffer, 0, sizeof(buffer));
ssize_t bytesRead = recv(fd, buffer, BUFFER_SIZE - 1, 0);
if (bytesRead > 0) {
buffer[bytesRead] = '\0';
client.appendCommand(buffer);
size_t newlinePos = client.getCommand().find_first_of("\r\n");
if (newlinePos != std::string::npos) {
std::string command = client.getCommand().substr(0, newlinePos);
client.setCommand(command);
std::cout << "Received data from client " << fd << ": " << command << std::endl;
int auth = client.getAuthentication();
if ((startsWith(command, "PASS ") || startsWith(command, "pass ")) && auth == 0)
processPassword(client, command, fd);
else if ((startsWith(command, "NICK ") || startsWith(command, "nick ")) && auth == 1)
processNickCmd(client, command, fd);
else if ((startsWith(command, "USER ") || startsWith(command, "user ")) && auth == 2)
processUserCmd(client, command, fd);
else if (startsWith(command, "JOIN ") || startsWith(command, "join "))
processJoinCmd(client, command, fd);
else if (startsWith(command, "PRIVMSG ") || startsWith(command, "privmsg "))
processPrivmsgCmd(client, command, fd);
else if (startsWith(command, "KICK ") || startsWith(command, "kick "))
processKickCmd(client, command, fd);
else if (startsWith(command, "TOPIC ") || startsWith(command, "topic "))
processTopicCmd(client, command, fd);
else if (startsWith(command, "INVITE ") || startsWith(command, "invite "))
processInviteCmd(client, command, fd);
else if (startsWith(command, "BOT ") || startsWith(command, "bot "))
processBotCmd(client, command, fd);
else if (startsWith(command, "MODE ") || startsWith(command, "mode "))
processModeCmd(client, command, fd);
else if (startsWith(command, "QUIT") || startsWith(command, "quit"))
processQuitCmd(fd);
else if (startsWith(command, "PING"))
ping(command, fd);
client.clearCommand();
}
}
else if (bytesRead == 0) {
std::cout << "Client <" << fd << "> Disconnected" << std::endl;
cleanChannel(fd);
clientCleanup(fd);
} else if (bytesRead == -1) {
std::cerr << "Error reading data from client <" << fd << ">" << std::endl;
cleanChannel(fd);
clientCleanup(fd);
}
}