166 lines
4.7 KiB
C++
166 lines
4.7 KiB
C++
#include "Server.hpp"
|
|
|
|
bool Server::_signal = false;
|
|
|
|
Server::Server() {}
|
|
|
|
Server::~Server() {}
|
|
|
|
void Server::parseArgs(int ac, char **av) {
|
|
if (ac != 3)
|
|
throw std::runtime_error("Usage: ./ircserv <port> <password>");
|
|
std::string port(av[1]);
|
|
std::string pwd(av[2]);
|
|
if (port.empty() || port.find_first_not_of("0123456789") != std::string::npos)
|
|
throw std::runtime_error("Error: Invalid arguments");
|
|
|
|
long _port = atol(av[1]);
|
|
if (!(_port >= 1 && _port <= 65535))
|
|
throw std::runtime_error("Error: Invalid arguments");
|
|
|
|
if (pwd.empty())
|
|
throw std::runtime_error("Error: Invalid arguments");
|
|
|
|
this->_port = _port;
|
|
this->_password = pwd;
|
|
}
|
|
|
|
void Server::receiveSignal(int signum) {
|
|
_signal = true;
|
|
(void)signum;
|
|
}
|
|
|
|
void Server::init() {
|
|
signal(SIGINT, receiveSignal);
|
|
signal(SIGQUIT, receiveSignal);
|
|
|
|
createServerSocket();
|
|
std::cout << ">>> SERVER STARTED <<<" << std::endl;
|
|
std::cout << "Waiting for connections..." << std::endl;
|
|
}
|
|
|
|
void Server::run() {
|
|
while (!_signal) {
|
|
int ret = poll(&_fds[0], _fds.size(), -1);
|
|
if (ret == -1)
|
|
throw std::runtime_error("Error: poll() failed");
|
|
|
|
for (size_t i = 0; i < _fds.size(); ++i) {
|
|
if (_fds[i].revents & POLLIN) {
|
|
if (_fds[i].fd == _serverSocketFd)
|
|
handleClientConnection();
|
|
else
|
|
handleClientData(_fds[i].fd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Server::createServerSocket() {
|
|
_serverSocketFd = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (_serverSocketFd == -1)
|
|
throw std::runtime_error("Error: failed to create socket");
|
|
|
|
int optval = 1;
|
|
if (setsockopt(_serverSocketFd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1)
|
|
throw std::runtime_error("Error: setsockopt() failed");
|
|
|
|
if (fcntl(_serverSocketFd, F_SETFL, O_NONBLOCK) == -1)
|
|
throw std::runtime_error("Error: fcntl() failed");
|
|
|
|
bindServerSocket();
|
|
|
|
if (listen(_serverSocketFd, SOMAXCONN) == -1)
|
|
throw std::runtime_error("Error: listen() failed");
|
|
|
|
addPollfd(_serverSocketFd, POLLIN, 0);
|
|
}
|
|
|
|
void Server::bindServerSocket() {
|
|
struct sockaddr_in sa;
|
|
sa.sin_family = AF_INET;
|
|
sa.sin_port = htons(_port);
|
|
sa.sin_addr.s_addr = INADDR_ANY;
|
|
if (bind(_serverSocketFd, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
|
|
throw std::runtime_error("Error: failed to bind socket");
|
|
}
|
|
}
|
|
|
|
void Server::addPollfd(int fd, short events, short revents) {
|
|
struct pollfd newPollfd;
|
|
newPollfd.fd = fd;
|
|
newPollfd.events = events;
|
|
newPollfd.revents = revents;
|
|
_fds.push_back(newPollfd);
|
|
}
|
|
|
|
void Server::handleClientConnection() {
|
|
for (size_t i = 0; i < _fds.size(); ++i) {
|
|
if (_fds[i].fd == _serverSocketFd && (_fds[i].revents & POLLIN)) {
|
|
struct sockaddr_in client_addr;
|
|
socklen_t clientAddrSize = sizeof(sockaddr_in);
|
|
int newFd = accept(_serverSocketFd, (struct sockaddr *)&client_addr, &clientAddrSize);
|
|
if (newFd == -1) {
|
|
throw std::runtime_error("Error: accept() failed");
|
|
}
|
|
|
|
addPollfd(newFd, POLLIN, 0);
|
|
_clients.push_back(Client(newFd, inet_ntoa((client_addr.sin_addr))));
|
|
|
|
std::cout << "Client <" << newFd << "> Connected" << std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Server::handleClientData(int fd) {
|
|
std::string command;
|
|
char buffer[BUFFER_SIZE];
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
|
ssize_t bytesRead;
|
|
while ((bytesRead = recv(fd, buffer, BUFFER_SIZE - 1, 0)) > 0) {
|
|
bool foundEof = false;
|
|
for (ssize_t i = 0; i < bytesRead; ++i) {
|
|
if (buffer[i] == '\n') {
|
|
foundEof = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!foundEof) {
|
|
buffer[bytesRead] = '\0';
|
|
command += buffer;
|
|
} else {
|
|
command.append(buffer, bytesRead - 1);
|
|
std::cout << "Received data from client " << fd << ": " << command << std::endl;
|
|
// process the command here
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bytesRead == 0) {
|
|
std::cout << "Client <" << fd << "> Disconnected" << std::endl;
|
|
clientCleanup(fd);
|
|
} else if (bytesRead == -1) {
|
|
std::cerr << "Error reading data from client <" << fd << ">" << std::endl;
|
|
clientCleanup(fd);
|
|
}
|
|
}
|
|
|
|
void Server::clientCleanup(int fd) {
|
|
for (std::vector<pollfd>::iterator it = _fds.begin(); it != _fds.end(); ++it) {
|
|
if (it->fd == fd) {
|
|
_fds.erase(it);
|
|
close(fd);
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (std::vector<Client>::iterator it = _clients.begin(); it != _clients.end(); ++it) {
|
|
if (it->getFd() == fd) {
|
|
_clients.erase(it);
|
|
break;
|
|
}
|
|
}
|
|
}
|