diff --git a/Makefile b/Makefile index 13e0961..71b7055 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ NAME = ircserv SRC = main.cpp Server/Server.cpp User/User.cpp -HEADERS = Server/Server.hpp +HEADERS = Server/Server.hpp User/User.hpp OBJ = $(SRC:.cpp=.o) diff --git a/Server/Server.cpp b/Server/Server.cpp index 9f982cb..4609f3e 100644 --- a/Server/Server.cpp +++ b/Server/Server.cpp @@ -6,19 +6,66 @@ /* By: iherman- +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include + const int Server::kConnectionQueueLimit = 10; Server::Server() : port_(PORT_DEFAULT), - password_("") + password_("password") { - // std::cout << "Hello from server" << std::endl; + serverSocket_ = socket(AF_INET, SOCK_STREAM, 0); + if (serverSocket_ < 0) + throw std::runtime_error("Failed to create socket"); + + struct sockaddr_in addr; + std::memset(&addr, 0, sizeof(addr)); + + addr.sin_family = AF_INET; + addr.sin_port = htons(port_); + addr.sin_addr.s_addr = INADDR_ANY; + + if (bind(serverSocket_, (struct sockaddr*)&addr, sizeof(addr))) + throw std::runtime_error("Failed to bind"); + + if (listen(serverSocket_, kConnectionQueueLimit)) + throw std::runtime_error("Failed to listen"); + + std::cout << "Server port: " << port_ + << "\nServer Password: " << password_ + << std::endl; +} + +Server::Server(const Server& other) +{ + port_ = other.port_; + serverSocket_ = other.serverSocket_; + password_ = other.password_; + sockets_ = other.sockets_; } Server::Server(int port, const std::string& password) : @@ -55,6 +102,9 @@ Server::Server(int port, const std::string& password) : Server::~Server() { + for (std::map::iterator it = clients_.begin(); it != clients_.end(); ++it) + close(it->first); + close(serverSocket_); } @@ -65,35 +115,129 @@ Server &Server::operator=(const Server& other) port_ = other.port_; serverSocket_ = other.serverSocket_; password_ = other.password_; + sockets_ = other.sockets_; } return *this; } -void Server::run() +bool Server::handleClient(User& client) { const std::size_t kBufferSize = 1024; char buffer[kBufferSize] = {0}; - struct sockaddr_in client_addr; - socklen_t client_addr_size = sizeof(client_addr); - int clientSocket = accept(serverSocket_, (struct sockaddr*)&client_addr, &client_addr_size); - - std::string message; - while (true) - { - int recv_amount = recv(clientSocket, buffer, kBufferSize, 0); + int recv_amount = recv(client.getFd(), buffer, kBufferSize, 0); - if (recv_amount <= 0) - break ; + if (recv_amount == 0) + return true; - message.append(buffer, recv_amount); - - if (message.find('\n') != std::string::npos) - break ; + if (recv_amount < 0) + { + if (errno == EAGAIN || errno == EWOULDBLOCK) + return false; + return true; } - message = "Server received: " + message; - send(clientSocket, message.c_str(), message.size(), 0); - close(clientSocket); -} \ No newline at end of file + client.appendBuffer(std::string(buffer, recv_amount)); + + if (client.getBuffer().find('\n') != std::string::npos) + { + std::string message = "Server received: " + client.getBuffer(); + send(client.getFd(), message.c_str(), message.size(), 0); + client.clearBuffer(); + } + + return false; +} + +static struct pollfd newPollfd(int fd) +{ + pollfd pfd; + + pfd.fd = fd; + pfd.events = POLLIN; + pfd.revents = 0; + return pfd; +} + +void Server::addClient() +{ + int newClientSocket = accept(serverSocket_, NULL, NULL); + + if (newClientSocket == -1) + { + // Not sure if program should terminate + std::cerr << "Problem occured accepting client" << std::endl; + return ; + } + + fcntl(newClientSocket, F_SETFL, O_NONBLOCK); + sockets_.push_back(newPollfd(newClientSocket)); + clients_[newClientSocket] = User(newClientSocket); + std::cout << "Client with fd: " << newClientSocket << " connected" << std::endl; +} + +void Server::run() +{ + // add serverSocket_ to sockets_ + sockets_.push_back(newPollfd(serverSocket_)); + + while (true) + { + int ret = poll(sockets_.data(), sockets_.size(), -1); + + if (ret <= 0) + { + // not sure if program should terminate + std::cerr << "Poll failed" << std::endl; + continue ; + } + + for (std::vector::iterator it = sockets_.begin(); it != sockets_.end(); ) + { + if (it->revents & (POLLERR | POLLHUP | POLLNVAL)) + { + // remove client + } + + if (!(it->revents & POLLIN)) + { + it++; + continue ; + } + + std::cout << "Checking client with fd: " << it->fd << std::endl; + + // check if listening port is open, if so add client + if (it->fd == serverSocket_) + { + addClient(); + it++; + break ; + } + + // call handleClient for each other socket + std::map::iterator clientIt = clients_.find(it->fd); + if (clientIt == clients_.end()) + { + std::cerr << "Unknown fd in poll list: " << it->fd << std::endl; + close(it->fd); + it = sockets_.erase(it); + continue; + } + + bool disconnected = handleClient(clientIt->second); + + if (disconnected) + { + close(it->fd); + std::cout << "Client with fd: " << it->fd << " disconnected " << std::endl; + + clients_.erase(it->fd); + it = sockets_.erase(it); + } + else + it++; + } + } +} diff --git a/Server/Server.hpp b/Server/Server.hpp index 05760c6..2b9000b 100644 --- a/Server/Server.hpp +++ b/Server/Server.hpp @@ -6,7 +6,7 @@ /* By: iherman- -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include // C++ lib functions # include @@ -38,25 +22,39 @@ # include # include +# include +# include + +# include "../User/User.hpp" + # define PORT_DEFAULT 9898 class Server { private: static const int kConnectionQueueLimit; - + int port_; int serverSocket_; std::string password_; + std::vector sockets_; + std::map clients_; + + bool handleClient(User& client); + + void addClient(); + std::vector::iterator removeClient(std::vector::iterator client); + + Server(const Server& other); + Server &operator=(const Server& other); + public: Server(); Server(int port, const std::string& password); ~Server(); - Server &operator=(const Server& other); - void run(); }; diff --git a/User/User.cpp b/User/User.cpp index 983025e..9040d43 100644 --- a/User/User.cpp +++ b/User/User.cpp @@ -18,7 +18,7 @@ User::User() : fd(-1), nick(""), username(""), realname(""), buffer(""), authenticated(false), registered(false) { - // std::cout << "User default constructor called" << std::endl; + // std::cout << "User default constructor called" << std::endl; } User::User(int fd) : fd(fd), nick(""), username(""), realname(""), buffer(""), authenticated(false), registered(false) @@ -28,8 +28,8 @@ User::User(int fd) : fd(fd), nick(""), username(""), realname(""), buffer(""), a User::User(const User &other) { - *this = other; - // std::cout << "User copy constructor called" << std::endl; + *this = other; + // std::cout << "User copy constructor called" << std::endl; } User& User::operator=(const User &other) @@ -55,22 +55,23 @@ User::~User() // Getters -int User::getFd() const { return (this->fd); }; -std::string User::getNick() const { return (this->nick); }; -std::string User::getUsername() const { return (this->username); }; -std::string User::getRealname() const { return (this->realname); }; -std::string &User::getBuffer() { return (this->buffer); }; -bool User::isAuthenticated() const { return (this->authenticated); }; -bool User::isRegistered() const { return (this->registered); }; +int User::getFd() const { return (this->fd); } +std::string User::getNick() const { return (this->nick); } +std::string User::getUsername() const { return (this->username); } +std::string User::getRealname() const { return (this->realname); } +std::string &User::getBuffer() { return (this->buffer); } +bool User::isAuthenticated() const { return (this->authenticated); } +bool User::isRegistered() const { return (this->registered); } // Setters -void User::setNick(std::string nick) { this->nick = nick; } -void User::setUsername(std::string username) { this->username = username; } -void User::setRealname(std::string realname) { this->realname = realname; } -void User::appendBuffer(std::string buff) { this->buffer = buff; } -void User::clearBuffer() { this->buffer.clear(); } +void User::appendBuffer(std::string buff) { this->buffer.append(buff); } +void User::clearBuffer() { this->buffer.clear(); } -void User::setAuthenticated(bool value) { this->authenticated = value; } -void User::setRegistered(bool value) { this->registered = value; } \ No newline at end of file +void User::setNick(std::string nick) { this->nick = nick; } +void User::setUsername(std::string username) { this->username = username; } +void User::setRealname(std::string realname) { this->realname = realname; } + +void User::setAuthenticated(bool value) { this->authenticated = value; } +void User::setRegistered(bool value) { this->registered = value; } diff --git a/main.cpp b/main.cpp index 015361c..7ab7e4b 100644 --- a/main.cpp +++ b/main.cpp @@ -6,12 +6,13 @@ /* By: iherman- +#include int get_port(const char* arg) {