Added functional multiple client handling
This commit is contained in:
@@ -6,19 +6,66 @@
|
||||
/* By: iherman- <iherman-@student.42malaga.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2026/05/06 17:19:12 by iherman- #+# #+# */
|
||||
/* Updated: 2026/05/07 14:08:48 by iherman- ### ########.fr */
|
||||
/* Updated: 2026/05/09 21:50:37 by iherman- ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "Server.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
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<int, User>::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);
|
||||
}
|
||||
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<struct pollfd>::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<int, User>::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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user