diff --git a/cpp_impl/src/UDPC_Defines.hpp b/cpp_impl/src/UDPC_Defines.hpp index f6f8ab6..5fc3a12 100644 --- a/cpp_impl/src/UDPC_Defines.hpp +++ b/cpp_impl/src/UDPC_Defines.hpp @@ -6,6 +6,7 @@ #define UDPC_GOOD_MODE_SEND_INTERVAL (1.0f / 30.0f) #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_ID_CONNECT 0x80000000 #define UDPC_ID_PING 0x40000000 @@ -18,6 +19,7 @@ #include #include #include +#include #include "TSQueue.hpp" #include "UDPConnection.h" @@ -27,8 +29,14 @@ namespace UDPC { static uint32_t LOCAL_ADDR = 0; 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); + +struct Context; struct ConnectionData { + ConnectionData(); + ConnectionData(bool isServer, Context *ctx); + /* * 0 - trigger send * 1 - is good mode @@ -59,9 +67,11 @@ struct Context { Context(bool isThreaded); uint_fast32_t _contextIdentifier; + char recvBuf[UDPC_PACKET_MAX_SIZE]; /* * 0 - is threaded * 1 - is client + * 2 - is accepting new connections */ std::bitset<32> flags; std::atomic_bool isAcceptNewConnections; @@ -73,9 +83,13 @@ struct Context { struct sockaddr_in socketInfo; std::chrono::steady_clock::time_point lastUpdated; + // ipv4 address to ConnectionData std::unordered_map conMap; + // id to ipv4 address std::unordered_map idMap; + std::default_random_engine rng_engine; + }; // struct Context Context *verifyContext(void *ctx); @@ -92,6 +106,8 @@ bool isBigEndian(); void preparePacket(char *data, uint32_t protocolID, uint32_t conID, uint32_t rseq, uint32_t ack, uint32_t *seqID, int flags); +uint32_t generateConnectionID(Context &ctx); + } // namespace UDPC #endif diff --git a/cpp_impl/src/UDPConnection.cpp b/cpp_impl/src/UDPConnection.cpp index 2407077..8cfd391 100644 --- a/cpp_impl/src/UDPConnection.cpp +++ b/cpp_impl/src/UDPConnection.cpp @@ -7,14 +7,36 @@ #include #include +UDPC::ConnectionData::ConnectionData() : +flags(), +sentPkts(), +sendPkts(UDPC_QUEUED_PKTS_MAX_SIZE), +priorityPkts(UDPC_QUEUED_PKTS_MAX_SIZE), +received(std::chrono::steady_clock::now()), +sent(std::chrono::steady_clock::now()) +{ +} + +UDPC::ConnectionData::ConnectionData(bool isServer, Context *ctx) : +UDPC::ConnectionData::ConnectionData() +{ + if(isServer) { + flags.set(0); + flags.set(3); + id = UDPC::generateConnectionID(*ctx); + flags.set(4); + } +} + UDPC::Context::Context(bool isThreaded) : _contextIdentifier(UDPC_CONTEXT_IDENTIFIER), flags(), isAcceptNewConnections(true), protocolID(UDPC_DEFAULT_PROTOCOL_ID), #ifndef NDEBUG - loggingType(INFO) + loggingType(INFO), #else - loggingType(WARNING) + loggingType(WARNING), #endif + rng_engine() { if(isThreaded) { flags.set(0); @@ -29,6 +51,8 @@ UDPC::Context::Context(bool isThreaded) UDPC::LOCAL_ADDR = 0x0100007F; } } + + rng_engine.seed(std::chrono::system_clock::now().time_since_epoch().count()); } UDPC::Context *UDPC::verifyContext(void *ctx) { @@ -84,6 +108,15 @@ void UDPC::preparePacket(char *data, uint32_t protocolID, uint32_t conID, std::memcpy(data + 16, &temp, 4); } +uint32_t UDPC::generateConnectionID(Context &ctx) { + auto dist = std::uniform_int_distribution(0, 0xFFFFFFFF); + uint32_t id = dist(ctx.rng_engine); + while(ctx.idMap.find(id) != ctx.idMap.end()) { + id = dist(ctx.rng_engine); + } + return id; +} + void *UDPC_init(uint16_t listenPort, uint32_t listenAddr, int isClient) { UDPC::Context *ctx = new UDPC::Context(false); @@ -423,7 +456,58 @@ void UDPC_update(void *ctx) { } } - // TODO receive packet + // receive packet +#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS + typedef int socklen_t; +#endif + struct sockaddr_in receivedData; + socklen_t receivedDataSize = sizeof(receivedData); + int bytes = recvfrom( + c->socketHandle, + c->recvBuf, + UDPC_PACKET_MAX_SIZE, + 0, + (struct sockaddr*) &receivedData, + &receivedDataSize); + + if(bytes == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { + // no packet was received + return; + } else if(bytes < 20) { + // packet size is too small, invalid packet + // TODO log this + return; + } + + uint32_t temp = ntohl(*((uint32_t*)c->recvBuf)); + if(temp != c->protocolID) { + // Invalid protocol id in packet + // TODO log this + return; + } + + uint32_t conID = ntohl(*((uint32_t*)(c->recvBuf + 4))); + uint32_t seqID = ntohl(*((uint32_t*)(c->recvBuf + 8))); + uint32_t rseq = ntohl(*((uint32_t*)(c->recvBuf + 12))); + uint32_t ack = htonl(*((uint32_t*)(c->recvBuf + 16))); + + bool isConnect = conID & UDPC_ID_CONNECT; + bool isPing = conID & UDPC_ID_PING; + bool isNotRecChecked = conID & UDPC_ID_NO_REC_CHK; + bool isResending = conID & UDPC_ID_RESENDING; + conID &= 0x0FFFFFFF; + + if(isConnect && c->flags.test(2)) { + // is connect packet and is accepting new connections + if(!c->flags.test(1) + && c->conMap.find(receivedData.sin_addr.s_addr) == c->conMap.end()) { + // is receiving as server, connection did not already exist + // TODO log establishing connection with client peer + UDPC::ConnectionData newConnection(true, c); + // TODO update idMap and conMap with new CD + // TODO impl establish connection with client peer as server + } + } // TODO impl }