Files
MiniChat/Server.cpp
2024-04-09 02:00:23 +00:00

132 lines
3.8 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) {
char buffer[BUFFER_SIZE] = {0};
// Receive the data
ssize_t bytes = recv(fd, buffer, BUFFER_SIZE - 1 , 0);
// Check if the client disconnected
if (bytes <= 0) {
std::cout << "Client <" << fd << "> Disconnected" << std::endl;
// cleanups here
} else {
buffer[bytes] = '\0';
std::cout << "Client <" << fd << "> Data: " << buffer;
// parse, check, and handle the received data here
}
}