first commit: echo server
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* FileDescriptor.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: acossari <acossari@student.codam.nl> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2026/08/24 16:23:52 by acossari #+# #+# */
|
||||
/* Updated: 2026/08/28 16:13:23 by acossari ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "net/FileDescriptor.hpp"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <utility>
|
||||
|
||||
namespace webserv {
|
||||
|
||||
// "Sink parameter": consumes the local parameter by moving its value into msg_
|
||||
// lvalue -> copy into message -> move into msg_ (1 copy, worst case scenario)
|
||||
// rvalue -> move into message -> move into msg_ (0 copies)
|
||||
FileDescriptor::Error::Error(std::string message) : msg_(std::move(message)) {}
|
||||
|
||||
const char* FileDescriptor::Error::what() const noexcept {
|
||||
return msg_.c_str();
|
||||
}
|
||||
|
||||
// A valid fd is either made close-on-exec or closed before construction fails.
|
||||
FileDescriptor::FileDescriptor(int fd) : fd_(fd) {
|
||||
if (fd_ < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// fork() inherits this fd, but a successful execve() closes it before the
|
||||
// new program starts, preventing CGI processes from retaining server fds.
|
||||
if (::fcntl(fd_, F_SETFD, FD_CLOEXEC) == -1) {
|
||||
// The subject forbids errno only after read/recv/write/send.
|
||||
// Save it before close(), which may overwrite the original fcntl error.
|
||||
const int errnoCode = errno;
|
||||
::close(fd_);
|
||||
fd_ = -1;
|
||||
throw Error(std::format("fcntl(F_SETFD, FD_CLOEXEC) on fd {}: {}", fd,
|
||||
std::strerror(errnoCode)));
|
||||
}
|
||||
}
|
||||
|
||||
FileDescriptor::~FileDescriptor() {
|
||||
reset();
|
||||
}
|
||||
|
||||
// The FileDescriptor&& parameter is an rvalue reference and a sink. It accepts
|
||||
// only a temporary or an object passed with std::move(). The constructor takes
|
||||
// ownership of that object's fd, so only the new FileDescriptor will close it.
|
||||
FileDescriptor::FileDescriptor(FileDescriptor&& other) noexcept
|
||||
: fd_(std::exchange(other.fd_, -1)) {}
|
||||
|
||||
FileDescriptor& FileDescriptor::operator=(FileDescriptor&& other) noexcept {
|
||||
if (this != &other) {
|
||||
reset();
|
||||
fd_ = std::exchange(other.fd_, -1);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void FileDescriptor::setNonBlocking() {
|
||||
if (!valid()) {
|
||||
throw Error("setNonBlocking() on an invalid file descriptor");
|
||||
}
|
||||
|
||||
// Read, modify, write pattern: F_SETFL replaces the whole status flags word,
|
||||
// so passing O_NONBLOCK alone would clear whatever else is set.
|
||||
const int flags = ::fcntl(fd_, F_GETFL);
|
||||
if (flags == -1) {
|
||||
throw Error(
|
||||
std::format("fcntl(F_GETFL) on fd {}: {}", fd_, std::strerror(errno)));
|
||||
}
|
||||
if (::fcntl(fd_, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||
throw Error(std::format("fcntl(F_SETFL, O_NONBLOCK) on fd {}: {}", fd_,
|
||||
std::strerror(errno)));
|
||||
}
|
||||
}
|
||||
|
||||
void FileDescriptor::reset() noexcept {
|
||||
if (fd_ >= 0) {
|
||||
::close(fd_);
|
||||
fd_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webserv
|
||||
Reference in New Issue
Block a user