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
+4 -1
View File
@@ -53,7 +53,10 @@ bool IrcMessage::hasParam(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
+90 -5
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())