diff --git a/cpp_impl/src/UDPC_Defines.hpp b/cpp_impl/src/UDPC_Defines.hpp index 3a70e86..0f3c4fd 100644 --- a/cpp_impl/src/UDPC_Defines.hpp +++ b/cpp_impl/src/UDPC_Defines.hpp @@ -7,6 +7,7 @@ #define UDPC_BAD_MODE_SEND_INTERVAL (1.0f / 10.0f) #define UDPC_SENT_PKTS_MAX_SIZE 33 #define UDPC_QUEUED_PKTS_MAX_SIZE 32 +#define UDPC_GOOD_RTT_LIMIT_SEC 0.25f #define UDPC_ID_CONNECT 0x80000000 #define UDPC_ID_PING 0x40000000 @@ -19,7 +20,9 @@ #include #include #include +#include #include +#include #include "TSQueue.hpp" #include "UDPConnection.h" @@ -31,8 +34,18 @@ static const auto INIT_PKT_INTERVAL_DT = std::chrono::seconds(5); static const auto HEARTBEAT_PKT_INTERVAL_DT = std::chrono::milliseconds(150); static const auto PACKET_TIMEOUT_TIME = std::chrono::seconds(1); +// forward declaration struct Context; +struct SentPktInfo { + typedef std::shared_ptr Ptr; + + SentPktInfo(); + + uint32_t id; + std::chrono::steady_clock::time_point sentTime; +}; + struct ConnectionData { ConnectionData(); ConnectionData(bool isServer, Context *ctx); @@ -45,6 +58,8 @@ struct ConnectionData { ConnectionData(ConnectionData&& other) = default; ConnectionData& operator=(ConnectionData&& other) = default; + void cleanupSentPkts(); + /* * 0 - trigger send * 1 - is good mode @@ -66,6 +81,8 @@ struct ConnectionData { std::deque sentPkts; TSQueue sendPkts; TSQueue priorityPkts; + // pkt id to pkt shared_ptr + std::unordered_map sentInfoMap; std::chrono::steady_clock::time_point received; std::chrono::steady_clock::time_point sent; float rtt; @@ -116,6 +133,10 @@ void preparePacket(char *data, uint32_t protocolID, uint32_t conID, uint32_t generateConnectionID(Context &ctx); +float durationToFSec( + const std::chrono::steady_clock::time_point& older, + const std::chrono::steady_clock::time_point& newer); + } // namespace UDPC #endif diff --git a/cpp_impl/src/UDPConnection.cpp b/cpp_impl/src/UDPConnection.cpp index c1731c4..5485df2 100644 --- a/cpp_impl/src/UDPConnection.cpp +++ b/cpp_impl/src/UDPConnection.cpp @@ -7,6 +7,11 @@ #include #include +UDPC::SentPktInfo::SentPktInfo() : +id(0), +sentTime(std::chrono::steady_clock::now()) +{} + UDPC::ConnectionData::ConnectionData() : flags(), timer(0.0f), @@ -33,6 +38,15 @@ UDPC::ConnectionData::ConnectionData() } } +void UDPC::ConnectionData::cleanupSentPkts() { + uint32_t id; + while(sentPkts.size() > UDPC_SENT_PKTS_MAX_SIZE) { + id = *((uint32_t*)(sentPkts.front().data + 8)); + sentInfoMap.erase(id); + sentPkts.pop_front(); + } +} + UDPC::Context::Context(bool isThreaded) : _contextIdentifier(UDPC_CONTEXT_IDENTIFIER), flags(), isAcceptNewConnections(true), protocolID(UDPC_DEFAULT_PROTOCOL_ID), @@ -122,6 +136,14 @@ uint32_t UDPC::generateConnectionID(Context &ctx) { return id; } +float UDPC::durationToFSec( + const std::chrono::steady_clock::time_point& older, + const std::chrono::steady_clock::time_point& newer) { + const auto dt = newer - older; + return (float)dt.count() + * (float)decltype(dt)::period::num / (float)decltype(dt)::period::den; +} + void *UDPC_init(uint16_t listenPort, uint32_t listenAddr, int isClient) { UDPC::Context *ctx = new UDPC::Context(false); @@ -200,21 +222,16 @@ void UDPC_update(void *ctx) { return; } + const auto prevNow = std::move(c->lastUpdated); const auto now = std::chrono::steady_clock::now(); - const auto dt = now - c->lastUpdated; - const float dt_fs = (float)dt.count() * (float)decltype(dt)::period::num / - (float)decltype(dt)::period::den; + c->lastUpdated = now; - std::chrono::steady_clock::duration temp_dt; float temp_dt_fs; { // check timed out, check good/bad mode with rtt, remove timed out std::vector removed; for(auto iter = c->conMap.begin(); iter != c->conMap.end(); ++iter) { - temp_dt = now - iter->second.received; - temp_dt_fs = (float)temp_dt.count() * - (float)decltype(temp_dt)::period::num / - (float)decltype(temp_dt)::period::den; + temp_dt_fs = UDPC::durationToFSec(iter->second.received, now); if(temp_dt_fs >= UDPC_TIMEOUT_SECONDS) { removed.push_back(iter->first); continue; @@ -384,11 +401,15 @@ void UDPC_update(void *ctx) { pInfo.receiver = iter->first; pInfo.senderPort = c->socketInfo.sin_port; pInfo.receiverPort = iter->second.port; + *((uint32_t*)(pInfo.data + 8)) = iter->second.lseq - 1; iter->second.sentPkts.push_back(std::move(pInfo)); - while(iter->second.sentPkts.size() > UDPC_SENT_PKTS_MAX_SIZE) { - iter->second.sentPkts.pop_front(); - } + iter->second.cleanupSentPkts(); + + // store other pkt info + UDPC::SentPktInfo::Ptr sentPktInfo = std::make_shared(); + sentPktInfo->id = iter->second.lseq - 1; + iter->second.sentInfoMap.insert(std::make_pair(sentPktInfo->id, sentPktInfo)); } else { // sendPkts or priorityPkts not empty UDPC_PacketInfo pInfo; @@ -440,11 +461,9 @@ void UDPC_update(void *ctx) { sentPInfo.receiverPort = iter->second.port; iter->second.sentPkts.push_back(std::move(pInfo)); - while(iter->second.sentPkts.size() > UDPC_SENT_PKTS_MAX_SIZE) { - iter->second.sentPkts.pop_front(); - } + iter->second.cleanupSentPkts(); } else { - // is not check-received, no data stored but other data is kept + // is not check-received, only id stored in data array UDPC_PacketInfo sentPInfo; sentPInfo.flags = 0x4; sentPInfo.dataSize = 0; @@ -452,12 +471,16 @@ void UDPC_update(void *ctx) { sentPInfo.receiver = iter->first; sentPInfo.senderPort = c->socketInfo.sin_port; sentPInfo.receiverPort = iter->second.port; + *((uint32_t*)(sentPInfo.data + 8)) = iter->second.lseq - 1; iter->second.sentPkts.push_back(std::move(pInfo)); - while(iter->second.sentPkts.size() > UDPC_SENT_PKTS_MAX_SIZE) { - iter->second.sentPkts.pop_front(); - } + iter->second.cleanupSentPkts(); } + + // store other pkt info + UDPC::SentPktInfo::Ptr sentPktInfo = std::make_shared(); + sentPktInfo->id = iter->second.lseq - 1; + iter->second.sentInfoMap.insert(std::make_pair(sentPktInfo->id, sentPktInfo)); } } @@ -541,6 +564,30 @@ void UDPC_update(void *ctx) { // packet is valid // TODO log received valid packet + // update rtt + for(auto sentIter = iter->second.sentPkts.rbegin(); sentIter != iter->second.sentPkts.rend(); ++sentIter) { + uint32_t id = *((uint32_t*)(sentIter->data + 8)); + if(id == rseq) { + auto sentInfoIter = iter->second.sentInfoMap.find(id); + assert(sentInfoIter != iter->second.sentInfoMap.end() + && "sentInfoMap should have known stored id"); + float diff = UDPC::durationToFSec(sentInfoIter->second->sentTime, now); + if(diff > iter->second.rtt) { + iter->second.rtt += (diff - iter->second.rtt) / 10.0f; + } else { + iter->second.rtt -= (iter->second.rtt - diff) / 10.0f; + } + + iter->second.flags.set(2, iter->second.rtt <= UDPC_GOOD_RTT_LIMIT_SEC); + + // TODO verbose log rtt + break; + } + } + + iter->second.received = now; + // TODO impl check pkt timeout + // TODO impl } diff --git a/cpp_impl/src/UDPConnection.h b/cpp_impl/src/UDPConnection.h index 5cd1cef..bbd5160 100644 --- a/cpp_impl/src/UDPConnection.h +++ b/cpp_impl/src/UDPConnection.h @@ -47,6 +47,7 @@ extern "C" { typedef enum { SILENT, ERROR, WARNING, VERBOSE, INFO } UDPC_LoggingType; typedef struct { + // id is stored at offset 8, size 4 (uint32_t) even for "empty" PktInfos char data[UDPC_PACKET_MAX_SIZE]; /* * 0x1 - connect