Test Fix panic on disconnect

This commit is contained in:
2025-12-29 19:02:22 +01:00
parent 072fb69a4a
commit ae507c3fb9
4 changed files with 27 additions and 10 deletions

View File

@@ -186,7 +186,7 @@ namespace ColumnLynx::Utils {
// Panic the main thread and instantly halt execution. This produces a stack trace dump. Do not use by itself, throw an error instead. // Panic the main thread and instantly halt execution. This produces a stack trace dump. Do not use by itself, throw an error instead.
static void panic(const std::string& reason) { static void panic(const std::string& reason) {
std::cerr << "\n***\033[31m MAIN THREAD PANIC! \033[0m***\n"; std::cerr << "\n***\033[31m MASTER THREAD PANIC! \033[0m***\n";
std::cerr << "Reason: " << reason << "\n"; std::cerr << "Reason: " << reason << "\n";
std::cerr << "Dumping panic trace...\n"; std::cerr << "Dumping panic trace...\n";

View File

@@ -76,5 +76,6 @@ namespace ColumnLynx::Net::TCP {
std::chrono::steady_clock::time_point mLastHeartbeatReceived; std::chrono::steady_clock::time_point mLastHeartbeatReceived;
std::chrono::steady_clock::time_point mLastHeartbeatSent; std::chrono::steady_clock::time_point mLastHeartbeatSent;
int mMissedHeartbeats = 0; int mMissedHeartbeats = 0;
std::string mRemoteIP; // Cached remote IP to avoid calling remote_endpoint() on closed sockets
}; };
} }

View File

@@ -78,6 +78,17 @@ int main(int argc, char** argv) {
std::shared_ptr<VirtualInterface> tun = std::make_shared<VirtualInterface>(optionsObj["interface"].as<std::string>()); std::shared_ptr<VirtualInterface> tun = std::make_shared<VirtualInterface>(optionsObj["interface"].as<std::string>());
log("Using virtual interface: " + tun->getName()); log("Using virtual interface: " + tun->getName());
// Get network configuration from config file
std::string networkString = config.find("NETWORK") != config.end() ? config.find("NETWORK")->second : "10.10.0.0";
uint8_t subnetMask = config.find("SUBNET_MASK") != config.end() ? std::stoi(config.find("SUBNET_MASK")->second) : 24;
uint32_t baseIP = VirtualInterface::stringToIpv4(networkString);
uint32_t serverIP = baseIP + 1; // e.g., 10.10.0.1
// Configure the server's TUN interface with point-to-point mode
// Server acts as a peer to clients, so use point-to-point configuration
tun->configureIP(serverIP, baseIP, subnetMask, 1420);
log("Configured TUN interface with IP " + VirtualInterface::ipv4ToString(serverIP) + " peer " + VirtualInterface::ipv4ToString(baseIP));
// Generate a temporary keypair, replace with actual CA signed keys later (Note, these are stored in memory) // Generate a temporary keypair, replace with actual CA signed keys later (Note, these are stored in memory)
std::shared_ptr<LibSodiumWrapper> sodiumWrapper = std::make_shared<LibSodiumWrapper>(); std::shared_ptr<LibSodiumWrapper> sodiumWrapper = std::make_shared<LibSodiumWrapper>();
@@ -134,7 +145,7 @@ int main(int argc, char** argv) {
} }
const uint8_t* ip = packet.data(); const uint8_t* ip = packet.data();
uint32_t dstIP = ntohl(*(uint32_t*)(ip + 16)); // IPv4 destination address offset in IPv6-mapped header uint32_t dstIP = ntohl(*(uint32_t*)(ip + 16)); // IPv4 destination address
auto session = SessionRegistry::getInstance().getByIP(dstIP); auto session = SessionRegistry::getInstance().getByIP(dstIP);
if (!session) { if (!session) {

View File

@@ -6,21 +6,28 @@
namespace ColumnLynx::Net::TCP { namespace ColumnLynx::Net::TCP {
void TCPConnection::start() { void TCPConnection::start() {
try {
// Cache the remote IP early to avoid calling remote_endpoint() on closed sockets later
mRemoteIP = mHandler->socket().remote_endpoint().address().to_string();
} catch (const std::exception& e) {
mRemoteIP = "unknown";
Utils::warn("Failed to get remote endpoint: " + std::string(e.what()));
}
mHandler->onMessage([this](AnyMessageType type, const std::string& data) { mHandler->onMessage([this](AnyMessageType type, const std::string& data) {
mHandleMessage(static_cast<ClientMessageType>(MessageHandler::toUint8(type)), data); mHandleMessage(static_cast<ClientMessageType>(MessageHandler::toUint8(type)), data);
}); });
mHandler->onDisconnect([this](const asio::error_code& ec) { mHandler->onDisconnect([this](const asio::error_code& ec) {
// Peer has closed; finalize locally without sending RST // Peer has closed; finalize locally without sending RST
std::string ip = mHandler->socket().remote_endpoint().address().to_string(); Utils::log("Client disconnected: " + mRemoteIP + " - " + ec.message());
Utils::log("Client disconnected: " + ip + " - " + ec.message());
asio::error_code ec2; asio::error_code ec2;
mHandler->socket().close(ec2); mHandler->socket().close(ec2);
SessionRegistry::getInstance().erase(mConnectionSessionID); SessionRegistry::getInstance().erase(mConnectionSessionID);
SessionRegistry::getInstance().deallocIP(mConnectionSessionID); SessionRegistry::getInstance().deallocIP(mConnectionSessionID);
Utils::log("Closed connection to " + ip); Utils::log("Closed connection to " + mRemoteIP);
if (mOnDisconnect) { if (mOnDisconnect) {
mOnDisconnect(shared_from_this()); mOnDisconnect(shared_from_this());
@@ -31,7 +38,7 @@ namespace ColumnLynx::Net::TCP {
mStartHeartbeat(); mStartHeartbeat();
// Placeholder for message handling setup // Placeholder for message handling setup
Utils::log("Client connected: " + mHandler->socket().remote_endpoint().address().to_string()); Utils::log("Client connected: " + mRemoteIP);
} }
void TCPConnection::sendMessage(ServerMessageType type, const std::string& data) { void TCPConnection::sendMessage(ServerMessageType type, const std::string& data) {
@@ -45,8 +52,6 @@ namespace ColumnLynx::Net::TCP {
} }
void TCPConnection::disconnect(bool echo) { void TCPConnection::disconnect(bool echo) {
std::string ip = mHandler->socket().remote_endpoint().address().to_string();
if (echo) { if (echo) {
mHandler->sendMessage(ServerMessageType::GRACEFUL_DISCONNECT, "Server initiated disconnect."); mHandler->sendMessage(ServerMessageType::GRACEFUL_DISCONNECT, "Server initiated disconnect.");
} }
@@ -58,7 +63,7 @@ namespace ColumnLynx::Net::TCP {
Utils::error("Error during socket shutdown: " + ec.message()); Utils::error("Error during socket shutdown: " + ec.message());
} }
// Do not close immediately; final cleanup happens in onDisconnect // Do not close immediately; final cleanup happens in onDisconnect
Utils::log("Initiated graceful disconnect (half-close) to " + ip); Utils::log("Initiated graceful disconnect (half-close) to " + mRemoteIP);
} }
uint64_t TCPConnection::getSessionID() const { uint64_t TCPConnection::getSessionID() const {
@@ -102,7 +107,7 @@ namespace ColumnLynx::Net::TCP {
} }
void TCPConnection::mHandleMessage(ClientMessageType type, const std::string& data) { void TCPConnection::mHandleMessage(ClientMessageType type, const std::string& data) {
std::string reqAddr = mHandler->socket().remote_endpoint().address().to_string(); std::string& reqAddr = mRemoteIP;
switch (type) { switch (type) {
case ClientMessageType::HANDSHAKE_INIT: { case ClientMessageType::HANDSHAKE_INIT: {