This commit is contained in:
Ubuntu 2026-06-04 21:24:43 +00:00
parent f1a7e3e8f7
commit 6732e59a03
5 changed files with 130 additions and 6 deletions

25
DEFENSE.txt Normal file
View File

@ -0,0 +1,25 @@
irssi
/connect localhost 6667 pass
/nick bob
/quote NICK 1abc
/quote PING coucou
/join #test
/quote PRIVMSG #test :salut
/quote PRIVMSG bob :coucou
/part #test
/join #test
/quote TOPIC #test
/quote TOPIC #test :nouveau sujet
/quote MODE #test +i
/quote MODE #test -i
/quote MODE #test +t
/quote MODE #test -t
/quote MODE #test +k secret
/quote MODE #test -k
/quote MODE #test +l 2
/quote MODE #test -l
/quote MODE #test +o alice
/quote MODE #test -o alice
/quote INVITE alice #test
/quote KICK #test alice
/quote QUIT

View File

@ -15,6 +15,7 @@
# include <iostream>
# include <stdexcept>
# include <cstring>
# include <csignal>
# include <cerrno>
# include "CommandValidator.hpp"
# include "Channel.hpp"

View File

@ -1,7 +1,15 @@
#include <iostream>
#include <cstdlib>
#include <csignal>
#include "Server.hpp"
volatile sig_atomic_t g_stop = 0;
void handleSig(int)
{
g_stop = 1;
}
int main(int argc, char **argv)
{
if (argc != 3)
@ -15,6 +23,8 @@ int main(int argc, char **argv)
std::cerr << "Error: invalid port" << std::endl;
return (1);
}
signal(SIGINT, handleSig);
signal(SIGQUIT, handleSig);
try
{
Server server(port, argv[2]);

View File

@ -53,6 +53,9 @@ bool IrcMessage::hasParam(size_t index) const
const std::string &IrcMessage::param(size_t index) const
{
static const std::string empty;
if (index >= _params.size())
return (empty);
return (_params[index]);
}

View File

@ -1,5 +1,7 @@
#include "Server.hpp"
extern volatile sig_atomic_t g_stop;
void Server::start(void)
{
_serverFd = socket(AF_INET, SOCK_STREAM, 0);
@ -36,7 +38,7 @@ void Server::start(void)
pollfd.events = POLLIN;
pollfd.revents = 0;
_fds.push_back(pollfd);
std::cout << "FT_IRC server startded on " << _port << " Port." << std::endl << "The password is \"" << _password << "\"." << std::endl;
std::cout << "FT_IRC server startded on " << _port << " Port." << std::endl << "The password is \"" << _password << "\"." << std::endl << "Ctrl+c for shutdown the server" << std::endl;
}
ConnectedUser::ConnectedUser(void) : fd(-1), passOk(false), nickOk(false), userOk(false)
@ -87,11 +89,29 @@ Server::~Server(void)
void Server::sendReply(int fd, const std::string &msg)
{
send(fd, msg.c_str(), msg.size(), 0);
size_t total = 0;
while (total < msg.size())
{
ssize_t s = send(fd, msg.c_str() + total, msg.size() - total, 0);
if (s <= 0)
return ;
total += static_cast<size_t>(s);
}
}
void Server::removeUser(int fd)
{
std::map<std::string, Channel>::iterator it = _channels.begin();
while (it != _channels.end())
{
it->second.removeMember(fd);
it->second.removeOperator(fd);
it->second.removeInvited(fd);
if (it->second.memberCount() == 0)
_channels.erase(it++);
else
++it;
}
close(fd);
_users.erase(fd);
for (size_t i = 0; i < _fds.size(); i++)
@ -108,7 +128,7 @@ void Server::acceptNew(void)
{
int newFd = accept(_serverFd, NULL, NULL);
if (newFd == -1)
throw std::runtime_error(strerror(errno));
return ;
fcntl(newFd, F_SETFL, O_NONBLOCK);
int flag = 1;
setsockopt(newFd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
@ -143,12 +163,16 @@ void Server::handleRecv(int fd)
_users[fd].parseBuffer.append(buf, n);
std::vector<IrcMessage> messages = _users[fd].parseBuffer.extractMessages();
for (size_t i = 0; i < messages.size(); i++)
{
if (_users.find(fd) == _users.end())
break ;
dispatch(fd, messages[i]);
}
}
void Server::run(void)
{
while (true)
while (!g_stop)
{
int ret = poll(_fds.data(), _fds.size(), -1);
if (ret == -1)
@ -163,8 +187,14 @@ void Server::run(void)
removeUser(fd);
i--;
}
else if ( _fds[i].revents & POLLIN)
else if (_fds[i].revents & POLLIN)
{
size_t before = _fds.size();
handleRecv(_fds[i].fd);
if (_fds.size() < before)
i--;
}
}
}
}
@ -221,9 +251,38 @@ void Server::handlePass(int fd, const IrcMessage &msg)
}
}
static bool isNickChar(char c, bool first)
{
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
return (true);
if (c == '[' || c == ']' || c == '\\' || c == '`'
|| c == '_' || c == '^' || c == '{' || c == '|' || c == '}')
return (true);
if (!first && ((c >= '0' && c <= '9') || c == '-'))
return (true);
return (false);
}
static bool isValidNick(const std::string &nick)
{
if (nick.empty())
return (false);
for (size_t i = 0; i < nick.size(); ++i)
{
if (!isNickChar(nick[i], i == 0))
return (false);
}
return (true);
}
void Server::handleNick(int fd, const IrcMessage &msg)
{
std::string newNick = msg.param(0);
if (!isValidNick(newNick))
{
sendReply(fd, "432 * " + newNick + " :Erroneous nickname\r\n");
return ;
}
std::map<int, ConnectedUser>::iterator it = _users.begin();
for (; it != _users.end(); it++)
{
@ -233,8 +292,28 @@ void Server::handleNick(int fd, const IrcMessage &msg)
return ;
}
}
bool wasRegistered = _users[fd].isRegistered();
std::string oldNick = _users[fd].nick;
_users[fd].nick = newNick;
_users[fd].nickOk = true;
if (wasRegistered && oldNick != newNick)
{
std::string notice = ":" + oldNick + "!" + _users[fd].username
+ "@localhost NICK " + newNick + "\r\n";
std::map<int, bool> seen;
seen[fd] = true;
for (std::map<std::string, Channel>::iterator cit = _channels.begin();
cit != _channels.end(); ++cit)
{
if (!cit->second.hasMember(fd))
continue ;
const std::vector<int> &mem = cit->second.getMembers();
for (size_t i = 0; i < mem.size(); ++i)
seen[mem[i]] = true;
}
for (std::map<int, bool>::iterator sit = seen.begin(); sit != seen.end(); ++sit)
sendReply(sit->first, notice);
}
}
void Server::handleUser(int fd, const IrcMessage &msg)
@ -327,6 +406,8 @@ void Server::handlePart(int fd, const IrcMessage &msg)
std::string msg_rm = ":" + _users[fd].nick + "!" + _users[fd].username + "@localhost PART " + chanName + "\r\n";
broadcastToChannel(chanName, msg_rm, -1);
chan.removeMember(fd);
chan.removeOperator(fd);
chan.removeInvited(fd);
if (chan.memberCount() == 0)
_channels.erase(chanName);
}
@ -408,6 +489,8 @@ void Server::handleKick(int fd, const IrcMessage &msg)
std::string kick_msg = ":" + _users[fd].nick + "!" + _users[fd].username + "@localhost KICK " + chanName + " " + targetNick + "\r\n";
broadcastToChannel(chanName, kick_msg, -1);
chan.removeMember(targetFd);
chan.removeOperator(targetFd);
chan.removeInvited(targetFd);
}
void Server::handleInvite(int fd, const IrcMessage &msg)
@ -486,6 +569,8 @@ void Server::handleMode(int fd, const IrcMessage &msg)
{
std::string chanName = msg.param(0);
std::string modeStr = msg.param(1);
if (modeStr.size() < 2 || (modeStr[0] != '+' && modeStr[0] != '-'))
return ;
if (chanName.empty() || chanName[0] != '#')
return ;
if (_channels.find(chanName) == _channels.end())