From 708a4ee25f06aff12e3700c73825cb480d62b6dc Mon Sep 17 00:00:00 2001 From: whaffman Date: Thu, 18 Sep 2025 12:57:00 +0200 Subject: [PATCH] Implement Socket class: add constructors, destructor, and methods for socket operations including listen, bind, accept, recv, send, and setNonBlocking. --- webserv/socket/Socket.cpp | 89 +++++++++++++++++++++++++++++++++++++++ webserv/socket/Socket.hpp | 29 +++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 webserv/socket/Socket.cpp create mode 100644 webserv/socket/Socket.hpp diff --git a/webserv/socket/Socket.cpp b/webserv/socket/Socket.cpp new file mode 100644 index 0000000..a8c13e9 --- /dev/null +++ b/webserv/socket/Socket.cpp @@ -0,0 +1,89 @@ +#include + +#include +#include // For close() + +#include // For inet_addr +#include // For fcntl()" +#include // For sockaddr_in +#include + +Socket::Socket() : _fd(socket(AF_INET, SOCK_STREAM, 0)) +{ + if (_fd == -1) + { + 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; + throw std::runtime_error("setsockopt failed"); + } +} + +Socket::Socket(int fd) : _fd(fd) // NOLINT readability-identifier-naming +{ + if (_fd == -1) + { + throw std::runtime_error("Invalid file descriptor"); + } +} + +Socket::~Socket() +{ + if (_fd != -1) + { + close(_fd); + } +} + +void Socket::listen(int backlog) const +{ + if (::listen(_fd, backlog) < 0) + { + throw std::runtime_error("Listen failed"); + } +} +void Socket::bind(const std::string &host, const int port) const +{ + + 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, (struct sockaddr *)&address, sizeof(address)) < 0) // NOLINT cppcoreguidelines-pro-type-cstyle-cast + { + throw std::runtime_error("Bind failed"); + } +} + +Socket Socket::accept() const +{ + int client_fd = ::accept(_fd, nullptr, nullptr); + if (client_fd < 0) + { + throw std::runtime_error("Accept failed"); + } + return {client_fd}; +} + +ssize_t Socket::recv(void *buf, size_t len) const +{ + return ::recv(_fd, buf, len, 0); +} + +ssize_t Socket::send(const void *buf, size_t len) const +{ + return ::send(_fd, buf, len, 0); +} + +void Socket::setNonBlocking() const +{ + if (fcntl(_fd, F_SETFL, O_NONBLOCK) < 0) + { + throw std::runtime_error("Failed to set non-blocking mode"); + } +} \ No newline at end of file diff --git a/webserv/socket/Socket.hpp b/webserv/socket/Socket.hpp new file mode 100644 index 0000000..3100571 --- /dev/null +++ b/webserv/socket/Socket.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +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; // Move constructor + Socket &operator=(Socket &&other) noexcept; // Move assignment + + ~Socket(); + + void listen(int backlog) const; + void bind(const std::string &host, const int port) const; + [[nodiscard]] Socket 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