From f3bdf28eedbfa45d21467e22c0e0c537efc6e0ca Mon Sep 17 00:00:00 2001 From: Quinten Date: Tue, 14 Oct 2025 18:38:57 +0200 Subject: [PATCH] refactor: implement socket structure and server refactor --- tests/socket/test_socket.cpp | 6 +- webserv/client/Client.cpp | 14 ++-- webserv/client/Client.hpp | 12 ++-- webserv/log/Log.hpp | 2 +- webserv/main.cpp | 3 +- webserv/server/Server.cpp | 88 ++++++++++++------------ webserv/server/Server.hpp | 21 +++--- webserv/socket/ASocket.cpp | 66 ++++++++++++++++++ webserv/socket/ASocket.hpp | 40 +++++++++++ webserv/socket/CGISocket.cpp | 72 ++----------------- webserv/socket/CGISocket.hpp | 27 ++------ webserv/socket/ClientSocket.cpp | 13 ++++ webserv/socket/ClientSocket.hpp | 15 ++++ webserv/socket/ServerSocket.cpp | 83 ++++++++++++++++++++++ webserv/socket/ServerSocket.hpp | 22 ++++++ webserv/socket/Socket.cpp | 118 -------------------------------- webserv/socket/Socket.hpp | 32 --------- 17 files changed, 324 insertions(+), 310 deletions(-) create mode 100644 webserv/socket/ASocket.cpp create mode 100644 webserv/socket/ASocket.hpp create mode 100644 webserv/socket/ClientSocket.cpp create mode 100644 webserv/socket/ClientSocket.hpp create mode 100644 webserv/socket/ServerSocket.cpp create mode 100644 webserv/socket/ServerSocket.hpp delete mode 100644 webserv/socket/Socket.cpp delete mode 100644 webserv/socket/Socket.hpp diff --git a/tests/socket/test_socket.cpp b/tests/socket/test_socket.cpp index 7b7241b..46832c0 100644 --- a/tests/socket/test_socket.cpp +++ b/tests/socket/test_socket.cpp @@ -1,4 +1,4 @@ -#include +#include #include @@ -23,7 +23,7 @@ class SocketTest : public ::testing::Test TEST_F(SocketTest, DefaultConstructor) { - Socket socket; + ServerSocket socket; // Socket should be created successfully // We can't test much without actually creating network resources SUCCEED(); @@ -32,7 +32,7 @@ TEST_F(SocketTest, DefaultConstructor) TEST_F(SocketTest, ConstructorWithFd) { // Socket constructor with invalid fd throws an exception - EXPECT_THROW(Socket socket(-1), std::runtime_error); + EXPECT_THROW(ServerSocket socket(-1), std::runtime_error); } TEST_F(SocketTest, MoveConstructor) diff --git a/webserv/client/Client.cpp b/webserv/client/Client.cpp index 469a558..0123762 100644 --- a/webserv/client/Client.cpp +++ b/webserv/client/Client.cpp @@ -1,9 +1,9 @@ #include -#include // for HttpHeaders -#include // for Log, LOCATION -#include // for Router -#include // for Server -#include // for Socket +#include // for HttpHeaders +#include // for Log, LOCATION +#include // for Router +#include // for Server +#include // for Socket #include // for uint8_t #include // for ref, reference_wrapper @@ -13,7 +13,7 @@ #include // for ssize_t -Client::Client(std::unique_ptr socket, Server &server) +Client::Client(std::unique_ptr socket, Server &server) : httpRequest_(std::make_unique(this)), httpResponse_(std::make_unique()), client_socket_(std::move(socket)), server_(std::ref(server)) { @@ -44,7 +44,7 @@ void Client::request() { Log::trace(LOCATION); char buffer[bufferSize_] = {}; // NOLINT(cppcoreguidelines-avoid-c-arrays) - ssize_t bytesRead = client_socket_->recv( + ssize_t bytesRead = client_socket_->read( buffer, sizeof(buffer) - 1); // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay) if (bytesRead < 0) { diff --git a/webserv/client/Client.hpp b/webserv/client/Client.hpp index 6a8b8cc..7ac63ca 100644 --- a/webserv/client/Client.hpp +++ b/webserv/client/Client.hpp @@ -2,12 +2,14 @@ // #include +#include "webserv/socket/ClientSocket.hpp" + #include // for ServerConfig #include // for OK #include // for HttpRequest #include // for HttpResponse #include -#include // for Socket +#include // for Socket #include // for size_t #include // for uint8_t @@ -15,14 +17,14 @@ #include // for vector class Server; -class Socket; +class ClientSocket; class ServerConfig; class HttpResponse; class Client { public: - Client(std::unique_ptr socket, Server &server); + Client(std::unique_ptr socket, Server &server); Client(const Client &other) = delete; // Disable copy constructor Client &operator=(const Client &other) = delete; // Disable copy assignment @@ -37,7 +39,7 @@ class Client [[nodiscard]] bool isResponseReady() const; [[nodiscard]] int getStatusCode() const; - [[nodiscard]] Socket &getSocket() const { return *client_socket_; } + [[nodiscard]] ClientSocket &getSocket() const { return *client_socket_; } // void setError(int statusCode); @@ -48,7 +50,7 @@ class Client constexpr static size_t bufferSize_ = 4096; std::unique_ptr httpRequest_ = nullptr; std::unique_ptr httpResponse_ = nullptr; - std::unique_ptr client_socket_; + std::unique_ptr client_socket_; Server &server_; // mutable const ServerConfig *server_config_ = nullptr; }; \ No newline at end of file diff --git a/webserv/log/Log.hpp b/webserv/log/Log.hpp index 9ac20b1..bc8f70e 100644 --- a/webserv/log/Log.hpp +++ b/webserv/log/Log.hpp @@ -49,7 +49,7 @@ class Log void log(Level level, const std::string &message, const std::map &context); - static constexpr Log::Level COMPILE_TIME_LOG_LEVEL = Log::Level::Info; + static constexpr Log::Level COMPILE_TIME_LOG_LEVEL = Log::Level::Trace; static void setFileChannel(const std::string &filename, std::ios_base::openmode mode = std::ios_base::app); static void setStdoutChannel(); diff --git a/webserv/main.cpp b/webserv/main.cpp index dcd61d6..b45db68 100644 --- a/webserv/main.cpp +++ b/webserv/main.cpp @@ -6,7 +6,6 @@ #include // for ios_base #include // for allocator, basic_string, char_traits, operator+, string -#include // for vector int main(int argc, char **argv) { @@ -37,6 +36,6 @@ int main(int argc, char **argv) Log::debug("ConfigManager initialized successfully."); Server server(configManager); - server.start(); + server.run(); return 0; } \ No newline at end of file diff --git a/webserv/server/Server.cpp b/webserv/server/Server.cpp index 48c70bf..07dfb96 100644 --- a/webserv/server/Server.cpp +++ b/webserv/server/Server.cpp @@ -1,9 +1,12 @@ +#include "webserv/socket/ASocket.hpp" + #include // for Client #include // for ConfigManager #include // for ServerConfig #include // for Log, LOCATION #include -#include // for Socket +#include // for ClientSocket +#include // for ServerSocket #include // for errno #include // for strerror @@ -38,6 +41,15 @@ Server::Server(const ConfigManager &configManager) Log::fatal("epoll_create1 failed"); throw std::runtime_error("epoll_create1 failed"); } + for (const auto &config : configManager_.getServerConfigs()) + { + setupServerSocket(*config); + } + if (listener_fds_.empty()) + { + Log::fatal("No server sockets created."); + throw std::runtime_error("No server sockets created."); + } } Server::~Server() @@ -49,27 +61,13 @@ Server::~Server() } } -void Server::start() +void Server::add(const ASocket &socket, uint32_t events, Client *client) { - Log::trace(LOCATION); - Log::info("Starting servers..."); - // 1. Load server configurations - - for (const auto &config : configManager_.getServerConfigs()) + if (socket.getType() != ASocket::Type::SERVER_SOCKET && client == nullptr) { - setupServerSocket(*config); + Log::error("Client pointer must be provided for non-server sockets"); + throw std::invalid_argument("Client pointer must be provided for non-server sockets"); } - if (listener_fds_.empty()) - { - Log::fatal("No server sockets created."); - throw std::runtime_error("No server sockets created."); - } - - eventLoop(); -} - -void Server::add(const Socket &socket, uint32_t events) const -{ Log::trace(LOCATION); int fd = socket.getFd(); struct epoll_event event{}; @@ -80,24 +78,27 @@ void Server::add(const Socket &socket, uint32_t events) const Log::error("epoll_ctl ADD failed for fd: " + std::to_string(fd)); throw std::runtime_error("epoll_ctl ADD failed"); } + socketToClient_[fd] = client; +} + +void Server::remove(const ASocket &socket) +{ + Log::trace(LOCATION); + int fd = socket.getFd(); + if (epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, nullptr) == -1) + { + Log::error("epoll_ctl DEL failed for fd: " + std::to_string(fd)); + throw std::runtime_error("epoll_ctl DEL failed"); + } + socketToClient_.erase(fd); } void Server::disconnect(const Client &client) { Log::trace(LOCATION); int client_fd = client.getSocket().getFd(); - clients_.erase(client_fd); -} -void Server::remove(const Socket &socket) const -{ - Log::trace(LOCATION); - int filedes = socket.getFd(); - if (epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, filedes, nullptr) == -1) - { - Log::error("epoll_ctl DEL failed for fd: " + std::to_string(filedes)); - throw std::runtime_error("epoll_ctl DEL failed"); - } + std::erase_if(clients_, [&](const std::unique_ptr &c) { return c->getSocket().getFd() == client_fd; }); } void Server::setupServerSocket(const ServerConfig &config) @@ -106,9 +107,8 @@ void Server::setupServerSocket(const ServerConfig &config) try { auto host = config.get("host").value_or(std::string()); // TODO should not be a default host - - auto port = config.get("listen").value_or(0); // TODO should not be a default port - std::unique_ptr serverSocket = std::make_unique(); + auto port = config.get("listen").value_or(0); // TODO should not be a default port + std::unique_ptr serverSocket = std::make_unique(); serverSocket->bind(host, port); serverSocket->listen(SOMAXCONN); int server_fd = serverSocket->getFd(); @@ -118,7 +118,6 @@ void Server::setupServerSocket(const ServerConfig &config) listeners_.push_back(std::move(serverSocket)); listener_fds_.insert(server_fd); Log::info("Server listening on " + host + ":" + std::to_string(port) + "..."); - // static_cast(config["listen"]) + "..."); } catch (const std::exception &e) { @@ -129,13 +128,15 @@ void Server::setupServerSocket(const ServerConfig &config) void Server::handleConnection(struct epoll_event *event) { Log::trace(LOCATION); - Socket &listener = getListener(event->data.fd); - std::unique_ptr clientSocket = listener.accept(); - add(*clientSocket, EPOLLIN); - clients_.insert({clientSocket->getFd(), std::make_unique(std::move(clientSocket), *this)}); + ServerSocket &listener = getListener(event->data.fd); + std::unique_ptr clientSocket = listener.accept(); + + auto client = std::make_unique(std::move(clientSocket), *this); + add(client->getSocket(), EPOLLIN, client.get()); + clients_.emplace_back(std::move(client)); } -Socket &Server::getListener(int fd) const +ServerSocket &Server::getListener(int fd) const { Log::trace(LOCATION); for (const auto &listener : listeners_) @@ -152,10 +153,9 @@ Socket &Server::getListener(int fd) const Client &Server::getClient(int fd) const { Log::trace(LOCATION); - auto it = clients_.find(fd); - if (it != clients_.end()) + if (socketToClient_.contains(fd)) { - return *(it->second); + return *(socketToClient_.at(fd)); } Log::error("Client not found for fd: " + std::to_string(fd)); throw std::runtime_error("Client not found for fd: " + std::to_string(fd)); @@ -198,7 +198,7 @@ void Server::handleResponse(struct epoll_event *event) { Log::debug("Sent " + std::to_string(bytesSent) + " bytes to fd: " + std::to_string(event->data.fd)); } - clients_.erase(event->data.fd); + disconnect(client); } void Server::handleEvent(struct epoll_event *event) @@ -224,7 +224,7 @@ void Server::handleEvent(struct epoll_event *event) } } -void Server::eventLoop() +void Server::run() { Log::trace(LOCATION); Log::info("Listening..."); diff --git a/webserv/server/Server.hpp b/webserv/server/Server.hpp index a560bb6..7bf2c03 100644 --- a/webserv/server/Server.hpp +++ b/webserv/server/Server.hpp @@ -1,10 +1,12 @@ #pragma once +#include "webserv/socket/ASocket.hpp" + #include #include #include // for ServerConfig #include // for Router -#include // for Socket +#include // for ServerSocket #include // for uint32_t #include // for unique_ptr @@ -32,13 +34,13 @@ class Server ~Server(); - void start(); - void add(const Socket &socket, uint32_t events) const; - void remove(const Socket &socket) const; + void run(); + void add(const ASocket &socket, uint32_t events, Client *client = nullptr); + void remove(const ASocket &socket); void disconnect(const Client &client); void responseReady(int client_fd) const; - Socket &getListener(int fd) const; + ServerSocket &getListener(int fd) const; Client &getClient(int fd) const; const Router &getRouter() const; @@ -46,9 +48,11 @@ class Server int epoll_fd_; const ConfigManager &configManager_; const Router router_; - std::vector> listeners_; + std::vector> listeners_; std::set listener_fds_; - std::unordered_map> clients_; + // std::unordered_map> clients_; + std::vector> clients_; + std::unordered_map socketToClient_; void handleEvent(struct epoll_event *event); void handleConnection(struct epoll_event *event); @@ -56,5 +60,4 @@ class Server void handleResponse(struct epoll_event *event); void setupServerSocket(const ServerConfig &config); - void eventLoop(); - }; +}; diff --git a/webserv/socket/ASocket.cpp b/webserv/socket/ASocket.cpp new file mode 100644 index 0000000..0e4d6ff --- /dev/null +++ b/webserv/socket/ASocket.cpp @@ -0,0 +1,66 @@ +#include // for Log, LOCATION +#include + +#include // For fcntl() +#include +#include // For close() + +ASocket::ASocket(int fd) : fd_(fd) +{ + Log::trace(LOCATION); + if (fd_ == -1) + { + Log::error("Invalid file descriptor"); + throw std::runtime_error("Invalid file descriptor"); + } + setNonBlocking(); +} + +ASocket::~ASocket() +{ + Log::trace(LOCATION); + if (fd_ != -1) + { + close(fd_); + } +} + +ssize_t ASocket::read(void *buf, size_t len) const +{ + ssize_t bytesRead = ::recv(fd_, buf, len, 0); + if (bytesRead == -1) + { + throw std::system_error(errno, std::generic_category(), "Socket: Read error"); + } + return bytesRead; +} + +ssize_t ASocket::write(const void *buf, size_t len) const +{ + Log::trace(LOCATION); + ssize_t bytesSent = ::send(fd_, buf, len, 0); + if (bytesSent == -1) + { + throw std::system_error(errno, std::generic_category(), "Socket: Write error"); + } + return bytesSent; +} + +void ASocket::setNonBlocking() const +{ + if (fcntl(fd_, F_SETFL, O_NONBLOCK) == -1) + { + throw std::system_error(errno, std::generic_category(), "ASocket: Failed to set FD non-blocking"); + } +} + +int ASocket::getFd() const +{ + Log::trace(LOCATION); + return fd_; +} + +void ASocket::setFd(int fd) +{ + fd_ = fd; +} \ No newline at end of file diff --git a/webserv/socket/ASocket.hpp b/webserv/socket/ASocket.hpp new file mode 100644 index 0000000..b5029ed --- /dev/null +++ b/webserv/socket/ASocket.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include // for size_t +#include + +#include // for ssize_t + +class ASocket +{ + public: + enum class Type : uint8_t + { + CLIENT_SOCKET, + SERVER_SOCKET, + CGI_SOCKET + }; + + ASocket() = delete; + explicit ASocket(int fd); + + ASocket(const ASocket &other) = delete; + ASocket &operator=(const ASocket &other) = delete; + ASocket(ASocket &&other) noexcept = default; + ASocket &operator=(ASocket &&other) noexcept = default; + + virtual ~ASocket(); + + [[nodiscard]] virtual Type getType() const = 0; + [[nodiscard]] int getFd() const; + + ssize_t read(void *buf, size_t len) const; + ssize_t write(const void *buf, size_t len) const; + + protected: + void setNonBlocking() const; + void setFd(int fd); + + private: + int fd_; +}; diff --git a/webserv/socket/CGISocket.cpp b/webserv/socket/CGISocket.cpp index 70601db..2daa441 100644 --- a/webserv/socket/CGISocket.cpp +++ b/webserv/socket/CGISocket.cpp @@ -1,74 +1,12 @@ +#include #include -#include // for strerror -#include // for runtime_error -#include // for string, operator+ -#include // for system_error, error_code - -#include // for fcntl, O_NONBLOCK -#include // for close, read, write - -CGISocket::CGISocket(int readFd, int writeFd) : _readFd(readFd), _writeFd(writeFd) +CGISocket::CGISocket(int fd) : ASocket(fd) { - if (_readFd == -1 || _writeFd == -1) - { - throw std::runtime_error("CGISocket: Invalid file descriptors"); - } - setNonBlocking(); + Log::trace(LOCATION); } -CGISocket::~CGISocket() +ASocket::Type CGISocket::getType() const { - if (_readFd != -1) - { - close(_readFd); - } - if (_writeFd != -1) - { - close(_writeFd); - } - + return ASocket::Type::CGI_SOCKET; } - -int CGISocket::getReadFd() const -{ - return _readFd; -} - -int CGISocket::getWriteFd() const -{ - return _writeFd; -} - -ssize_t CGISocket::read(void *buffer, size_t size) const -{ - ssize_t bytesRead = ::read(_readFd, buffer, size); - if (bytesRead == -1) - { - throw std::system_error(errno, std::generic_category(), "CGISocket: Read error"); - } - return bytesRead; -} - -ssize_t CGISocket::write(const void *buffer, size_t size) const -{ - ssize_t bytesWritten = ::write(_writeFd, buffer, size); - if (bytesWritten == -1) - { - throw std::system_error(errno, std::generic_category(), "CGISocket: Write error"); - } - return bytesWritten; -} - -void CGISocket::setNonBlocking() const -{ - if (fcntl(_readFd, F_SETFL, O_NONBLOCK) == -1) - { - throw std::system_error(errno, std::generic_category(), "CGISocket: Failed to set read FD non-blocking"); - } - if (fcntl(_writeFd, F_SETFL, O_NONBLOCK) == -1) - { - throw std::system_error(errno, std::generic_category(), "CGISocket: Failed to set write FD non-blocking"); - } -} - diff --git a/webserv/socket/CGISocket.hpp b/webserv/socket/CGISocket.hpp index e3cc148..6f18b80 100644 --- a/webserv/socket/CGISocket.hpp +++ b/webserv/socket/CGISocket.hpp @@ -1,32 +1,15 @@ #pragma once +#include + #include #include #include -class CGISocket +class CGISocket : public ASocket { public: - CGISocket(int readFd, int writeFd); - - CGISocket(const CGISocket &) = delete; - CGISocket &operator=(const CGISocket &) = delete; - CGISocket(CGISocket &&other) noexcept = default; - CGISocket &operator=(CGISocket &&other) noexcept = default; - - ~CGISocket(); - - // Get FDs for server epoll registration - [[nodiscard]] int getReadFd() const; // Server reads CGI output - [[nodiscard]] int getWriteFd() const; // Server writes to CGI input - - // Handler interface - ssize_t read(void *buffer, size_t size) const; - ssize_t write(const void *buffer, size_t size) const; - void setNonBlocking() const; - - private: - int _readFd = -1; // Server side of output pipe - int _writeFd = -1; // Server side of input pipe + [[nodiscard]] ASocket::Type getType() const override; + explicit CGISocket(int fd); }; \ No newline at end of file diff --git a/webserv/socket/ClientSocket.cpp b/webserv/socket/ClientSocket.cpp new file mode 100644 index 0000000..48a6a65 --- /dev/null +++ b/webserv/socket/ClientSocket.cpp @@ -0,0 +1,13 @@ +#include +#include + +ClientSocket::ClientSocket(int fd) : ASocket(fd) +{ + Log::trace(LOCATION); +} + +ASocket::Type ClientSocket::getType() const +{ + Log::trace(LOCATION); + return ASocket::Type::CLIENT_SOCKET; +} diff --git a/webserv/socket/ClientSocket.hpp b/webserv/socket/ClientSocket.hpp new file mode 100644 index 0000000..2506ea0 --- /dev/null +++ b/webserv/socket/ClientSocket.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include +#include +#include + +class ClientSocket : public ASocket +{ + public: + [[nodiscard]] ASocket::Type getType() const override; + + explicit ClientSocket(int fd); +}; \ No newline at end of file diff --git a/webserv/socket/ServerSocket.cpp b/webserv/socket/ServerSocket.cpp new file mode 100644 index 0000000..7d6d414 --- /dev/null +++ b/webserv/socket/ServerSocket.cpp @@ -0,0 +1,83 @@ +#include "webserv/socket/ASocket.hpp" +#include "webserv/socket/ClientSocket.hpp" + +#include +#include + +#include +#include + +#include // For inet_addr +#include // For fcntl()" +#include // For sockaddr_in +#include +#include // For close() + +ServerSocket::ServerSocket() : ASocket(socket(AF_INET, SOCK_STREAM, 0)) +{ + Log::trace(LOCATION); + if (getFd() == -1) + { + Log::error("Socket creation failed"); + throw std::runtime_error("Socket creation failed"); + } + int opt = 1; + if (setsockopt(getFd(), SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) + { + close(getFd()); + setFd(-1); + Log::error("setsockopt failed"); + throw std::runtime_error("setsockopt failed"); + } + setNonBlocking(); +} + +ServerSocket::ServerSocket(int fd) : ASocket(fd) +{ + Log::trace(LOCATION); +} + +void ServerSocket::listen(int backlog) const +{ + Log::trace(LOCATION); + if (::listen(getFd(), backlog) < 0) + { + Log::error("Listen failed"); + throw std::runtime_error("Listen failed"); + } +} + +void ServerSocket::bind(const std::string &host, const int port) const +{ + Log::trace(LOCATION); + struct sockaddr_in address{}; + address.sin_family = AF_INET; + address.sin_addr.s_addr = inet_addr(host.c_str()); + address.sin_port = htons(port); + + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + if (::bind(getFd(), reinterpret_cast(&address), sizeof(address)) < 0) + { + Log::fatal("Cannot bind to " + host + ":" + std::to_string(port) + + " - address already in use or permission denied"); + throw std::runtime_error("Bind failed"); + } +} + +ASocket::Type ServerSocket::getType() const +{ + Log::trace(LOCATION); + return ASocket::Type::SERVER_SOCKET; +} + +std::unique_ptr ServerSocket::accept() const +{ + Log::trace(LOCATION); + int client_fd = ::accept(getFd(), nullptr, nullptr); + if (client_fd < 0) + { + Log::error("Accept failed"); + throw std::runtime_error("Accept failed"); + } + return std::make_unique(client_fd); +} diff --git a/webserv/socket/ServerSocket.hpp b/webserv/socket/ServerSocket.hpp new file mode 100644 index 0000000..311a161 --- /dev/null +++ b/webserv/socket/ServerSocket.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "webserv/socket/ClientSocket.hpp" +#include + +#include // for unique_ptr +#include // for string + +class ServerSocket : public ASocket +{ + public: + ServerSocket(); + + ServerSocket(int fd); + + void listen(int backlog) const; + void bind(const std::string &host, int port) const; + + [[nodiscard]] ASocket::Type getType() const override; + + [[nodiscard]] std::unique_ptr accept() const; +}; \ No newline at end of file diff --git a/webserv/socket/Socket.cpp b/webserv/socket/Socket.cpp deleted file mode 100644 index 2ab2511..0000000 --- a/webserv/socket/Socket.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include - -#include - -#include -#include - -#include // For inet_addr -#include // For fcntl()" -#include // For sockaddr_in -#include -#include // For close() - -Socket::Socket() : fd_(socket(AF_INET, SOCK_STREAM, 0)) -{ - Log::trace(LOCATION); - if (fd_ == -1) - { - Log::error("Socket creation failed"); - throw std::runtime_error("Socket creation failed"); - } - int opt = 1; - if (setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) - { - close(fd_); - fd_ = -1; - Log::error("setsockopt failed"); - throw std::runtime_error("setsockopt failed"); - } - setNonBlocking(); -} - -Socket::Socket(int fd) : fd_(fd) // NOLINT(readability-identifier-naming) -{ - Log::trace(LOCATION); - if (fd_ == -1) - { - Log::error("Invalid file descriptor"); - throw std::runtime_error("Invalid file descriptor"); - } - setNonBlocking(); -} - -Socket::~Socket() -{ - Log::trace(LOCATION); - if (fd_ != -1) - { - close(fd_); - } -} - -void Socket::listen(int backlog) const -{ - Log::trace(LOCATION); - if (::listen(fd_, backlog) < 0) - { - Log::error("Listen failed"); - throw std::runtime_error("Listen failed"); - } -} - -void Socket::bind(const std::string &host, const int port) const -{ - Log::trace(LOCATION); - struct sockaddr_in address{}; - address.sin_family = AF_INET; - address.sin_addr.s_addr = inet_addr(host.c_str()); - address.sin_port = htons(port); - - if (::bind(fd_, reinterpret_cast(&address), sizeof(address)) - < 0) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) - { - Log::fatal("Cannot bind to " + host + ":" + std::to_string(port) - + " - address already in use or permission denied"); - throw std::runtime_error("Bind failed"); - } -} - -std::unique_ptr Socket::accept() const -{ - Log::trace(LOCATION); - int client_fd = ::accept(fd_, nullptr, nullptr); - if (client_fd < 0) - { - Log::error("Accept failed"); - throw std::runtime_error("Accept failed"); - } - return std::make_unique(client_fd); -} - -ssize_t Socket::recv(void *buf, size_t len) const -{ - Log::trace(LOCATION); - return ::recv(fd_, buf, len, 0); -} - -ssize_t Socket::send(const void *buf, size_t len) const -{ - Log::trace(LOCATION); - return ::send(fd_, buf, len, 0); -} - -void Socket::setNonBlocking() const -{ - Log::trace(LOCATION); - if (fcntl(fd_, F_SETFL, O_NONBLOCK) < 0) - { - Log::error("Failed to set non-blocking mode"); - throw std::runtime_error("Failed to set non-blocking mode"); - } -} - -int Socket::getFd() const -{ - Log::trace(LOCATION); - return fd_; -} \ No newline at end of file diff --git a/webserv/socket/Socket.hpp b/webserv/socket/Socket.hpp deleted file mode 100644 index 11b0eba..0000000 --- a/webserv/socket/Socket.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include // for size_t -#include // for unique_ptr -#include // for string - -#include // for ssize_t - -class Socket -{ - public: - Socket(); - Socket(int fd); // NOLINT readability-identifier-naming - - Socket(const Socket &other) = delete; // Disable copy constructor - Socket &operator=(const Socket &other) = delete; // Disable copy assignment - Socket(Socket &&other) noexcept = default; // Move constructor - Socket &operator=(Socket &&other) noexcept = default; // Move assignment - - ~Socket(); - - void listen(int backlog) const; - void bind(const std::string &host, int port) const; - [[nodiscard]] std::unique_ptr accept() const; - ssize_t recv(void *buf, size_t len) const; - ssize_t send(const void *buf, size_t len) const; - void setNonBlocking() const; - [[nodiscard]] int getFd() const; - - private: - int fd_; -}; \ No newline at end of file