diff options
| author | littleblack111 <littleblack11111@gmail.com> | 2025-03-04 23:29:39 +0800 |
|---|---|---|
| committer | littleblack111 <littleblack11111@gmail.com> | 2025-03-04 23:29:39 +0800 |
| commit | 09d899230c3d31bd405cc3407c6c372ab9091e98 (patch) | |
| tree | c6a34436ec3d1a3e99dde3b97dea820d85dc37b9 /src | |
| parent | bf95e496e2f03fcffb9c6043307f13c99a18d8d0 (diff) | |
refactor!: python -> c++
Diffstat (limited to 'src')
| -rw-r--r-- | src/FileDescriptor.cpp | 89 | ||||
| -rw-r--r-- | src/FileDescriptor.hpp | 39 | ||||
| -rw-r--r-- | src/log.hpp | 13 | ||||
| -rw-r--r-- | src/main.cpp | 9 | ||||
| -rw-r--r-- | src/server.cpp | 50 | ||||
| -rw-r--r-- | src/server.hpp | 23 | ||||
| -rw-r--r-- | src/session.cpp | 112 | ||||
| -rw-r--r-- | src/session.hpp | 32 | ||||
| -rw-r--r-- | src/sessionManager.cpp | 29 | ||||
| -rw-r--r-- | src/sessionManager.hpp | 20 |
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; |
