diff --git a/include/columnlynx/client/client_session.hpp b/include/columnlynx/client/client_session.hpp index 1cb3188..bd4db0f 100644 --- a/include/columnlynx/client/client_session.hpp +++ b/include/columnlynx/client/client_session.hpp @@ -87,6 +87,10 @@ namespace ColumnLynx { void incrementSendCount() { std::unique_lock lock(mMutex); + if (mClientState->send_cnt == std::numeric_limits::max()) { + Utils::error("ClientSession: send counter overflow detected"); + return; + } mClientState->send_cnt++; } diff --git a/src/client/net/udp/udp_client.cpp b/src/client/net/udp/udp_client.cpp index dc755f7..fb55162 100644 --- a/src/client/net/udp/udp_client.cpp +++ b/src/client/net/udp/udp_client.cpp @@ -3,6 +3,8 @@ // Distributed under the terms of the GNU General Public License, either version 2 only or version 3. See LICENSES/ for details. #include +#include +#include namespace ColumnLynx::Net::UDP { void UDPClient::start() { @@ -102,7 +104,12 @@ namespace ColumnLynx::Net::UDP { if (ec) { if (ec == asio::error::operation_aborted) return; // Socket closed // Other recv error - mStartReceive(); + Utils::warn("UDPClient receive error: " + ec.message()); + // Back off briefly before restarting receive to avoid busy error loops + asio::post(mSocket.get_executor(), [this]() { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + mStartReceive(); + }); return; } diff --git a/src/common/virtual_interface.cpp b/src/common/virtual_interface.cpp index c18b2dd..6fb2ad7 100644 --- a/src/common/virtual_interface.cpp +++ b/src/common/virtual_interface.cpp @@ -213,8 +213,8 @@ static bool runCommand(const std::vector& args) { pfd.fd = mFd; pfd.events = POLLIN; - // timeout in ms; keep it small so shutdown is responsive - int ret = poll(&pfd, 1, 200); + // timeout in ms; keep it small so shutdown is responsive. Reduced for lower latency. + int ret = poll(&pfd, 1, 50); if (ret == 0) { // No data yet diff --git a/src/server/main.cpp b/src/server/main.cpp index 441546c..4f20de6 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -213,8 +213,13 @@ int main(int argc, char** argv) { // First, check if destination IP is a registered client (e.g., server responding to client or client-to-client) auto dstSession = SessionRegistry::getInstance().getByIP(dstIP); if (dstSession) { - // Destination is a registered client, forward to that client's session - udpServer->sendData(dstSession->sessionID, std::string(packet.begin(), packet.end())); + // Destination is a registered client, enforce MTU and forward to that client's session + const size_t MTU = 1420; // Enforce configured MTU; TODO: read from server config + if (packet.size() > MTU) { + Utils::warn("TUN: Dropping oversized packet (" + std::to_string(packet.size()) + " > MTU " + std::to_string(MTU) + ")"); + } else { + udpServer->sendData(dstSession->sessionID, std::string(packet.begin(), packet.end())); + } continue; } diff --git a/src/server/net/udp/udp_server.cpp b/src/server/net/udp/udp_server.cpp index d99ee1e..e786324 100644 --- a/src/server/net/udp/udp_server.cpp +++ b/src/server/net/udp/udp_server.cpp @@ -95,7 +95,23 @@ namespace ColumnLynx::Net::UDP { UDPPacketHeader hdr{}; uint8_t nonce[12]; uint32_t prefix = session->noncePrefix; - uint64_t sendCount = const_cast(session.get())->send_ctr.fetch_add(1, std::memory_order_relaxed); + // Increment send counter with overflow protection + uint64_t sendCount = 0; + { + auto ptr = const_cast(session.get()); + uint64_t old = ptr->send_ctr.load(std::memory_order_relaxed); + for (;;) { + if (old == std::numeric_limits::max()) { + Utils::error("UDP: send counter overflow for session " + std::to_string(sessionID)); + return; + } + if (ptr->send_ctr.compare_exchange_weak(old, old + 1, std::memory_order_relaxed)) { + sendCount = old; + break; + } + // old updated by compare_exchange_weak, loop + } + } memcpy(nonce, &prefix, sizeof(uint32_t)); // Prefix nonce memcpy(nonce + sizeof(uint32_t), &sendCount, sizeof(uint64_t)); // Use send count as nonce suffix to ensure uniqueness std::copy_n(nonce, 12, hdr.nonce.data());