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 <iostream>
# include <stdexcept> # include <stdexcept>
# include <cstring> # include <cstring>
# include <csignal>
# include <cerrno> # include <cerrno>
# include "CommandValidator.hpp" # include "CommandValidator.hpp"
# include "Channel.hpp" # include "Channel.hpp"

View File

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

View File

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

View File

@ -1,5 +1,7 @@
#include "Server.hpp" #include "Server.hpp"
extern volatile sig_atomic_t g_stop;
void Server::start(void) void Server::start(void)
{ {
_serverFd = socket(AF_INET, SOCK_STREAM, 0); _serverFd = socket(AF_INET, SOCK_STREAM, 0);
@ -36,7 +38,7 @@ void Server::start(void)
pollfd.events = POLLIN; pollfd.events = POLLIN;
pollfd.revents = 0; pollfd.revents = 0;
_fds.push_back(pollfd); _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) 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) 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) 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); close(fd);
_users.erase(fd); _users.erase(fd);
for (size_t i = 0; i < _fds.size(); i++) for (size_t i = 0; i < _fds.size(); i++)
@ -108,7 +128,7 @@ void Server::acceptNew(void)
{ {
int newFd = accept(_serverFd, NULL, NULL); int newFd = accept(_serverFd, NULL, NULL);
if (newFd == -1) if (newFd == -1)
throw std::runtime_error(strerror(errno)); return ;
fcntl(newFd, F_SETFL, O_NONBLOCK); fcntl(newFd, F_SETFL, O_NONBLOCK);
int flag = 1; int flag = 1;
setsockopt(newFd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)); setsockopt(newFd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
@ -143,12 +163,16 @@ void Server::handleRecv(int fd)
_users[fd].parseBuffer.append(buf, n); _users[fd].parseBuffer.append(buf, n);
std::vector<IrcMessage> messages = _users[fd].parseBuffer.extractMessages(); std::vector<IrcMessage> messages = _users[fd].parseBuffer.extractMessages();
for (size_t i = 0; i < messages.size(); i++) for (size_t i = 0; i < messages.size(); i++)
{
if (_users.find(fd) == _users.end())
break ;
dispatch(fd, messages[i]); dispatch(fd, messages[i]);
}
} }
void Server::run(void) void Server::run(void)
{ {
while (true) while (!g_stop)
{ {
int ret = poll(_fds.data(), _fds.size(), -1); int ret = poll(_fds.data(), _fds.size(), -1);
if (ret == -1) if (ret == -1)
@ -163,8 +187,14 @@ void Server::run(void)
removeUser(fd); removeUser(fd);
i--; i--;
} }
else if ( _fds[i].revents & POLLIN) else if (_fds[i].revents & POLLIN)
{
size_t before = _fds.size();
handleRecv(_fds[i].fd); 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) void Server::handleNick(int fd, const IrcMessage &msg)
{ {
std::string newNick = msg.param(0); 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(); std::map<int, ConnectedUser>::iterator it = _users.begin();
for (; it != _users.end(); it++) for (; it != _users.end(); it++)
{ {
@ -233,8 +292,28 @@ void Server::handleNick(int fd, const IrcMessage &msg)
return ; return ;
} }
} }
bool wasRegistered = _users[fd].isRegistered();
std::string oldNick = _users[fd].nick;
_users[fd].nick = newNick; _users[fd].nick = newNick;
_users[fd].nickOk = true; _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) 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"; std::string msg_rm = ":" + _users[fd].nick + "!" + _users[fd].username + "@localhost PART " + chanName + "\r\n";
broadcastToChannel(chanName, msg_rm, -1); broadcastToChannel(chanName, msg_rm, -1);
chan.removeMember(fd); chan.removeMember(fd);
chan.removeOperator(fd);
chan.removeInvited(fd);
if (chan.memberCount() == 0) if (chan.memberCount() == 0)
_channels.erase(chanName); _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"; std::string kick_msg = ":" + _users[fd].nick + "!" + _users[fd].username + "@localhost KICK " + chanName + " " + targetNick + "\r\n";
broadcastToChannel(chanName, kick_msg, -1); broadcastToChannel(chanName, kick_msg, -1);
chan.removeMember(targetFd); chan.removeMember(targetFd);
chan.removeOperator(targetFd);
chan.removeInvited(targetFd);
} }
void Server::handleInvite(int fd, const IrcMessage &msg) 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 chanName = msg.param(0);
std::string modeStr = msg.param(1); std::string modeStr = msg.param(1);
if (modeStr.size() < 2 || (modeStr[0] != '+' && modeStr[0] != '-'))
return ;
if (chanName.empty() || chanName[0] != '#') if (chanName.empty() || chanName[0] != '#')
return ; return ;
if (_channels.find(chanName) == _channels.end()) if (_channels.find(chanName) == _channels.end())