22#include <netinet/in.h>
26#include <sys/socket.h>
35#define PING_TIMEOUT 120
36#define PONG_TIMEOUT 20
40Server *Server::_instance = NULL;
50 _clients[client->
getFd()] = client;
54 pfd.fd = client->
getFd();
64 if (_instance == NULL) {
65 _instance =
new Server(port, password);
71Server::Server(
int port,
const std::string &password)
72 : _port(port), _password(password), _server_fd(-1), _serverName(
"irc.myserver.com") {
78 delete _commandManager;
94 if (_server_fd != -1) {
107void Server::setupSocket() {
109 _server_fd = socket(AF_INET, SOCK_STREAM, 0);
110 if (_server_fd < 0) {
116 if (setsockopt(_server_fd, SOL_SOCKET, SO_REUSEADDR, &opt,
sizeof(opt)) < 0) {
121 if (fcntl(_server_fd, F_SETFL, O_NONBLOCK) < 0) {
126 struct sockaddr_in server_addr;
127 server_addr.sin_family = AF_INET;
128 server_addr.sin_addr.s_addr = INADDR_ANY;
129 server_addr.sin_port = htons(_port);
132 if (
bind(_server_fd, (
struct sockaddr *)&server_addr,
sizeof(server_addr)) < 0) {
137 if (listen(_server_fd, 10) < 0) {
152void Server::mainLoop() {
155 for (
size_t i = 0; i < _pollfds.
size(); ++i) {
156 if (_pollfds[i].fd == _server_fd) {
163 if (it != _clients.
end()) {
164 Client *client = it->second;
166 _pollfds[i].events |= POLLOUT;
168 _pollfds[i].events &= ~POLLOUT;
173 _pollfds[i].events &= ~POLLOUT;
178 int poll_count = poll(&_pollfds[0], _pollfds.
size(), 1000);
185 for (
size_t i = 0; i < _pollfds.
size(); ++i) {
186 if (_pollfds[i].revents == 0) {
191 if (_pollfds[i].revents & (POLLHUP | POLLERR)) {
198 if (_pollfds[i].revents & POLLOUT) {
199 handleClientWrite(_pollfds[i].fd);
200 if (_clients.
count(_pollfds[i].fd) && _clients[_pollfds[i].fd]->isMarkedForDisconnect()) {
208 if (_pollfds[i].revents & POLLIN) {
209 if (_pollfds[i].fd == _server_fd) {
212 handleClientData(_pollfds[i].fd);
213 if (_clients.
count(_pollfds[i].fd) && _clients[_pollfds[i].fd]->isMarkedForDisconnect()) {
221 checkClientTimeouts();
226void Server::checkClientTimeouts() {
231 Client *client = it->second;
256 for (
size_t i = 0; i < clientsToDisconnect.
size(); ++i) {
264 struct sockaddr_in client_addr;
265 socklen_t client_len =
sizeof(client_addr);
266 int client_fd = accept(_server_fd, (
struct sockaddr *)&client_addr, &client_len);
273 fcntl(client_fd, F_SETFL, O_NONBLOCK);
283 std::string hostname = inet_ntoa(client_addr.sin_addr);
284 _clients[client_fd] =
new Client(client_fd, hostname);
286 std::cout <<
"New connection from " << hostname <<
" on fd " << client_fd <<
std::endl;
293 if (it != _clients.
end()) {
294 Client *client = it->second;
296 <<
" (fd: " << fd <<
") disconnected." <<
std::endl;
300 for (
size_t i = 0; i < channels.size(); ++i) {
301 channels[i]->removeMember(client);
309 for (
size_t i = 0; i < _pollfds.
size(); ++i) {
310 if (_pollfds[i].fd == fd) {
320void Server::handleClientData(
int fd) {
322 ssize_t bytes_read = recv(fd, buffer,
sizeof(buffer) - 1, 0);
324 if (bytes_read <= 0) {
329 buffer[bytes_read] =
'\0';
347void Server::handleClientWrite(
int fd) {
354 if (sendBuffer.
empty()) {
358 ssize_t bytes_sent = send(fd, sendBuffer.
c_str(), sendBuffer.
length(), 0);
360 if (bytes_sent < 0) {
361 if (errno == EWOULDBLOCK || errno == EAGAIN) {
369 }
else if (bytes_sent > 0) {
372 std::cerr <<
"Sent " << bytes_sent <<
" bytes to fd " << fd
385 if (it != _clients.
end()) {
393 if (it->second->getNickname() == nickname) {
402 _channels[channel->
getName()] = channel;
408 if (it != _channels.
end()) {
416 if (it != _channels.
end()) {
Manages channel members and states.
Manages client connection and state.
Manages IRC commands and their execution.
Defines IRC numeric replies and error messages.
Core IRC server implementation.
#define UNREGISTERED_CLIENT_TIMEOUT
const std::string & getName() const
Represents an IRC client connected to the server.
const std::string & getSendBuffer() const
Gets the client's send buffer content.
bool isRegistered() const
Checks if the client is registered.
const std::vector< Channel * > & getChannels() const
Gets the list of channels the client is in.
void updateActivityTime()
Updates the client's last activity time to the current time.
std::time_t getLastActivityTime() const
Gets the timestamp of the client's last activity.
void appendBuffer(const std::string &data)
Appends data to the client's receive buffer.
virtual void sendMessage(const std::string &message) const
Sends a message to the client by appending it to the send buffer.
const std::string & getNickname() const
Gets the client's nickname.
void setLastPingSentTime(std::time_t time)
Sets the timestamp of the last PING sent to the client.
std::time_t getLastPingSentTime() const
Gets the timestamp of the last PING sent to the client.
void markForDisconnect(const std::string &message)
Marks the client for disconnection with a specified message.
std::string readLineFromBuffer()
Reads a single line from the receive buffer.
int getFd() const
Gets the client's file descriptor.
void removeSentData(size_t bytes_sent)
Removes a specified number of bytes from the beginning of the send buffer.
Manages the registration, parsing, and execution of IRC commands.
void parseAndExecute(Client *client, const std::string &rawMessage)
Parses a raw message and executes the corresponding command.
Implements the core IRC server functionality as a Singleton.
Channel * getChannel(const std::string &name)
Retrieves a Channel object by its name.
Client * getClientByNickname(const std::string &nickname)
Retrieves a Client object by its nickname.
const std::map< int, Client * > & getClients() const
Gets a constant reference to the map of clients managed by the server.
const std::map< std::string, Channel * > & getChannels() const
Gets a constant reference to the map of channels managed by the server.
~Server()
Destroys the Server object, cleaning up all clients, channels, and the command manager.
static Server * getInstance(int port=-1, const std::string &password="")
Gets the single instance of the Server (Singleton pattern).
void removeChannel(const std::string &name)
Removes a channel from the server, deleting the Channel object.
const std::string & getPassword() const
Gets the server's password.
void removeClient(int fd)
Removes a client from the server, closing its socket and freeing resources.
void acceptNewClient()
Accepts a new incoming client connection.
const std::string & getServerName() const
Gets the server's name.
void addChannel(Channel *channel)
Adds a new channel to the server.
void addTestClient(Client *client)
Adds a client directly to the server's management for testing purposes.
static void resetInstance()
Resets the singleton instance of the Server for testing purposes.
Client * getClient(int fd)
Retrieves a Client object by its file descriptor.
void run()
Starts the IRC server, setting up the socket and entering the main event loop.