Added functional multiple client handling
This commit is contained in:
4
Makefile
4
Makefile
@@ -1,8 +1,8 @@
|
||||
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)
|
||||
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* By: iherman- <iherman-@student.42malaga.com +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* 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
|
||||
|
||||
// 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
|
||||
# include <iostream>
|
||||
@@ -38,25 +22,39 @@
|
||||
# include <string>
|
||||
# include <cstring>
|
||||
|
||||
# include <vector>
|
||||
# include <map>
|
||||
|
||||
# include "../User/User.hpp"
|
||||
|
||||
# define PORT_DEFAULT 9898
|
||||
|
||||
class Server
|
||||
{
|
||||
private:
|
||||
static const int kConnectionQueueLimit;
|
||||
|
||||
|
||||
int port_;
|
||||
int serverSocket_;
|
||||
|
||||
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:
|
||||
Server();
|
||||
Server(int port, const std::string& password);
|
||||
~Server();
|
||||
|
||||
Server &operator=(const Server& other);
|
||||
|
||||
void run();
|
||||
};
|
||||
|
||||
|
||||
@@ -16,25 +16,42 @@
|
||||
// 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)
|
||||
{
|
||||
*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)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
// Copy attributes here
|
||||
}
|
||||
// std::cout << "User copy assignment operator called" << std::endl;
|
||||
return (*this);
|
||||
if (this != &other)
|
||||
{
|
||||
fd = other.fd;
|
||||
nick = other.nick;
|
||||
username = other.username;
|
||||
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()
|
||||
@@ -44,22 +61,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 setNick(std::string nick) { this->nick = nick; }
|
||||
void setUsername(std::string username) { this->username = username; }
|
||||
void setRealname(std::string realname) { this->realname = realname; }
|
||||
void appendBuffer(std::string buff) { this->buffer = buff; }
|
||||
void clearBuffer() { this->buffer.clear(); }
|
||||
void User::appendBuffer(std::string buff) { this->buffer.append(buff); }
|
||||
void User::clearBuffer() { this->buffer.clear(); }
|
||||
|
||||
void setAuthenticated(bool value) { this->authenticated = value; }
|
||||
void setRegistered(bool value) { this->registered = value; }
|
||||
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; }
|
||||
@@ -29,6 +29,7 @@ class User
|
||||
|
||||
public:
|
||||
User();
|
||||
User(int fd);
|
||||
User(const User &other);
|
||||
User& operator=(const User &other);
|
||||
~User();
|
||||
|
||||
Reference in New Issue
Block a user