summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/FileDescriptor.cpp89
-rw-r--r--src/FileDescriptor.hpp39
-rw-r--r--src/log.hpp13
-rw-r--r--src/main.cpp9
-rw-r--r--src/server.cpp50
-rw-r--r--src/server.hpp23
-rw-r--r--src/session.cpp112
-rw-r--r--src/session.hpp32
-rw-r--r--src/sessionManager.cpp29
-rw-r--r--src/sessionManager.hpp20
10 files changed, 416 insertions, 0 deletions
diff --git a/src/FileDescriptor.cpp b/src/FileDescriptor.cpp
new file mode 100644
index 0000000..8592f42
--- /dev/null
+++ b/src/FileDescriptor.cpp
@@ -0,0 +1,89 @@
+#include <cstdlib>
+#include <hyprutils/os/FileDescriptor.hpp>
+#include <fcntl.h>
+#include <sys/poll.h>
+#include <unistd.h>
+#include <utility>
+
+using namespace Hyprutils::OS;
+
+CFileDescriptor::CFileDescriptor(int const fd) : m_fd(fd) {}
+
+CFileDescriptor::CFileDescriptor(CFileDescriptor&& other) : m_fd(std::exchange(other.m_fd, -1)) {}
+
+CFileDescriptor& CFileDescriptor::operator=(CFileDescriptor&& other) {
+ 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) {
+ if (fcntl(m_fd, F_SETFD, flags) == -1)
+ return false;
+
+ return true;
+}
+
+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/FileDescriptor.hpp b/src/FileDescriptor.hpp
new file mode 100644
index 0000000..59fb7e9
--- /dev/null
+++ b/src/FileDescriptor.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <fcntl.h>
+namespace Hyprutils {
+namespace OS {
+class CFileDescriptor {
+ public:
+ CFileDescriptor() = default;
+ explicit CFileDescriptor(int const fd);
+ CFileDescriptor(CFileDescriptor &&);
+ CFileDescriptor &operator=(CFileDescriptor &&);
+ ~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;
+};
+}; // namespace OS
+}; // namespace Hyprutils
diff --git a/src/log.hpp b/src/log.hpp
new file mode 100644
index 0000000..5285dc8
--- /dev/null
+++ b/src/log.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <map>
+#include <string>
+typedef enum {
+ LOG_LEVEL_DEBUG = 0,
+ LOG_LEVEL_INFO,
+ LOG_LEVEL_WARN,
+ LOG_LEVEL_ERROR,
+ LOG_LEVEL_FATAL,
+ LOG_LEVEL_MAX
+} eLogLevel;
+
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..1cf50b5
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,9 @@
+#include "sessionManager.hpp"
+#include "server.hpp"
+
+int main() {
+ g_pServer = std::make_unique<CServer>(8080);
+ g_pSessionManager = std::make_unique<CSessionManager>();
+ g_pSessionManager->enterLoop();
+ return 0;
+}
diff --git a/src/server.cpp b/src/server.cpp
new file mode 100644
index 0000000..f85d1fc
--- /dev/null
+++ b/src/server.cpp
@@ -0,0 +1,50 @@
+#include "server.hpp"
+#include "sessionManager.hpp"
+#include <cstring>
+#include <print>
+#include <sys/socket.h>
+
+CServer::CServer(uint16_t port)
+ : m_sockfd(Hyprutils::OS::CFileDescriptor{socket(AF_INET, SOCK_STREAM, 0)}) {
+ if (!m_sockfd.isValid())
+ throw std::runtime_error("Failed to create socket");
+
+ memset(&m_addr, 0, sizeof(m_addr));
+ m_addr.sin_family = AF_INET;
+ m_addr.sin_port = htons(port);
+ m_addr.sin_addr.s_addr = INADDR_ANY;
+ m_dBind = bind(m_sockfd.get(), reinterpret_cast<sockaddr *>(&m_addr), sizeof(m_addr));
+ m_dListen = listen(m_sockfd.get(), 5);
+ m_dBind < 0 || m_dListen < 0 ? throw std::runtime_error("Failed to bind or listen") : std::println("Server started on port: {}", port);
+
+ // char buffer[1024] = {0};
+ // int clientSocket = accept(m_sockfd.get(), nullptr, nullptr);
+ // recv(clientSocket, buffer, sizeof(buffer), 0);
+ // std::println("Message from client: {}", buffer);
+};
+
+// void CServer::run() {
+// while (true) {
+// char buffer[1024] = {0};
+// int clientSocket = accept(m_sockfd.get(), nullptr, nullptr);
+// recv(clientSocket, buffer, sizeof(buffer), 0);
+// std::println("Message from client: {}", buffer);
+// }
+// }
+
+CServer::~CServer() {
+ m_sockfd.reset();
+}
+
+
+void CServer::log(const eLogLevel loglevel, const std::string &message) const {
+ std::println("[{}]: {}", "a", message);
+}
+
+bool CServer::isValid() {
+ return m_sockfd.isValid() && m_dBind >= 0 && m_dListen >= 0;
+}
+
+Hyprutils::OS::CFileDescriptor CServer::getSocket() const {
+ return m_sockfd.duplicate();
+}
diff --git a/src/server.hpp b/src/server.hpp
new file mode 100644
index 0000000..e100266
--- /dev/null
+++ b/src/server.hpp
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "FileDescriptor.hpp"
+#include "log.hpp"
+#include <netinet/in.h>
+#include <string>
+#include <memory>
+
+class CServer {
+ public:
+ CServer(uint16_t port);
+ ~CServer();
+ void log(const eLogLevel loglevel, const std::string &message) const;
+ bool isValid();
+ Hyprutils::OS::CFileDescriptor getSocket() const;
+
+ private:
+ Hyprutils::OS::CFileDescriptor m_sockfd;
+ sockaddr_in m_addr;
+ int m_dBind = -1;
+ int m_dListen = -1;
+};
+inline std::unique_ptr<CServer> g_pServer;
diff --git a/src/session.cpp b/src/session.cpp
new file mode 100644
index 0000000..da7ebf6
--- /dev/null
+++ b/src/session.cpp
@@ -0,0 +1,112 @@
+#include "session.hpp"
+#include <cmath>
+#include <ostream>
+#include <sys/socket.h>
+#include <print>
+#include <cerrno>
+#include <cstring>
+
+CSession::CSession(Hyprutils::OS::CFileDescriptor sockfd) : m_sockfd(std::move(sockfd)) {
+ if (!m_sockfd.isValid())
+ throw std::runtime_error("Failed to create socket");
+}
+
+CSession::~CSession() {
+ m_sockfd.reset();
+}
+
+void CSession::onConnect() const {
+ std::println("Client connected");
+}
+
+void CSession::onDisconnect() const {
+ std::println("Client disconnected");
+}
+
+void CSession::onErrno() const {
+ std::println("Error: {}", strerror(errno));
+}
+
+void CSession::onRecv(SRecvData &data) const {
+ std::println("Received: {}", data.data, data.dataSize);
+}
+
+void CSession::recvManager() {
+ while (true) {
+ CSession::SRecvData recvData = read();
+ if (!recvData.good) {
+ break;
+ }
+ }
+}
+
+CSession::SRecvData CSession::read() {
+ SRecvData recvData;
+ ssize_t dataSize = recv(m_sockfd.get(), recvData.data, recvData.dataSize, 0);
+ if (dataSize < 0) {
+ recvData.good = false;
+ onErrno();
+ }
+ if (dataSize == 0) {
+ recvData.good = false;
+ onDisconnect();
+ }
+ onRecv(recvData);
+ return recvData;
+}
+
+CSession::SRecvData CSession::read(std::string &msg) {
+ write(msg);
+ SRecvData recvData;
+ ssize_t dataSize = recv(m_sockfd.get(), recvData.data, recvData.dataSize, 0);
+
+ if (dataSize > 0) {
+ recvData.good = false;
+
+ if (dataSize < 0)
+ onErrno();
+
+ if (dataSize == 0)
+ onDisconnect();
+ }
+ onRecv(recvData);
+
+ return recvData;
+}
+
+void CSession::run() {
+ onConnect();
+ // std::jthread recvThread(&CSession::recvManager, this);
+ registerSession();
+ recvManager();
+}
+
+bool CSession::registerSession() {
+ SRecvData rervData = read((std::string&)"Name: ");
+ if (!rervData.good) {
+ return false;
+ }
+ m_name = rervData.data;
+
+ std::println("Client registered as: {}", m_name);
+
+ return true;
+}
+
+bool CSession::isValid() const {
+ return m_sockfd.isValid() && !m_name.empty();
+}
+
+bool CSession::write(const std::string &msg) const {
+ bool bad = false;
+ ssize_t bytes_sent = send(m_sockfd.get(), msg.c_str(), msg.size(), 0);
+ if (bytes_sent < 0) {
+ bad = true;
+ onErrno();
+ }
+ return bad;
+}
+
+std::string CSession::getName() const {
+ return m_name;
+}
diff --git a/src/session.hpp b/src/session.hpp
new file mode 100644
index 0000000..8e0859c
--- /dev/null
+++ b/src/session.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "FileDescriptor.hpp"
+#include <string>
+
+class CSession {
+ public:
+ struct SRecvData {
+ char data[1024] = {0};
+ ssize_t dataSize = sizeof(data);
+ bool good = true;
+ };
+ CSession(Hyprutils::OS::CFileDescriptor m_sockfd);
+ ~CSession();
+ std::string getName() const;
+ bool isValid() const;
+ SRecvData read();
+ SRecvData read(std::string &msg);
+ bool write(const std::string &msg) const;
+ void run();
+
+ private:
+ Hyprutils::OS::CFileDescriptor m_sockfd;
+ std::string m_name;
+ void recvManager();
+ bool registerSession();
+void onConnect() const;
+void onDisconnect() const;
+void onErrno() const;
+void onRecv(SRecvData &data) const;
+ friend class CSessionManager;
+};
diff --git a/src/sessionManager.cpp b/src/sessionManager.cpp
new file mode 100644
index 0000000..a249f61
--- /dev/null
+++ b/src/sessionManager.cpp
@@ -0,0 +1,29 @@
+#include "sessionManager.hpp"
+#include "session.hpp"
+#include "server.hpp"
+#include <print>
+
+CSessionManager::CSessionManager() = default;
+
+CSessionManager::~CSessionManager() {
+ for (auto &[thread, session] : m_vSessions) {
+ thread.join();
+ }
+}
+
+void CSessionManager::newSession(Hyprutils::OS::CFileDescriptor sockfd) {
+ std::shared_ptr session = std::make_shared<CSession>(std::move(sockfd));
+ m_vSessions.emplace_back(std::jthread(&CSession::run, session), std::move(session));
+}
+
+void CSessionManager::enterLoop() {
+ while (true) {
+ newSession(Hyprutils::OS::CFileDescriptor{accept(g_pServer->getSocket().take(), nullptr, nullptr) /* awaits new client/session */});
+ }
+}
+
+void CSessionManager::broadcast(const std::string &msg) const {
+ for (const auto &[thread, session] : m_vSessions) {
+ session->write(msg);
+ }
+}
diff --git a/src/sessionManager.hpp b/src/sessionManager.hpp
new file mode 100644
index 0000000..0e6eef3
--- /dev/null
+++ b/src/sessionManager.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "session.hpp"
+#include <memory>
+#include <thread>
+#include <vector>
+
+class CSessionManager {
+public:
+ CSessionManager();
+ ~CSessionManager();
+ void enterLoop();
+ void newSession(Hyprutils::OS::CFileDescriptor sockfd);
+ void broadcast(const std::string &message) const;
+ void kick(const CSession *session) const;
+ void addSession(const CSession &session);
+private:
+ std::vector<std::pair<std::jthread, std::shared_ptr<CSession>>> m_vSessions;
+};
+inline std::unique_ptr<CSessionManager> g_pSessionManager;