/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* Server.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: iherman- #include #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") { 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) : port_(port), password_(password) { if (port_ < 1 || port_ > 65535) throw std::runtime_error("Invalid port"); if (password_.empty()) throw std::runtime_error("Empty password"); 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() { for (std::map::iterator it = clients_.begin(); it != clients_.end(); ++it) close(it->first); close(serverSocket_); } Server &Server::operator=(const Server& other) { if (this != &other) { port_ = other.port_; serverSocket_ = other.serverSocket_; password_ = other.password_; sockets_ = other.sockets_; } return *this; } // TEMPORARY TESTING FUNCTION void echo(User& client) { std::string message = "Server received: " + client.getBuffer(); send(client.getFd(), message.c_str(), message.size(), 0); } void Server::parseCommand(User& client) { std::stringstream args(client.getBuffer()); std::string command; args >> command; std::map commands; // TEMP commands["echo"] = &echo; std::map::iterator it = commands.find(command); if (it == commands.end()) { std::string message = "Error: command not found!"; send(client.getFd(), message.c_str(), message.size(), 0); client.clearBuffer(); return ; } it->second(client); client.clearBuffer(); } bool Server::handleClient(User& client) { const std::size_t kBufferSize = 1024; char buffer[kBufferSize] = {0}; int recv_amount = recv(client.getFd(), buffer, kBufferSize, 0); if (recv_amount == 0) return true; if (recv_amount < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) return false; return true; } client.appendBuffer(std::string(buffer, recv_amount)); if (client.getBuffer().find('\n') != std::string::npos) parseCommand(client); 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; } std::vector::iterator Server::removeClient(std::vector::iterator& client) { close(client->fd); std::cout << "Client with fd: " << client->fd << " disconnected " << std::endl; clients_.erase(client->fd); return (sockets_.erase(client)); } 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)) { it = removeClient(it); continue ; } 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) it = removeClient(it); else it++; } } }