summaryrefslogtreecommitdiff
path: root/src/misc
diff options
context:
space:
mode:
Diffstat (limited to 'src/misc')
-rw-r--r--src/misc/FileDescriptor.cpp86
-rw-r--r--src/misc/FileDescriptor.hpp35
2 files changed, 121 insertions, 0 deletions
diff --git a/src/misc/FileDescriptor.cpp b/src/misc/FileDescriptor.cpp
new file mode 100644
index 0000000..92505f5
--- /dev/null
+++ b/src/misc/FileDescriptor.cpp
@@ -0,0 +1,86 @@
+#include "FileDescriptor.hpp"
+#include <cstdlib>
+#include <fcntl.h>
+#include <sys/poll.h>
+#include <unistd.h>
+#include <utility>
+
+CFileDescriptor::CFileDescriptor(int const fd)
+ : m_fd(fd) {}
+
+CFileDescriptor::CFileDescriptor(CFileDescriptor &&other) noexcept
+ : m_fd(std::exchange(other.m_fd, -1)) {}
+
+CFileDescriptor &CFileDescriptor::operator=(CFileDescriptor &&other) noexcept {
+ if (this == &other) // Shit will go haywire if there is duplicate ownership
+ abort();
+
+ reset();
+ m_fd = std::exchange(other.m_fd, -1);
+ return *this;
+}
+
+CFileDescriptor::~CFileDescriptor() {
+ reset();
+}
+
+bool CFileDescriptor::isValid() const {
+ return m_fd != -1;
+}
+
+int CFileDescriptor::get() const {
+ return m_fd;
+}
+
+int CFileDescriptor::getFlags() const {
+ return fcntl(m_fd, F_GETFD);
+}
+
+bool CFileDescriptor::setFlags(int flags) {
+ return fcntl(m_fd, F_SETFD, flags) != -1;
+}
+
+int CFileDescriptor::take() {
+ return std::exchange(m_fd, -1);
+}
+
+void CFileDescriptor::reset() {
+ if (m_fd != -1) {
+ close(m_fd);
+ m_fd = -1;
+ }
+}
+
+CFileDescriptor CFileDescriptor::duplicate(int flags) const {
+ if (m_fd == -1)
+ return {};
+
+ return CFileDescriptor{fcntl(m_fd, flags, 0)};
+}
+
+bool CFileDescriptor::isClosed() const {
+ return isClosed(m_fd);
+}
+
+bool CFileDescriptor::isReadable() const {
+ return isReadable(m_fd);
+}
+
+bool CFileDescriptor::isClosed(int fd) {
+ pollfd pfd = {
+ .fd = fd,
+ .events = POLLIN,
+ .revents = 0,
+ };
+
+ if (poll(&pfd, 1, 0) < 0)
+ return true;
+
+ return pfd.revents & (POLLHUP | POLLERR);
+}
+
+bool CFileDescriptor::isReadable(int fd) {
+ pollfd pfd = {.fd = fd, .events = POLLIN, .revents = 0};
+
+ return poll(&pfd, 1, 0) > 0 && (pfd.revents & POLLIN);
+}
diff --git a/src/misc/FileDescriptor.hpp b/src/misc/FileDescriptor.hpp
new file mode 100644
index 0000000..75aeb73
--- /dev/null
+++ b/src/misc/FileDescriptor.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <fcntl.h>
+class CFileDescriptor {
+ public:
+ CFileDescriptor() = default;
+ explicit CFileDescriptor(int const fd);
+ CFileDescriptor(CFileDescriptor &&) noexcept;
+ CFileDescriptor &operator=(CFileDescriptor &&) noexcept;
+ ~CFileDescriptor();
+
+ CFileDescriptor(const CFileDescriptor &) = delete;
+ CFileDescriptor &operator=(const CFileDescriptor &) = delete;
+
+ bool operator==(const CFileDescriptor &rhs) const {
+ return m_fd == rhs.m_fd;
+ }
+
+ bool isValid() const;
+ int get() const;
+ int getFlags() const;
+ bool setFlags(int flags);
+ int take();
+ void reset();
+ CFileDescriptor duplicate(int flags = F_DUPFD_CLOEXEC) const;
+
+ bool isReadable() const;
+ bool isClosed() const;
+
+ static bool isReadable(int fd);
+ static bool isClosed(int fd);
+
+ private:
+ int m_fd = -1;
+};