Added functional multiple client handling

This commit is contained in:
iherman-
2026-05-09 21:52:16 +02:00
parent 752eb89e72
commit bdc24594a4
5 changed files with 229 additions and 68 deletions

View File

@@ -1,8 +1,8 @@
NAME = ircserv NAME = ircserv
SRC = main.cpp Server/Server.cpp Client/Client.cpp SRC = main.cpp Server/Server.cpp User/User.cpp
HEADERS = Server/Server.hpp HEADERS = Server/Server.hpp User/User.hpp
OBJ = $(SRC:.cpp=.o) OBJ = $(SRC:.cpp=.o)

View File

@@ -6,19 +6,66 @@
/* By: iherman- <iherman-@student.42malaga.com +#+ +:+ +#+ */ /* By: iherman- <iherman-@student.42malaga.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/06 17:19:12 by iherman- #+# #+# */ /* 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 "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; const int Server::kConnectionQueueLimit = 10;
Server::Server() : Server::Server() :
port_(PORT_DEFAULT), 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) : Server::Server(int port, const std::string& password) :
@@ -55,6 +102,9 @@ Server::Server(int port, const std::string& password) :
Server::~Server() Server::~Server()
{ {
for (std::map<int, User>::iterator it = clients_.begin(); it != clients_.end(); ++it)
close(it->first);
close(serverSocket_); close(serverSocket_);
} }
@@ -65,35 +115,129 @@ Server &Server::operator=(const Server& other)
port_ = other.port_; port_ = other.port_;
serverSocket_ = other.serverSocket_; serverSocket_ = other.serverSocket_;
password_ = other.password_; password_ = other.password_;
sockets_ = other.sockets_;
} }
return *this; return *this;
} }
void Server::run() bool Server::handleClient(User& client)
{ {
const std::size_t kBufferSize = 1024; const std::size_t kBufferSize = 1024;
char buffer[kBufferSize] = {0}; char buffer[kBufferSize] = {0};
struct sockaddr_in client_addr; int recv_amount = recv(client.getFd(), buffer, kBufferSize, 0);
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);
if (recv_amount <= 0) if (recv_amount == 0)
break ; return true;
message.append(buffer, recv_amount); if (recv_amount < 0)
{
if (message.find('\n') != std::string::npos) if (errno == EAGAIN || errno == EWOULDBLOCK)
break ; return false;
return true;
} }
message = "Server received: " + message; client.appendBuffer(std::string(buffer, recv_amount));
send(clientSocket, message.c_str(), message.size(), 0);
close(clientSocket); 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++;
}
}
}

View File

@@ -6,7 +6,7 @@
/* By: iherman- <iherman-@student.42malaga.com +#+ +:+ +#+ */ /* By: iherman- <iherman-@student.42malaga.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/06 17:18:11 by iherman- #+# #+# */ /* Created: 2026/05/06 17:18:11 by iherman- #+# #+# */
/* Updated: 2026/05/07 13:29:00 by iherman- ### ########.fr */ /* Updated: 2026/05/09 21:47:58 by iherman- ### ########.fr */
/* */ /* */
/* ************************************************************************** */ /* ************************************************************************** */
@@ -14,23 +14,7 @@
# define SERVER_HPP # define SERVER_HPP
// C lib functions // C lib functions
#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>
// C++ lib functions // C++ lib functions
# include <iostream> # include <iostream>
@@ -38,25 +22,39 @@
# include <string> # include <string>
# include <cstring> # include <cstring>
# include <vector>
# include <map>
# include "../User/User.hpp"
# define PORT_DEFAULT 9898 # define PORT_DEFAULT 9898
class Server class Server
{ {
private: private:
static const int kConnectionQueueLimit; static const int kConnectionQueueLimit;
int port_; int port_;
int serverSocket_; int serverSocket_;
std::string password_; std::string password_;
std::vector<struct pollfd> sockets_;
std::map<int, User> clients_;
bool handleClient(User& client);
void addClient();
std::vector<struct pollfd>::iterator removeClient(std::vector<struct pollfd>::iterator client);
Server(const Server& other);
Server &operator=(const Server& other);
public: public:
Server(); Server();
Server(int port, const std::string& password); Server(int port, const std::string& password);
~Server(); ~Server();
Server &operator=(const Server& other);
void run(); void run();
}; };

View File

@@ -16,25 +16,42 @@
// Constructors // // Constructors //
////////////////// //////////////////
User::User() User::User() :
fd(-1),
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),
authenticated(false),
registered(false)
{
// std::cout << "User default constructor called" << std::endl;
} }
User::User(const User &other) User::User(const User &other)
{ {
*this = other; *this = other;
// std::cout << "User copy constructor called" << std::endl; // std::cout << "User copy constructor called" << std::endl;
} }
User& User::operator=(const User &other) User& User::operator=(const User &other)
{ {
if (this != &other) if (this != &other)
{ {
// Copy attributes here fd = other.fd;
} nick = other.nick;
// std::cout << "User copy assignment operator called" << std::endl; username = other.username;
return (*this); realname = other.realname;
buffer = other.buffer;
authenticated = other.authenticated;
registered = other.registered;
}
// std::cout << "User copy assignment operator called" << std::endl;
return (*this);
} }
User::~User() User::~User()
@@ -44,22 +61,23 @@ User::~User()
// Getters // Getters
int User::getFd() const { return (this->fd) }; int User::getFd() const { return (this->fd); }
std::string User::getNick() const { return (this->nick) }; std::string User::getNick() const { return (this->nick); }
std::string User::getUsername() const { return (this->username) }; std::string User::getUsername() const { return (this->username); }
std::string User::getRealname() const { return (this->realname) }; std::string User::getRealname() const { return (this->realname); }
std::string &User::getBuffer() { return (this->buffer) }; std::string &User::getBuffer() { return (this->buffer); }
bool User::isAuthenticated() const { return (this->authenticated) }; bool User::isAuthenticated() const { return (this->authenticated); }
bool User::isRegistered() const { return (this->registered) }; bool User::isRegistered() const { return (this->registered); }
// Setters // Setters
void setNick(std::string nick) { this->nick = nick; } void User::appendBuffer(std::string buff) { this->buffer.append(buff); }
void setUsername(std::string username) { this->username = username; } void User::clearBuffer() { this->buffer.clear(); }
void setRealname(std::string realname) { this->realname = realname; }
void appendBuffer(std::string buff) { this->buffer = buff; }
void clearBuffer() { this->buffer.clear(); }
void setAuthenticated(bool value) { this->authenticated = value; } void User::setNick(std::string nick) { this->nick = nick; }
void setRegistered(bool value) { this->registered = value; } 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; }

View File

@@ -29,6 +29,7 @@ class User
public: public:
User(); User();
User(int fd);
User(const User &other); User(const User &other);
User& operator=(const User &other); User& operator=(const User &other);
~User(); ~User();