diff --git a/CMakeLists.txt b/CMakeLists.txt index d4e640f..bca8dbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.16) # If MAJOR is 0, and MINOR > 0, Version is BETA project(ColumnLynx - VERSION 0.0.6 + VERSION 0.1.0 LANGUAGES CXX ) diff --git a/include/columnlynx/common/net/session_registry.hpp b/include/columnlynx/common/net/session_registry.hpp index 11449ae..762dc05 100644 --- a/include/columnlynx/common/net/session_registry.hpp +++ b/include/columnlynx/common/net/session_registry.hpp @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include #include #include @@ -49,107 +52,36 @@ namespace ColumnLynx::Net { static SessionRegistry& getInstance() { static SessionRegistry instance; return instance; } // Insert or replace a session entry - void put(uint64_t sessionID, std::shared_ptr state) { - std::unique_lock lock(mMutex); - mSessions[sessionID] = std::move(state); - mIPSessions[mSessions[sessionID]->clientTunIP] = mSessions[sessionID]; - } + void put(uint64_t sessionID, std::shared_ptr state); // Lookup a session entry by session ID - std::shared_ptr get(uint64_t sessionID) const { - std::shared_lock lock(mMutex); - auto it = mSessions.find(sessionID); - return (it == mSessions.end()) ? nullptr : it->second; - } + std::shared_ptr get(uint64_t sessionID) const; // Lookup a session entry by IPv4 - std::shared_ptr getByIP(uint32_t ip) const { - std::shared_lock lock(mMutex); - auto it = mIPSessions.find(ip); - return (it == mIPSessions.end()) ? nullptr : it->second; - } + std::shared_ptr getByIP(uint32_t ip) const; // Get a snapshot of the Session Registry - std::unordered_map> snapshot() const { - std::unordered_map> snap; - std::shared_lock lock(mMutex); - snap = mSessions; - return snap; - } + std::unordered_map> snapshot() const; // Remove a session by ID - void erase(uint64_t sessionID) { - std::unique_lock lock(mMutex); - mSessions.erase(sessionID); - } + void erase(uint64_t sessionID); // Cleanup expired sessions - void cleanupExpired() { - std::unique_lock lock(mMutex); - auto now = std::chrono::steady_clock::now(); - for (auto it = mSessions.begin(); it != mSessions.end(); ) { - if (it->second && it->second->expires <= now) { - it = mSessions.erase(it); - } else { - ++it; - } - } - - for (auto it = mIPSessions.begin(); it != mIPSessions.end(); ) { - if (it->second && it->second->expires <= now) { - it = mIPSessions.erase(it); - } else { - ++it; - } - } - } + void cleanupExpired(); // Get the number of registered sessions - int size() const { - std::shared_lock lock(mMutex); - return static_cast(mSessions.size()); - } + int size() const; // IP management // Get the lowest available IPv4 address; Returns 0 if none available - uint32_t getFirstAvailableIP(uint32_t baseIP, uint8_t mask) const { - std::shared_lock lock(mMutex); + uint32_t getFirstAvailableIP(uint32_t baseIP, uint8_t mask) const; - uint32_t hostCount = (1u << (32 - mask)); - uint32_t firstHost = 2; - uint32_t lastHost = hostCount - 2; + // Lock IP to session ID; Do NOT call before put() - You will segfault! + void lockIP(uint64_t sessionID, uint32_t ip); - for (uint32_t offset = firstHost; offset <= lastHost; offset++) { - uint32_t candidateIP = baseIP + offset; - if (mIPSessions.find(candidateIP) == mIPSessions.end()) { - return candidateIP; - } - } - - return 0; - } - - void lockIP(uint64_t sessionID, uint32_t ip) { - std::unique_lock lock(mMutex); - mSessionIPs[sessionID] = ip; - - /*if (mIPSessions.find(sessionID) == mIPSessions.end()) { - Utils::debug("yikes"); - }*/ - mIPSessions[ip] = mSessions.find(sessionID)->second; - } - - void deallocIP(uint64_t sessionID) { - std::unique_lock lock(mMutex); - - auto it = mSessionIPs.find(sessionID); - if (it != mSessionIPs.end()) { - uint32_t ip = it->second; - mIPSessions.erase(ip); - mSessionIPs.erase(it); - } - } + // Unlock IP from session ID + void deallocIP(uint64_t sessionID); private: mutable std::shared_mutex mMutex; diff --git a/src/common/session_registry.cpp b/src/common/session_registry.cpp new file mode 100644 index 0000000..1c91445 --- /dev/null +++ b/src/common/session_registry.cpp @@ -0,0 +1,100 @@ +// session_registry.cpp - Session Registry for ColumnLynx +// Copyright (C) 2025 DcruBro +// Distributed under the terms of the GNU General Public License, either version 2 only or version 3. See LICENSES/ for details. + +#include + +namespace ColumnLynx::Net { + void SessionRegistry::put(uint64_t sessionID, std::shared_ptr state) { + std::unique_lock lock(mMutex); + mSessions[sessionID] = std::move(state); + mIPSessions[mSessions[sessionID]->clientTunIP] = mSessions[sessionID]; + } + + std::shared_ptr SessionRegistry::get(uint64_t sessionID) const { + std::shared_lock lock(mMutex); + auto it = mSessions.find(sessionID); + return (it == mSessions.end()) ? nullptr : it->second; + } + + std::shared_ptr SessionRegistry::getByIP(uint32_t ip) const { + std::shared_lock lock(mMutex); + auto it = mIPSessions.find(ip); + return (it == mIPSessions.end()) ? nullptr : it->second; + } + + std::unordered_map> SessionRegistry::snapshot() const { + std::unordered_map> snap; + std::shared_lock lock(mMutex); + snap = mSessions; + return snap; + } + + void SessionRegistry::erase(uint64_t sessionID) { + std::unique_lock lock(mMutex); + mSessions.erase(sessionID); + } + + void SessionRegistry::cleanupExpired() { + std::unique_lock lock(mMutex); + auto now = std::chrono::steady_clock::now(); + for (auto it = mSessions.begin(); it != mSessions.end(); ) { + if (it->second && it->second->expires <= now) { + it = mSessions.erase(it); + } else { + ++it; + } + } + + for (auto it = mIPSessions.begin(); it != mIPSessions.end(); ) { + if (it->second && it->second->expires <= now) { + it = mIPSessions.erase(it); + } else { + ++it; + } + } + } + + int SessionRegistry::size() const { + std::shared_lock lock(mMutex); + return static_cast(mSessions.size()); + } + + uint32_t SessionRegistry::getFirstAvailableIP(uint32_t baseIP, uint8_t mask) const { + std::shared_lock lock(mMutex); + + uint32_t hostCount = (1u << (32 - mask)); + uint32_t firstHost = 2; + uint32_t lastHost = hostCount - 2; + + for (uint32_t offset = firstHost; offset <= lastHost; offset++) { + uint32_t candidateIP = baseIP + offset; + if (mIPSessions.find(candidateIP) == mIPSessions.end()) { + return candidateIP; + } + } + + return 0; + } + + void SessionRegistry::lockIP(uint64_t sessionID, uint32_t ip) { + std::unique_lock lock(mMutex); + mSessionIPs[sessionID] = ip; + + /*if (mIPSessions.find(sessionID) == mIPSessions.end()) { + Utils::debug("yikes"); + }*/ + mIPSessions[ip] = mSessions.find(sessionID)->second; + } + + void SessionRegistry::deallocIP(uint64_t sessionID) { + std::unique_lock lock(mMutex); + + auto it = mSessionIPs.find(sessionID); + if (it != mSessionIPs.end()) { + uint32_t ip = it->second; + mIPSessions.erase(ip); + mSessionIPs.erase(it); + } + } +} \ No newline at end of file diff --git a/src/common/utils.cpp b/src/common/utils.cpp index 7a1c992..73c7c51 100644 --- a/src/common/utils.cpp +++ b/src/common/utils.cpp @@ -49,7 +49,7 @@ namespace ColumnLynx::Utils { } std::string getVersion() { - return "a0.6"; + return "b0.1"; } unsigned short serverPort() { diff --git a/src/server/server/net/tcp/tcp_connection.cpp b/src/server/net/tcp/tcp_connection.cpp similarity index 100% rename from src/server/server/net/tcp/tcp_connection.cpp rename to src/server/net/tcp/tcp_connection.cpp diff --git a/src/server/server/net/tcp/tcp_server.cpp b/src/server/net/tcp/tcp_server.cpp similarity index 100% rename from src/server/server/net/tcp/tcp_server.cpp rename to src/server/net/tcp/tcp_server.cpp diff --git a/src/server/server/net/udp/udp_server.cpp b/src/server/net/udp/udp_server.cpp similarity index 100% rename from src/server/server/net/udp/udp_server.cpp rename to src/server/net/udp/udp_server.cpp