Compare commits

...

3 Commits

Author SHA1 Message Date
iherman-
c61e0826c6 Merged changes 2026-05-10 20:24:20 +02:00
iherman-
d6652af02d Added missing header to main 2026-05-10 19:04:55 +02:00
iherman-
bdc24594a4 Added functional multiple client handling 2026-05-09 21:52:16 +02:00
5 changed files with 205 additions and 61 deletions

View File

@@ -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)

View File

@@ -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);
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)
{
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_));
std::string message;
while (true)
{
int recv_amount = recv(clientSocket, buffer, kBufferSize, 0);
int ret = poll(sockets_.data(), sockets_.size(), -1);
if (recv_amount <= 0)
break ;
if (ret <= 0)
{
// not sure if program should terminate
std::cerr << "Poll failed" << std::endl;
continue ;
}
message.append(buffer, recv_amount);
for (std::vector<struct pollfd>::iterator it = sockets_.begin(); it != sockets_.end(); )
{
if (it->revents & (POLLERR | POLLHUP | POLLNVAL))
{
// remove client
}
if (message.find('\n') != std::string::npos)
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 ;
}
message = "Server received: " + message;
send(clientSocket, message.c_str(), message.size(), 0);
close(clientSocket);
// 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 +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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,6 +22,11 @@
# include <string>
# include <cstring>
# include <vector>
# include <map>
# include "../User/User.hpp"
# define PORT_DEFAULT 9898
class Server
@@ -50,13 +39,22 @@ class Server
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();
};

View File

@@ -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::appendBuffer(std::string buff) { this->buffer.append(buff); }
void User::clearBuffer() { this->buffer.clear(); }
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::setAuthenticated(bool value) { this->authenticated = value; }
void User::setRegistered(bool value) { this->registered = value; }

View File

@@ -6,12 +6,13 @@
/* By: iherman- <iherman-@student.42malaga.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/06 17:57:53 by iherman- #+# #+# */
/* Updated: 2026/05/07 13:28:09 by iherman- ### ########.fr */
/* Updated: 2026/05/10 19:02:29 by iherman- ### ########.fr */
/* */
/* ************************************************************************** */
#include "Server/Server.hpp"
#include <sstream>
#include <cstdio>
int get_port(const char* arg)
{