first commit
This commit is contained in:
commit
332cb7501a
|
|
@ -0,0 +1,132 @@
|
|||
# ft_irc parsing module
|
||||
|
||||
Partie parsing C++98 pour `ft_irc`.
|
||||
|
||||
## Ce que ça fait
|
||||
|
||||
- accumule les données TCP reçues dans un buffer par client ;
|
||||
- extrait les lignes complètes terminées par `\r\n` ou `\n` ;
|
||||
- parse une ligne IRC en :
|
||||
- prefix optionnel ;
|
||||
- command ;
|
||||
- params ;
|
||||
- trailing param après `:`, qui peut contenir des espaces ;
|
||||
- normalise les commandes en uppercase ;
|
||||
- fournit une validation minimale du nombre de paramètres.
|
||||
|
||||
## Ce que ça ne fait volontairement pas
|
||||
|
||||
Le parser ne doit pas gérer la logique métier :
|
||||
|
||||
- vérifier le password ;
|
||||
- vérifier si le nickname existe déjà ;
|
||||
- créer les channels ;
|
||||
- vérifier les permissions operator ;
|
||||
- appliquer les modes ;
|
||||
- envoyer les numeric replies.
|
||||
|
||||
Tout ça appartient aux handlers de commandes.
|
||||
|
||||
## Utilisation dans ton Client
|
||||
|
||||
Chaque client doit avoir son propre `ParseBuffer`.
|
||||
|
||||
Exemple :
|
||||
|
||||
```cpp
|
||||
// Dans ta classe Client
|
||||
ParseBuffer _parseBuffer;
|
||||
```
|
||||
|
||||
Quand `poll()` indique que le fd client est lisible :
|
||||
|
||||
```cpp
|
||||
char buf[4096];
|
||||
ssize_t n = recv(clientFd, buf, sizeof(buf), 0);
|
||||
|
||||
if (n <= 0)
|
||||
{
|
||||
// déconnexion ou erreur
|
||||
}
|
||||
else
|
||||
{
|
||||
client.getParseBuffer().append(buf, n);
|
||||
|
||||
std::vector<IrcMessage> messages = client.getParseBuffer().extractMessages();
|
||||
|
||||
for (size_t i = 0; i < messages.size(); ++i)
|
||||
{
|
||||
IrcMessage &msg = messages[i];
|
||||
|
||||
if (!msg.isValid())
|
||||
{
|
||||
// selon l'erreur:
|
||||
// - ignorer
|
||||
// - répondre ERR_UNKNOWNCOMMAND
|
||||
// - fermer si line too long
|
||||
continue;
|
||||
}
|
||||
|
||||
// dispatcher.handle(client, msg);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Compilation test
|
||||
|
||||
```bash
|
||||
c++ -Wall -Wextra -Werror -std=c++98 \
|
||||
-Iincludes \
|
||||
srcs/IrcMessage.cpp \
|
||||
srcs/IrcParser.cpp \
|
||||
srcs/ParseBuffer.cpp \
|
||||
srcs/CommandValidator.cpp \
|
||||
test/main.cpp \
|
||||
-o parser_test
|
||||
|
||||
./parser_test
|
||||
```
|
||||
|
||||
## Format IRC géré
|
||||
|
||||
```txt
|
||||
COMMAND param1 param2 :trailing avec espaces
|
||||
```
|
||||
|
||||
Exemples :
|
||||
|
||||
```txt
|
||||
PASS secret
|
||||
NICK jeremy
|
||||
USER jeremy 0 * :Jeremy Real Name
|
||||
JOIN #42
|
||||
PRIVMSG #42 :salut les gars
|
||||
MODE #42 +it
|
||||
MODE #42 +k password
|
||||
KICK #42 bob :raison du kick
|
||||
```
|
||||
|
||||
## Intégration recommandée
|
||||
|
||||
Architecture propre :
|
||||
|
||||
```txt
|
||||
Client
|
||||
- fd
|
||||
- nick
|
||||
- username
|
||||
- ParseBuffer
|
||||
|
||||
Server
|
||||
- poll loop
|
||||
- accept
|
||||
- recv
|
||||
- donne les IrcMessage au dispatcher
|
||||
|
||||
CommandDispatcher
|
||||
- map command -> handler
|
||||
- PASS/NICK/USER/JOIN/PRIVMSG/MODE/etc.
|
||||
|
||||
Parser
|
||||
- aucune logique métier
|
||||
```
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef COMMANDVALIDATOR_HPP
|
||||
# define COMMANDVALIDATOR_HPP
|
||||
|
||||
# include <string>
|
||||
# include "IrcMessage.hpp"
|
||||
|
||||
class CommandValidator
|
||||
{
|
||||
public:
|
||||
CommandValidator(void);
|
||||
CommandValidator(const CommandValidator &other);
|
||||
CommandValidator &operator=(const CommandValidator &other);
|
||||
~CommandValidator(void);
|
||||
|
||||
static bool hasEnoughParams(const IrcMessage &msg);
|
||||
static bool needsRegistration(const std::string &command);
|
||||
static bool isKnownCommand(const std::string &command);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef IRCMESSAGE_HPP
|
||||
# define IRCMESSAGE_HPP
|
||||
|
||||
# include <string>
|
||||
# include <vector>
|
||||
|
||||
class IrcMessage
|
||||
{
|
||||
private:
|
||||
std::string _prefix;
|
||||
std::string _command;
|
||||
std::vector<std::string> _params;
|
||||
std::string _raw;
|
||||
bool _valid;
|
||||
std::string _error;
|
||||
|
||||
public:
|
||||
IrcMessage(void);
|
||||
IrcMessage(const IrcMessage &other);
|
||||
IrcMessage &operator=(const IrcMessage &other);
|
||||
~IrcMessage(void);
|
||||
|
||||
void setPrefix(const std::string &prefix);
|
||||
void setCommand(const std::string &command);
|
||||
void addParam(const std::string ¶m);
|
||||
void setRaw(const std::string &raw);
|
||||
void setValid(bool valid);
|
||||
void setError(const std::string &error);
|
||||
|
||||
const std::string &getPrefix(void) const;
|
||||
const std::string &getCommand(void) const;
|
||||
const std::vector<std::string> &getParams(void) const;
|
||||
const std::string &getRaw(void) const;
|
||||
bool isValid(void) const;
|
||||
const std::string &getError(void) const;
|
||||
|
||||
bool hasPrefix(void) const;
|
||||
bool hasParam(size_t index) const;
|
||||
const std::string ¶m(size_t index) const;
|
||||
size_t paramCount(void) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef IRCPARSER_HPP
|
||||
# define IRCPARSER_HPP
|
||||
|
||||
# include <string>
|
||||
# include <vector>
|
||||
# include "IrcMessage.hpp"
|
||||
|
||||
class IrcParser
|
||||
{
|
||||
private:
|
||||
static std::string trimLeft(const std::string &s);
|
||||
static std::string trimRight(const std::string &s);
|
||||
static std::string toUpper(const std::string &s);
|
||||
static bool isSpace(char c);
|
||||
static bool isCommandChar(char c);
|
||||
static bool isValidCommand(const std::string &command);
|
||||
static void parseParams(const std::string &s, size_t pos, IrcMessage &msg);
|
||||
|
||||
public:
|
||||
IrcParser(void);
|
||||
IrcParser(const IrcParser &other);
|
||||
IrcParser &operator=(const IrcParser &other);
|
||||
~IrcParser(void);
|
||||
|
||||
static IrcMessage parseLine(const std::string &line);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef PARSEBUFFER_HPP
|
||||
# define PARSEBUFFER_HPP
|
||||
|
||||
# include <string>
|
||||
# include <vector>
|
||||
# include "IrcMessage.hpp"
|
||||
|
||||
class ParseBuffer
|
||||
{
|
||||
private:
|
||||
std::string _buffer;
|
||||
size_t _maxLineSize;
|
||||
|
||||
bool extractOneLine(std::string &line);
|
||||
|
||||
public:
|
||||
ParseBuffer(void);
|
||||
explicit ParseBuffer(size_t maxLineSize);
|
||||
ParseBuffer(const ParseBuffer &other);
|
||||
ParseBuffer &operator=(const ParseBuffer &other);
|
||||
~ParseBuffer(void);
|
||||
|
||||
void append(const char *data, size_t len);
|
||||
std::vector<IrcMessage> extractMessages(void);
|
||||
void clear(void);
|
||||
|
||||
const std::string &raw(void) const;
|
||||
size_t size(void) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
#ifndef SERVER_HPP
|
||||
# define SERVER_HPP
|
||||
|
||||
# include <string>
|
||||
# include <vector>
|
||||
# include <map>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <poll.h>
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
# include "ParseBuffer.hpp"
|
||||
# include <stdexcept>
|
||||
# include <cstring>
|
||||
# include <cerrno>
|
||||
|
||||
struct ConnectedUser
|
||||
{
|
||||
int fd;
|
||||
std::string nick;
|
||||
std::string username;
|
||||
std::string realname;
|
||||
std::string hostname;
|
||||
bool passOk;
|
||||
bool nickOk;
|
||||
bool userOk;
|
||||
ParseBuffer parseBuffer;
|
||||
|
||||
explicit ConnectedUser(int fd);
|
||||
bool isRegistered(void) const;
|
||||
};
|
||||
|
||||
class Server
|
||||
{
|
||||
private:
|
||||
int _serverFd;
|
||||
int _port;
|
||||
std::string _password;
|
||||
std::vector<struct pollfd> _fds;
|
||||
std::map<int, ConnectedUser> _users;
|
||||
|
||||
void acceptNew(void);
|
||||
void handleRecv(int fd);
|
||||
void removeUser(int fd);
|
||||
|
||||
public:
|
||||
Server(int port, const std::string &password);
|
||||
Server(const Server &other);
|
||||
Server &operator=(const Server &other);
|
||||
~Server(void);
|
||||
|
||||
void start(void);
|
||||
void run(void);
|
||||
void sendReply(int fd, const std::string &msg);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
#include "CommandValidator.hpp"
|
||||
|
||||
CommandValidator::CommandValidator(void) {}
|
||||
CommandValidator::CommandValidator(const CommandValidator &other) { (void)other; }
|
||||
CommandValidator &CommandValidator::operator=(const CommandValidator &other) { (void)other; return (*this); }
|
||||
CommandValidator::~CommandValidator(void) {}
|
||||
|
||||
bool CommandValidator::isKnownCommand(const std::string &cmd)
|
||||
{
|
||||
return (cmd == "PASS"
|
||||
|| cmd == "NICK"
|
||||
|| cmd == "USER"
|
||||
|| cmd == "JOIN"
|
||||
|| cmd == "PART"
|
||||
|| cmd == "PRIVMSG"
|
||||
|| cmd == "NOTICE"
|
||||
|| cmd == "QUIT"
|
||||
|| cmd == "PING"
|
||||
|| cmd == "PONG"
|
||||
|| cmd == "KICK"
|
||||
|| cmd == "INVITE"
|
||||
|| cmd == "TOPIC"
|
||||
|| cmd == "MODE");
|
||||
}
|
||||
|
||||
/*
|
||||
This is only syntactic/minimal validation.
|
||||
The real command handler still checks:
|
||||
- password correctness
|
||||
- nickname already used
|
||||
- channel exists
|
||||
- permissions/operator status
|
||||
- invite-only/key/limit modes
|
||||
*/
|
||||
bool CommandValidator::hasEnoughParams(const IrcMessage &msg)
|
||||
{
|
||||
const std::string &cmd = msg.getCommand();
|
||||
|
||||
if (cmd == "PASS") return (msg.paramCount() >= 1);
|
||||
if (cmd == "NICK") return (msg.paramCount() >= 1);
|
||||
if (cmd == "USER") return (msg.paramCount() >= 4);
|
||||
if (cmd == "JOIN") return (msg.paramCount() >= 1);
|
||||
if (cmd == "PART") return (msg.paramCount() >= 1);
|
||||
if (cmd == "PRIVMSG") return (msg.paramCount() >= 2);
|
||||
if (cmd == "NOTICE") return (msg.paramCount() >= 2);
|
||||
if (cmd == "QUIT") return (true);
|
||||
if (cmd == "PING") return (msg.paramCount() >= 1);
|
||||
if (cmd == "PONG") return (msg.paramCount() >= 1);
|
||||
if (cmd == "KICK") return (msg.paramCount() >= 2);
|
||||
if (cmd == "INVITE") return (msg.paramCount() >= 2);
|
||||
if (cmd == "TOPIC") return (msg.paramCount() >= 1);
|
||||
if (cmd == "MODE") return (msg.paramCount() >= 1);
|
||||
return (false);
|
||||
}
|
||||
|
||||
/*
|
||||
Before registration, usually only PASS, NICK, USER, PING/PONG/QUIT are useful.
|
||||
*/
|
||||
bool CommandValidator::needsRegistration(const std::string &cmd)
|
||||
{
|
||||
return !(cmd == "PASS"
|
||||
|| cmd == "NICK"
|
||||
|| cmd == "USER"
|
||||
|| cmd == "PING"
|
||||
|| cmd == "PONG"
|
||||
|| cmd == "QUIT");
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
#include "IrcMessage.hpp"
|
||||
|
||||
IrcMessage::IrcMessage(void) : _valid(false)
|
||||
{
|
||||
}
|
||||
|
||||
IrcMessage::IrcMessage(const IrcMessage &other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
IrcMessage &IrcMessage::operator=(const IrcMessage &other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
_prefix = other._prefix;
|
||||
_command = other._command;
|
||||
_params = other._params;
|
||||
_raw = other._raw;
|
||||
_valid = other._valid;
|
||||
_error = other._error;
|
||||
}
|
||||
return (*this);
|
||||
}
|
||||
|
||||
IrcMessage::~IrcMessage(void)
|
||||
{
|
||||
}
|
||||
|
||||
void IrcMessage::setPrefix(const std::string &prefix) { _prefix = prefix; }
|
||||
void IrcMessage::setCommand(const std::string &command) { _command = command; }
|
||||
void IrcMessage::addParam(const std::string ¶m) { _params.push_back(param); }
|
||||
void IrcMessage::setRaw(const std::string &raw) { _raw = raw; }
|
||||
void IrcMessage::setValid(bool valid) { _valid = valid; }
|
||||
void IrcMessage::setError(const std::string &error) { _error = error; }
|
||||
|
||||
const std::string &IrcMessage::getPrefix(void) const { return (_prefix); }
|
||||
const std::string &IrcMessage::getCommand(void) const { return (_command); }
|
||||
const std::vector<std::string> &IrcMessage::getParams(void) const { return (_params); }
|
||||
const std::string &IrcMessage::getRaw(void) const { return (_raw); }
|
||||
bool IrcMessage::isValid(void) const { return (_valid); }
|
||||
const std::string &IrcMessage::getError(void) const { return (_error); }
|
||||
|
||||
bool IrcMessage::hasPrefix(void) const
|
||||
{
|
||||
return (!_prefix.empty());
|
||||
}
|
||||
|
||||
bool IrcMessage::hasParam(size_t index) const
|
||||
{
|
||||
return (index < _params.size());
|
||||
}
|
||||
|
||||
const std::string &IrcMessage::param(size_t index) const
|
||||
{
|
||||
return (_params[index]);
|
||||
}
|
||||
|
||||
size_t IrcMessage::paramCount(void) const
|
||||
{
|
||||
return (_params.size());
|
||||
}
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
#include "IrcParser.hpp"
|
||||
#include <cctype>
|
||||
|
||||
IrcParser::IrcParser(void) {}
|
||||
IrcParser::IrcParser(const IrcParser &other) { (void)other; }
|
||||
IrcParser &IrcParser::operator=(const IrcParser &other) { (void)other; return (*this); }
|
||||
IrcParser::~IrcParser(void) {}
|
||||
|
||||
bool IrcParser::isSpace(char c)
|
||||
{
|
||||
return (c == ' ' || c == '\t');
|
||||
}
|
||||
|
||||
std::string IrcParser::trimLeft(const std::string &s)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
while (i < s.size() && isSpace(s[i]))
|
||||
i++;
|
||||
return (s.substr(i));
|
||||
}
|
||||
|
||||
std::string IrcParser::trimRight(const std::string &s)
|
||||
{
|
||||
size_t end = s.size();
|
||||
|
||||
while (end > 0 && (s[end - 1] == '\r' || s[end - 1] == '\n' || isSpace(s[end - 1])))
|
||||
end--;
|
||||
return (s.substr(0, end));
|
||||
}
|
||||
|
||||
std::string IrcParser::toUpper(const std::string &s)
|
||||
{
|
||||
std::string out = s;
|
||||
|
||||
for (size_t i = 0; i < out.size(); ++i)
|
||||
out[i] = static_cast<char>(std::toupper(static_cast<unsigned char>(out[i])));
|
||||
return (out);
|
||||
}
|
||||
|
||||
bool IrcParser::isCommandChar(char c)
|
||||
{
|
||||
return (std::isalpha(static_cast<unsigned char>(c)) || std::isdigit(static_cast<unsigned char>(c)));
|
||||
}
|
||||
|
||||
bool IrcParser::isValidCommand(const std::string &command)
|
||||
{
|
||||
if (command.empty())
|
||||
return (false);
|
||||
for (size_t i = 0; i < command.size(); ++i)
|
||||
{
|
||||
if (!isCommandChar(command[i]))
|
||||
return (false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
/*
|
||||
IRC params rule:
|
||||
- parameters are separated by spaces
|
||||
- if a parameter starts with ':', it is the trailing parameter
|
||||
- the trailing parameter may contain spaces and is always the last param
|
||||
|
||||
Example:
|
||||
PRIVMSG #chan :hello les gars
|
||||
params[0] = "#chan"
|
||||
params[1] = "hello les gars"
|
||||
*/
|
||||
void IrcParser::parseParams(const std::string &s, size_t pos, IrcMessage &msg)
|
||||
{
|
||||
while (pos < s.size())
|
||||
{
|
||||
while (pos < s.size() && isSpace(s[pos]))
|
||||
pos++;
|
||||
if (pos >= s.size())
|
||||
break;
|
||||
|
||||
if (s[pos] == ':')
|
||||
{
|
||||
msg.addParam(s.substr(pos + 1));
|
||||
break;
|
||||
}
|
||||
|
||||
size_t start = pos;
|
||||
while (pos < s.size() && !isSpace(s[pos]))
|
||||
pos++;
|
||||
msg.addParam(s.substr(start, pos - start));
|
||||
}
|
||||
}
|
||||
|
||||
IrcMessage IrcParser::parseLine(const std::string &line)
|
||||
{
|
||||
IrcMessage msg;
|
||||
std::string s;
|
||||
size_t pos;
|
||||
size_t start;
|
||||
|
||||
msg.setRaw(line);
|
||||
s = trimRight(trimLeft(line));
|
||||
|
||||
if (s.empty())
|
||||
{
|
||||
msg.setError("empty line");
|
||||
return (msg);
|
||||
}
|
||||
|
||||
/*
|
||||
Optional prefix:
|
||||
:nick!user@host COMMAND params...
|
||||
In ft_irc, clients usually do not send prefixes, but accepting it makes the parser robust.
|
||||
*/
|
||||
pos = 0;
|
||||
if (s[pos] == ':')
|
||||
{
|
||||
size_t prefixEnd = s.find(' ', pos);
|
||||
if (prefixEnd == std::string::npos)
|
||||
{
|
||||
msg.setError("prefix without command");
|
||||
return (msg);
|
||||
}
|
||||
msg.setPrefix(s.substr(1, prefixEnd - 1));
|
||||
pos = prefixEnd + 1;
|
||||
while (pos < s.size() && isSpace(s[pos]))
|
||||
pos++;
|
||||
}
|
||||
|
||||
start = pos;
|
||||
while (pos < s.size() && !isSpace(s[pos]))
|
||||
pos++;
|
||||
|
||||
msg.setCommand(toUpper(s.substr(start, pos - start)));
|
||||
|
||||
if (!isValidCommand(msg.getCommand()))
|
||||
{
|
||||
msg.setError("invalid command");
|
||||
return (msg);
|
||||
}
|
||||
|
||||
parseParams(s, pos, msg);
|
||||
msg.setValid(true);
|
||||
return (msg);
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
#include "ParseBuffer.hpp"
|
||||
#include "IrcParser.hpp"
|
||||
|
||||
ParseBuffer::ParseBuffer(void) : _maxLineSize(512)
|
||||
{
|
||||
}
|
||||
|
||||
ParseBuffer::ParseBuffer(size_t maxLineSize) : _maxLineSize(maxLineSize)
|
||||
{
|
||||
}
|
||||
|
||||
ParseBuffer::ParseBuffer(const ParseBuffer &other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
ParseBuffer &ParseBuffer::operator=(const ParseBuffer &other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
_buffer = other._buffer;
|
||||
_maxLineSize = other._maxLineSize;
|
||||
}
|
||||
return (*this);
|
||||
}
|
||||
|
||||
ParseBuffer::~ParseBuffer(void)
|
||||
{
|
||||
}
|
||||
|
||||
void ParseBuffer::append(const char *data, size_t len)
|
||||
{
|
||||
if (data && len > 0)
|
||||
_buffer.append(data, len);
|
||||
}
|
||||
|
||||
/*
|
||||
Extract lines terminated by:
|
||||
- "\r\n" standard IRC
|
||||
- "\n" useful for netcat/manual tests
|
||||
|
||||
The returned line does not include CRLF/LF.
|
||||
*/
|
||||
bool ParseBuffer::extractOneLine(std::string &line)
|
||||
{
|
||||
size_t lf = _buffer.find('\n');
|
||||
|
||||
if (lf == std::string::npos)
|
||||
return (false);
|
||||
|
||||
line = _buffer.substr(0, lf);
|
||||
if (!line.empty() && line[line.size() - 1] == '\r')
|
||||
line.erase(line.size() - 1);
|
||||
|
||||
_buffer.erase(0, lf + 1);
|
||||
return (true);
|
||||
}
|
||||
|
||||
std::vector<IrcMessage> ParseBuffer::extractMessages(void)
|
||||
{
|
||||
std::vector<IrcMessage> messages;
|
||||
std::string line;
|
||||
|
||||
while (extractOneLine(line))
|
||||
{
|
||||
IrcMessage msg;
|
||||
|
||||
if (line.size() + 2 > _maxLineSize)
|
||||
{
|
||||
msg.setRaw(line);
|
||||
msg.setError("line too long");
|
||||
msg.setValid(false);
|
||||
}
|
||||
else
|
||||
msg = IrcParser::parseLine(line);
|
||||
messages.push_back(msg);
|
||||
}
|
||||
return (messages);
|
||||
}
|
||||
|
||||
void ParseBuffer::clear(void)
|
||||
{
|
||||
_buffer.clear();
|
||||
}
|
||||
|
||||
const std::string &ParseBuffer::raw(void) const
|
||||
{
|
||||
return (_buffer);
|
||||
}
|
||||
|
||||
size_t ParseBuffer::size(void) const
|
||||
{
|
||||
return (_buffer.size());
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#include "Server.hpp"
|
||||
|
||||
void Server::start(void)
|
||||
{
|
||||
_serverFd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (_serverFd == -1)
|
||||
throw std::runtime_error(strerror(errno));
|
||||
int opt = 1;
|
||||
if (setsockopt(_serverFd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1)
|
||||
{
|
||||
close(_serverFd);
|
||||
throw std::runtime_error(strerror(errno));
|
||||
}
|
||||
if (fcntl(_serverFd, F_SETFL, O_NONBLOCK) == -1)
|
||||
{
|
||||
close(_serverFd);
|
||||
throw std::runtime_error(strerror(errno));
|
||||
}
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(_port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
if (bind(_serverFd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
|
||||
{
|
||||
close(_serverFd);
|
||||
throw std::runtime_error(strerror(errno));
|
||||
}
|
||||
if (listen(_serverFd, SOMAXCONN) == -1)
|
||||
{
|
||||
close(_serverFd);
|
||||
throw std::runtime_error(strerror(errno));
|
||||
}
|
||||
struct pollfd pollfd;
|
||||
pollfd.fd = _serverFd;
|
||||
pollfd.events = POLLIN;
|
||||
pollfd.revents = 0;
|
||||
_fds.push_back(pollfd);
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "ParseBuffer.hpp"
|
||||
#include "CommandValidator.hpp"
|
||||
|
||||
static void printMessage(const IrcMessage &msg)
|
||||
{
|
||||
std::cout << "raw=[" << msg.getRaw() << "]\n";
|
||||
std::cout << "valid=" << (msg.isValid() ? "yes" : "no") << "\n";
|
||||
if (!msg.getError().empty())
|
||||
std::cout << "error=" << msg.getError() << "\n";
|
||||
if (msg.hasPrefix())
|
||||
std::cout << "prefix=" << msg.getPrefix() << "\n";
|
||||
std::cout << "command=" << msg.getCommand() << "\n";
|
||||
for (size_t i = 0; i < msg.paramCount(); ++i)
|
||||
std::cout << "param[" << i << "]=[" << msg.param(i) << "]\n";
|
||||
std::cout << "known=" << (CommandValidator::isKnownCommand(msg.getCommand()) ? "yes" : "no") << "\n";
|
||||
std::cout << "enough_params=" << (CommandValidator::hasEnoughParams(msg) ? "yes" : "no") << "\n";
|
||||
std::cout << "-----\n";
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ParseBuffer buffer;
|
||||
std::string chunk1 = "PASS secret\r\nNICK je";
|
||||
std::string chunk2 = "remy\r\nUSER jeremy 0 * :Jeremy Real Name\r\n";
|
||||
std::string chunk3 = "JOIN #42\r\nPRIVMSG #42 :salut les gars ca va ?\r\n";
|
||||
std::string chunk4 = ":nick!user@host PRIVMSG jeremy :hello from prefixed line\r\n";
|
||||
|
||||
buffer.append(chunk1.c_str(), chunk1.size());
|
||||
std::vector<IrcMessage> messages = buffer.extractMessages();
|
||||
for (size_t i = 0; i < messages.size(); ++i)
|
||||
printMessage(messages[i]);
|
||||
|
||||
buffer.append(chunk2.c_str(), chunk2.size());
|
||||
messages = buffer.extractMessages();
|
||||
for (size_t i = 0; i < messages.size(); ++i)
|
||||
printMessage(messages[i]);
|
||||
|
||||
buffer.append(chunk3.c_str(), chunk3.size());
|
||||
buffer.append(chunk4.c_str(), chunk4.size());
|
||||
messages = buffer.extractMessages();
|
||||
for (size_t i = 0; i < messages.size(); ++i)
|
||||
printMessage(messages[i]);
|
||||
|
||||
return (0);
|
||||
}
|
||||
Loading…
Reference in New Issue