push
This commit is contained in:
parent
332cb7501a
commit
6b978d0673
|
|
@ -0,0 +1 @@
|
||||||
|
.claude
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
NAME = ircserv
|
||||||
|
CXX = c++
|
||||||
|
CXXFLAGS = -Wall -Wextra -Werror -std=c++98
|
||||||
|
INCLUDES = -I includes
|
||||||
|
|
||||||
|
SRCS = main.cpp \
|
||||||
|
srcs/Server.cpp \
|
||||||
|
srcs/ParseBuffer.cpp \
|
||||||
|
srcs/IrcParser.cpp \
|
||||||
|
srcs/IrcMessage.cpp \
|
||||||
|
srcs/CommandValidator.cpp
|
||||||
|
|
||||||
|
OBJS = $(SRCS:.cpp=.o)
|
||||||
|
|
||||||
|
all: $(NAME)
|
||||||
|
|
||||||
|
$(NAME): $(OBJS)
|
||||||
|
$(CXX) $(CXXFLAGS) $(OBJS) -o $(NAME)
|
||||||
|
|
||||||
|
%.o: %.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJS)
|
||||||
|
|
||||||
|
fclean: clean
|
||||||
|
rm -f $(NAME)
|
||||||
|
|
||||||
|
re: fclean all
|
||||||
|
|
||||||
|
.PHONY: all clean fclean re
|
||||||
Binary file not shown.
|
|
@ -14,6 +14,7 @@
|
||||||
# include <stdexcept>
|
# include <stdexcept>
|
||||||
# include <cstring>
|
# include <cstring>
|
||||||
# include <cerrno>
|
# include <cerrno>
|
||||||
|
# include "CommandValidator.hpp"
|
||||||
|
|
||||||
struct ConnectedUser
|
struct ConnectedUser
|
||||||
{
|
{
|
||||||
|
|
@ -27,6 +28,7 @@ struct ConnectedUser
|
||||||
bool userOk;
|
bool userOk;
|
||||||
ParseBuffer parseBuffer;
|
ParseBuffer parseBuffer;
|
||||||
|
|
||||||
|
ConnectedUser(void);
|
||||||
explicit ConnectedUser(int fd);
|
explicit ConnectedUser(int fd);
|
||||||
bool isRegistered(void) const;
|
bool isRegistered(void) const;
|
||||||
};
|
};
|
||||||
|
|
@ -43,6 +45,12 @@ class Server
|
||||||
void acceptNew(void);
|
void acceptNew(void);
|
||||||
void handleRecv(int fd);
|
void handleRecv(int fd);
|
||||||
void removeUser(int fd);
|
void removeUser(int fd);
|
||||||
|
void dispatch(int fd, const IrcMessage &msg);
|
||||||
|
void handlePass(int fd, const IrcMessage &msg);
|
||||||
|
void handleNick(int fd, const IrcMessage &msg);
|
||||||
|
void handleUser(int fd, const IrcMessage &msg);
|
||||||
|
void handlePing(int fd, const IrcMessage &msg);
|
||||||
|
void handleQuit(int fd, const IrcMessage &msg);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Server(int port, const std::string &password);
|
Server(int port, const std::string &password);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include "Server.hpp"
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc != 3)
|
||||||
|
{
|
||||||
|
std::cerr << "Usage: ./ircserv <port> <password>" << std::endl;
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
int port = std::atoi(argv[1]);
|
||||||
|
if (port <= 0 || port > 65535)
|
||||||
|
{
|
||||||
|
std::cerr << "Error: invalid port" << std::endl;
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Server server(port, argv[2]);
|
||||||
|
server.start();
|
||||||
|
server.run();
|
||||||
|
}
|
||||||
|
catch (std::exception &e)
|
||||||
|
{
|
||||||
|
std::cerr << "Error: " << e.what() << std::endl;
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
207
srcs/Server.cpp
207
srcs/Server.cpp
|
|
@ -36,4 +36,211 @@ void Server::start(void)
|
||||||
pollfd.events = POLLIN;
|
pollfd.events = POLLIN;
|
||||||
pollfd.revents = 0;
|
pollfd.revents = 0;
|
||||||
_fds.push_back(pollfd);
|
_fds.push_back(pollfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectedUser::ConnectedUser(void) : fd(-1), passOk(false), nickOk(false), userOk(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectedUser::ConnectedUser(int fd) : fd(fd), passOk(false), nickOk(false), userOk(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConnectedUser::isRegistered(void) const
|
||||||
|
{
|
||||||
|
return (passOk && nickOk && userOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
Server::Server(int port, const std::string &password)
|
||||||
|
{
|
||||||
|
_port = port;
|
||||||
|
_password = password;
|
||||||
|
_serverFd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Server::Server(const Server &other)
|
||||||
|
{
|
||||||
|
*this = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
Server &Server::operator=(const Server &other)
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
{
|
||||||
|
_serverFd = other._serverFd;
|
||||||
|
_port = other._port;
|
||||||
|
_password = other._password;
|
||||||
|
_fds = other._fds;
|
||||||
|
_users = other._users;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Server::~Server(void)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < _fds.size(); i++)
|
||||||
|
{
|
||||||
|
close(_fds[i].fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::sendReply(int fd, const std::string &msg)
|
||||||
|
{
|
||||||
|
send(fd, msg.c_str(), msg.size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::removeUser(int fd)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
_users.erase(fd);
|
||||||
|
for (size_t i = 0; i < _fds.size(); i++)
|
||||||
|
{
|
||||||
|
if (_fds[i].fd == fd)
|
||||||
|
{
|
||||||
|
_fds.erase(_fds.begin() + i);
|
||||||
|
break ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::acceptNew(void)
|
||||||
|
{
|
||||||
|
int newFd = accept(_serverFd, NULL, NULL);
|
||||||
|
if (newFd == -1)
|
||||||
|
throw std::runtime_error(strerror(errno));
|
||||||
|
fcntl(newFd, F_SETFL, O_NONBLOCK);
|
||||||
|
struct pollfd pfd;
|
||||||
|
pfd.fd = newFd;
|
||||||
|
pfd.events = POLLIN;
|
||||||
|
pfd.revents = 0;
|
||||||
|
_fds.push_back(pfd);
|
||||||
|
_users.insert(std::make_pair(newFd, ConnectedUser(newFd)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::handleRecv(int fd)
|
||||||
|
{
|
||||||
|
char buf[512];
|
||||||
|
int n;
|
||||||
|
n = recv(fd, buf, sizeof(buf), 0);
|
||||||
|
if (n == 0)
|
||||||
|
{
|
||||||
|
removeUser(fd);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
else if (n == -1)
|
||||||
|
{
|
||||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||||
|
return ;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
removeUser(fd);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_users[fd].parseBuffer.append(buf, n);
|
||||||
|
std::vector<IrcMessage> messages = _users[fd].parseBuffer.extractMessages();
|
||||||
|
for (size_t i = 0; i < messages.size(); i++)
|
||||||
|
dispatch(fd, messages[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::run(void)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int ret = poll(_fds.data(), _fds.size(), -1);
|
||||||
|
if (ret == -1)
|
||||||
|
break ;
|
||||||
|
for (size_t i = 0; i < _fds.size(); i++)
|
||||||
|
{
|
||||||
|
if (i == 0 && _fds[0].revents & POLLIN)
|
||||||
|
acceptNew();
|
||||||
|
else if (_fds[i].revents & (POLLHUP | POLLERR))
|
||||||
|
{
|
||||||
|
int fd = _fds[i].fd;
|
||||||
|
removeUser(fd);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
else if ( _fds[i].revents & POLLIN)
|
||||||
|
handleRecv(_fds[i].fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::dispatch(int fd, const IrcMessage &msg)
|
||||||
|
{
|
||||||
|
if (!msg.isValid())
|
||||||
|
return ;
|
||||||
|
const std::string &cmd = msg.getCommand();
|
||||||
|
if (CommandValidator::needsRegistration(cmd) && !_users[fd].isRegistered())
|
||||||
|
{
|
||||||
|
sendReply(fd, "451 :You have not registered\r\n");
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
else if (!CommandValidator::hasEnoughParams(msg))
|
||||||
|
{
|
||||||
|
sendReply(fd, "461 " + cmd + " :Not enough parameters\r\n");
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
else if (cmd == "PASS")
|
||||||
|
handlePass(fd, msg);
|
||||||
|
else if (cmd == "NICK")
|
||||||
|
handleNick(fd, msg);
|
||||||
|
else if (cmd == "USER")
|
||||||
|
handleUser(fd, msg);
|
||||||
|
else if (cmd == "PING")
|
||||||
|
handlePing(fd, msg);
|
||||||
|
else if (cmd == "QUIT")
|
||||||
|
handleQuit(fd, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::handlePass(int fd, const IrcMessage &msg)
|
||||||
|
{
|
||||||
|
if (msg.param(0) == _password)
|
||||||
|
_users[fd].passOk = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sendReply(fd, "464 :Password incorrect\r\n");
|
||||||
|
removeUser(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::handleNick(int fd, const IrcMessage &msg)
|
||||||
|
{
|
||||||
|
std::string newNick = msg.param(0);
|
||||||
|
std::map<int, ConnectedUser>::iterator it = _users.begin();
|
||||||
|
for (; it != _users.end(); it++)
|
||||||
|
{
|
||||||
|
if (it->second.nick == newNick && it->first != fd)
|
||||||
|
{
|
||||||
|
sendReply(fd, "433 * " + newNick + " :Nickname is already in use\r\n");
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_users[fd].nick = newNick;
|
||||||
|
_users[fd].nickOk = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::handleUser(int fd, const IrcMessage &msg)
|
||||||
|
{
|
||||||
|
if (_users[fd].isRegistered() == true)
|
||||||
|
return ;
|
||||||
|
_users[fd].username = msg.param(0);
|
||||||
|
_users[fd].realname = msg.param(3);
|
||||||
|
_users[fd].userOk = true;
|
||||||
|
if (_users[fd].isRegistered())
|
||||||
|
{
|
||||||
|
sendReply(fd, ":server 001 " + _users[fd].nick + " :Welcome to the IRC server\r\n");
|
||||||
|
sendReply(fd, ":server 002 " + _users[fd].nick + " :Your host is server\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::handlePing(int fd, const IrcMessage &msg)
|
||||||
|
{
|
||||||
|
sendReply(fd, "PONG :" + msg.param(0) + "\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::handleQuit(int fd, const IrcMessage &msg)
|
||||||
|
{
|
||||||
|
removeUser(fd);
|
||||||
|
(void)msg;
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue