2019-06-06 07:02:48 +00:00
|
|
|
#include "UDPC_Defines.hpp"
|
2019-06-06 07:42:07 +00:00
|
|
|
#include "UDPConnection.h"
|
2019-06-06 07:02:48 +00:00
|
|
|
|
2019-07-25 11:51:08 +00:00
|
|
|
#include <cassert>
|
2019-07-21 05:29:31 +00:00
|
|
|
#include <chrono>
|
2019-07-25 11:51:08 +00:00
|
|
|
#include <cstring>
|
2019-07-07 05:44:37 +00:00
|
|
|
#include <optional>
|
2019-07-21 05:29:31 +00:00
|
|
|
#include <vector>
|
2019-07-07 05:44:37 +00:00
|
|
|
|
2019-08-22 11:16:07 +00:00
|
|
|
UDPC::SentPktInfo::SentPktInfo() :
|
|
|
|
id(0),
|
|
|
|
sentTime(std::chrono::steady_clock::now())
|
|
|
|
{}
|
|
|
|
|
2019-08-18 10:14:14 +00:00
|
|
|
UDPC::ConnectionData::ConnectionData() :
|
|
|
|
flags(),
|
2019-08-22 07:08:05 +00:00
|
|
|
timer(0.0f),
|
|
|
|
toggleT(30.0f),
|
|
|
|
toggleTimer(0.0f),
|
|
|
|
toggledTimer(0.0f),
|
2019-08-18 10:14:14 +00:00
|
|
|
sentPkts(),
|
|
|
|
sendPkts(UDPC_QUEUED_PKTS_MAX_SIZE),
|
|
|
|
priorityPkts(UDPC_QUEUED_PKTS_MAX_SIZE),
|
|
|
|
received(std::chrono::steady_clock::now()),
|
2019-08-22 07:08:05 +00:00
|
|
|
sent(std::chrono::steady_clock::now()),
|
|
|
|
rtt(0.0f)
|
2019-08-18 10:14:14 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-22 11:16:07 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-06 07:42:07 +00:00
|
|
|
UDPC::Context::Context(bool isThreaded)
|
|
|
|
: _contextIdentifier(UDPC_CONTEXT_IDENTIFIER), flags(),
|
|
|
|
isAcceptNewConnections(true), protocolID(UDPC_DEFAULT_PROTOCOL_ID),
|
2019-06-06 07:02:48 +00:00
|
|
|
#ifndef NDEBUG
|
2019-08-18 10:14:14 +00:00
|
|
|
loggingType(INFO),
|
2019-06-06 07:02:48 +00:00
|
|
|
#else
|
2019-08-18 10:14:14 +00:00
|
|
|
loggingType(WARNING),
|
2019-06-06 07:02:48 +00:00
|
|
|
#endif
|
2019-08-18 10:14:14 +00:00
|
|
|
rng_engine()
|
2019-06-06 07:02:48 +00:00
|
|
|
{
|
2019-07-21 04:45:42 +00:00
|
|
|
if(isThreaded) {
|
2019-06-06 07:02:48 +00:00
|
|
|
flags.set(0);
|
|
|
|
} else {
|
|
|
|
flags.reset(0);
|
|
|
|
}
|
2019-07-25 11:51:08 +00:00
|
|
|
|
|
|
|
if(UDPC::LOCAL_ADDR == 0) {
|
|
|
|
if(UDPC::isBigEndian()) {
|
|
|
|
UDPC::LOCAL_ADDR = 0x7F000001;
|
|
|
|
} else {
|
|
|
|
UDPC::LOCAL_ADDR = 0x0100007F;
|
|
|
|
}
|
|
|
|
}
|
2019-08-18 10:14:14 +00:00
|
|
|
|
|
|
|
rng_engine.seed(std::chrono::system_clock::now().time_since_epoch().count());
|
2019-06-06 07:02:48 +00:00
|
|
|
}
|
|
|
|
|
2019-07-21 04:45:42 +00:00
|
|
|
UDPC::Context *UDPC::verifyContext(void *ctx) {
|
|
|
|
if(ctx == nullptr) {
|
|
|
|
return nullptr;
|
2019-06-06 07:02:48 +00:00
|
|
|
}
|
2019-06-06 07:42:07 +00:00
|
|
|
UDPC::Context *c = (UDPC::Context *)ctx;
|
2019-07-21 04:45:42 +00:00
|
|
|
if(c->_contextIdentifier == UDPC_CONTEXT_IDENTIFIER) {
|
|
|
|
return c;
|
2019-06-06 07:02:48 +00:00
|
|
|
} else {
|
2019-07-21 04:45:42 +00:00
|
|
|
return nullptr;
|
2019-06-06 07:02:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-07 05:44:37 +00:00
|
|
|
bool UDPC::isBigEndian() {
|
2019-07-07 05:48:58 +00:00
|
|
|
static std::optional<bool> isBigEndian = std::nullopt;
|
2019-07-07 05:44:37 +00:00
|
|
|
if(isBigEndian) {
|
|
|
|
return *isBigEndian;
|
|
|
|
}
|
|
|
|
union {
|
|
|
|
uint32_t i;
|
|
|
|
char c[4];
|
2019-07-21 04:45:42 +00:00
|
|
|
} bint = {0x01020304};
|
2019-07-07 05:44:37 +00:00
|
|
|
|
|
|
|
isBigEndian = (bint.c[0] == 1);
|
|
|
|
return *isBigEndian;
|
|
|
|
}
|
|
|
|
|
2019-07-25 11:51:08 +00:00
|
|
|
void UDPC::preparePacket(char *data, uint32_t protocolID, uint32_t conID,
|
|
|
|
uint32_t rseq, uint32_t ack, uint32_t *seqID,
|
|
|
|
int flags) {
|
|
|
|
uint32_t temp;
|
|
|
|
|
|
|
|
temp = htonl(protocolID);
|
|
|
|
std::memcpy(data, &temp, 4);
|
|
|
|
temp = htonl(conID | ((flags & 0x1) != 0 ? UDPC_ID_CONNECT : 0) |
|
|
|
|
((flags & 0x2) != 0 ? UDPC_ID_PING : 0) |
|
|
|
|
((flags & 0x4) != 0 ? UDPC_ID_NO_REC_CHK : 0) |
|
|
|
|
((flags & 0x8) != 0 ? UDPC_ID_RESENDING : 0));
|
|
|
|
std::memcpy(data + 4, &temp, 4);
|
|
|
|
|
|
|
|
if(seqID) {
|
|
|
|
temp = htonl(*seqID);
|
|
|
|
++(*seqID);
|
|
|
|
} else {
|
|
|
|
temp = 0;
|
|
|
|
}
|
|
|
|
std::memcpy(data + 8, &temp, 4);
|
|
|
|
|
|
|
|
temp = htonl(rseq);
|
|
|
|
std::memcpy(data + 12, &temp, 4);
|
|
|
|
temp = htonl(ack);
|
|
|
|
std::memcpy(data + 16, &temp, 4);
|
|
|
|
}
|
|
|
|
|
2019-08-18 10:14:14 +00:00
|
|
|
uint32_t UDPC::generateConnectionID(Context &ctx) {
|
|
|
|
auto dist = std::uniform_int_distribution<uint32_t>(0, 0xFFFFFFFF);
|
|
|
|
uint32_t id = dist(ctx.rng_engine);
|
|
|
|
while(ctx.idMap.find(id) != ctx.idMap.end()) {
|
|
|
|
id = dist(ctx.rng_engine);
|
|
|
|
}
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2019-08-22 11:16:07 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-06-06 07:42:07 +00:00
|
|
|
void *UDPC_init(uint16_t listenPort, uint32_t listenAddr, int isClient) {
|
2019-06-06 07:02:48 +00:00
|
|
|
UDPC::Context *ctx = new UDPC::Context(false);
|
|
|
|
|
2019-07-21 05:29:31 +00:00
|
|
|
// create socket
|
|
|
|
ctx->socketHandle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
|
|
if(ctx->socketHandle <= 0) {
|
|
|
|
// TODO maybe different way of handling init fail
|
|
|
|
delete ctx;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// bind socket
|
|
|
|
ctx->socketInfo.sin_family = AF_INET;
|
|
|
|
ctx->socketInfo.sin_addr.s_addr =
|
|
|
|
(listenAddr == 0 ? INADDR_ANY : listenAddr);
|
|
|
|
ctx->socketInfo.sin_port = htons(listenPort);
|
|
|
|
if(bind(ctx->socketHandle, (const struct sockaddr *)&ctx->socketInfo,
|
|
|
|
sizeof(struct sockaddr_in)) < 0) {
|
|
|
|
// TODO maybe different way of handling init fail
|
|
|
|
CleanupSocket(ctx->socketHandle);
|
|
|
|
delete ctx;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-07-25 11:51:08 +00:00
|
|
|
// TODO verify this is necessary to get the listen port
|
|
|
|
if(ctx->socketInfo.sin_port == 0) {
|
|
|
|
struct sockaddr_in getInfo;
|
|
|
|
socklen_t size = sizeof(struct sockaddr_in);
|
|
|
|
if(getsockname(ctx->socketHandle, (struct sockaddr *)&getInfo, &size) == 0) {
|
|
|
|
ctx->socketInfo.sin_port = getInfo.sin_port;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-21 05:29:31 +00:00
|
|
|
// set non-blocking on socket
|
|
|
|
#if UDPC_PLATFORM == UDPC_PLATFORM_MAC || UDPC_PLATFORM == UDPC_PLATFORM_LINUX
|
|
|
|
int nonblocking = 1;
|
|
|
|
if(fcntl(ctx->socketHandle, F_SETFL, O_NONBLOCK, nonblocking) == -1) {
|
|
|
|
#elif UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
|
|
|
|
DWORD nonblocking = 1;
|
|
|
|
if(ioctlsocket(ctx->socketHandle, FIONBIO, &nonblocking) != 0) {
|
|
|
|
#else
|
|
|
|
{
|
|
|
|
#endif
|
|
|
|
// TODO maybe different way of handling init fail
|
|
|
|
CleanupSocket(ctx->socketHandle);
|
|
|
|
delete ctx;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-06-06 07:02:48 +00:00
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
2019-06-06 07:42:07 +00:00
|
|
|
void *UDPC_init_threaded_update(uint16_t listenPort, uint32_t listenAddr,
|
|
|
|
int isClient) {
|
2019-07-21 05:29:31 +00:00
|
|
|
UDPC::Context *ctx =
|
|
|
|
(UDPC::Context *)UDPC_init(listenPort, listenAddr, isClient);
|
|
|
|
if(!ctx) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
ctx->flags.set(0);
|
2019-06-06 07:02:48 +00:00
|
|
|
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UDPC_destroy(void *ctx) {
|
2019-07-21 04:45:42 +00:00
|
|
|
UDPC::Context *UDPC_ctx = UDPC::verifyContext(ctx);
|
|
|
|
if(UDPC_ctx) {
|
|
|
|
delete UDPC_ctx;
|
2019-06-06 07:02:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UDPC_update(void *ctx) {
|
2019-07-21 04:45:42 +00:00
|
|
|
UDPC::Context *c = UDPC::verifyContext(ctx);
|
2019-07-21 05:29:31 +00:00
|
|
|
if(!c || c->flags.test(0)) {
|
|
|
|
// invalid or is threaded, update should not be called
|
2019-06-06 07:02:48 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-07-21 05:29:31 +00:00
|
|
|
|
2019-08-22 11:16:07 +00:00
|
|
|
const auto prevNow = std::move(c->lastUpdated);
|
2019-07-21 05:29:31 +00:00
|
|
|
const auto now = std::chrono::steady_clock::now();
|
2019-08-22 11:16:07 +00:00
|
|
|
c->lastUpdated = now;
|
2019-07-21 05:29:31 +00:00
|
|
|
|
|
|
|
float temp_dt_fs;
|
2019-07-25 11:51:08 +00:00
|
|
|
{
|
|
|
|
// check timed out, check good/bad mode with rtt, remove timed out
|
|
|
|
std::vector<uint32_t> removed;
|
|
|
|
for(auto iter = c->conMap.begin(); iter != c->conMap.end(); ++iter) {
|
2019-08-22 11:16:07 +00:00
|
|
|
temp_dt_fs = UDPC::durationToFSec(iter->second.received, now);
|
2019-07-25 11:51:08 +00:00
|
|
|
if(temp_dt_fs >= UDPC_TIMEOUT_SECONDS) {
|
|
|
|
removed.push_back(iter->first);
|
|
|
|
continue;
|
|
|
|
// TODO log timed out connection
|
|
|
|
}
|
|
|
|
|
|
|
|
// check good/bad mode
|
|
|
|
iter->second.toggleTimer += temp_dt_fs;
|
|
|
|
iter->second.toggledTimer += temp_dt_fs;
|
|
|
|
if(iter->second.flags.test(1) && !iter->second.flags.test(2)) {
|
|
|
|
// good mode, bad rtt
|
|
|
|
// TODO log switching to bad mode
|
|
|
|
iter->second.flags.reset(1);
|
|
|
|
if(iter->second.toggledTimer <= 10.0f) {
|
|
|
|
iter->second.toggleT *= 2.0f;
|
|
|
|
}
|
|
|
|
iter->second.toggledTimer = 0.0f;
|
|
|
|
} else if(iter->second.flags.test(1)) {
|
|
|
|
// good mode, good rtt
|
|
|
|
if(iter->second.toggleTimer >= 10.0f) {
|
|
|
|
iter->second.toggleTimer = 0.0f;
|
|
|
|
iter->second.toggleT /= 2.0f;
|
|
|
|
if(iter->second.toggleT < 1.0f) {
|
|
|
|
iter->second.toggleT = 1.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if(!iter->second.flags.test(1) &&
|
|
|
|
iter->second.flags.test(2)) {
|
|
|
|
// bad mode, good rtt
|
|
|
|
if(iter->second.toggledTimer >= iter->second.toggleT) {
|
|
|
|
iter->second.toggleTimer = 0.0f;
|
|
|
|
iter->second.toggledTimer = 0.0f;
|
|
|
|
// TODO log switching to good mode
|
|
|
|
iter->second.flags.set(1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// bad mode, bad rtt
|
|
|
|
iter->second.toggledTimer = 0.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
iter->second.timer += temp_dt_fs;
|
|
|
|
if(iter->second.timer >= (iter->second.flags.test(1)
|
|
|
|
? UDPC_GOOD_MODE_SEND_INTERVAL
|
|
|
|
: UDPC_BAD_MODE_SEND_INTERVAL)) {
|
|
|
|
iter->second.timer = 0.0f;
|
|
|
|
iter->second.flags.set(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for(auto iter = removed.begin(); iter != removed.end(); ++iter) {
|
|
|
|
auto cIter = c->conMap.find(*iter);
|
|
|
|
assert(cIter != c->conMap.end());
|
|
|
|
if(cIter->second.flags.test(4)) {
|
|
|
|
c->idMap.erase(cIter->second.id);
|
|
|
|
}
|
|
|
|
c->conMap.erase(cIter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// update send (only if triggerSend flag is set)
|
2019-07-21 05:29:31 +00:00
|
|
|
for(auto iter = c->conMap.begin(); iter != c->conMap.end(); ++iter) {
|
2019-07-25 11:51:08 +00:00
|
|
|
if(!iter->second.flags.test(0)) {
|
|
|
|
continue;
|
2019-07-21 05:29:31 +00:00
|
|
|
}
|
2019-07-25 11:51:08 +00:00
|
|
|
iter->second.flags.reset(0);
|
|
|
|
|
|
|
|
if(iter->second.flags.test(3)) {
|
|
|
|
if(c->flags.test(1)) {
|
|
|
|
// is initiating connection to server
|
|
|
|
auto initDT = now - iter->second.sent;
|
|
|
|
if(initDT < UDPC::INIT_PKT_INTERVAL_DT) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
iter->second.sent = now;
|
|
|
|
|
|
|
|
std::unique_ptr<char[]> buf = std::make_unique<char[]>(20);
|
|
|
|
UDPC::preparePacket(
|
|
|
|
buf.get(),
|
|
|
|
c->protocolID,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0xFFFFFFFF,
|
|
|
|
nullptr,
|
|
|
|
0x1);
|
|
|
|
|
|
|
|
struct sockaddr_in destinationInfo;
|
|
|
|
destinationInfo.sin_family = AF_INET;
|
|
|
|
destinationInfo.sin_addr.s_addr = iter->first;
|
|
|
|
destinationInfo.sin_port = htons(iter->second.port);
|
|
|
|
long int sentBytes = sendto(
|
|
|
|
c->socketHandle,
|
|
|
|
buf.get(),
|
|
|
|
20,
|
|
|
|
0,
|
|
|
|
(struct sockaddr*) &destinationInfo,
|
|
|
|
sizeof(struct sockaddr_in));
|
|
|
|
if(sentBytes != 20) {
|
|
|
|
// TODO log fail of sending connection-initiate-packet
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// is server, initiate connection to client
|
|
|
|
iter->second.flags.reset(3);
|
|
|
|
iter->second.sent = now;
|
|
|
|
|
|
|
|
std::unique_ptr<char[]> buf = std::make_unique<char[]>(20);
|
|
|
|
UDPC::preparePacket(
|
|
|
|
buf.get(),
|
|
|
|
c->protocolID,
|
|
|
|
iter->second.id,
|
|
|
|
iter->second.rseq,
|
|
|
|
iter->second.ack,
|
|
|
|
&iter->second.lseq,
|
|
|
|
0x1);
|
|
|
|
|
|
|
|
struct sockaddr_in destinationInfo;
|
|
|
|
destinationInfo.sin_family = AF_INET;
|
|
|
|
destinationInfo.sin_addr.s_addr = iter->first;
|
|
|
|
destinationInfo.sin_port = htons(iter->second.port);
|
|
|
|
long int sentBytes = sendto(
|
|
|
|
c->socketHandle,
|
|
|
|
buf.get(),
|
|
|
|
20,
|
|
|
|
0,
|
|
|
|
(struct sockaddr*) &destinationInfo,
|
|
|
|
sizeof(struct sockaddr_in));
|
|
|
|
if(sentBytes != 20) {
|
|
|
|
// TODO log fail send init connection packet as server
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not initiating connection, send as normal on current connection
|
|
|
|
if(iter->second.sendPkts.empty() && iter->second.priorityPkts.empty()) {
|
|
|
|
// nothing in queues, send heartbeat packet
|
|
|
|
auto sentDT = now - iter->second.sent;
|
|
|
|
if(sentDT < UDPC::HEARTBEAT_PKT_INTERVAL_DT) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<char[]> buf = std::make_unique<char[]>(20);
|
|
|
|
UDPC::preparePacket(
|
|
|
|
buf.get(),
|
|
|
|
c->protocolID,
|
|
|
|
iter->second.id,
|
|
|
|
iter->second.rseq,
|
|
|
|
iter->second.ack,
|
|
|
|
&iter->second.lseq,
|
|
|
|
0);
|
|
|
|
|
|
|
|
struct sockaddr_in destinationInfo;
|
|
|
|
destinationInfo.sin_family = AF_INET;
|
|
|
|
destinationInfo.sin_addr.s_addr = iter->first;
|
|
|
|
destinationInfo.sin_port = htons(iter->second.port);
|
|
|
|
long int sentBytes = sendto(
|
|
|
|
c->socketHandle,
|
|
|
|
buf.get(),
|
|
|
|
20,
|
|
|
|
0,
|
|
|
|
(struct sockaddr*) &destinationInfo,
|
|
|
|
sizeof(struct sockaddr_in));
|
|
|
|
if(sentBytes != 20) {
|
|
|
|
// TODO log fail send heartbeat packet
|
|
|
|
}
|
|
|
|
|
|
|
|
UDPC_PacketInfo pInfo{{0}, 0, 0, 0, 0, 0, 0};
|
|
|
|
pInfo.sender = UDPC::LOCAL_ADDR;
|
|
|
|
pInfo.receiver = iter->first;
|
|
|
|
pInfo.senderPort = c->socketInfo.sin_port;
|
|
|
|
pInfo.receiverPort = iter->second.port;
|
2019-08-22 11:16:07 +00:00
|
|
|
*((uint32_t*)(pInfo.data + 8)) = iter->second.lseq - 1;
|
2019-07-21 05:29:31 +00:00
|
|
|
|
2019-07-25 11:51:08 +00:00
|
|
|
iter->second.sentPkts.push_back(std::move(pInfo));
|
2019-08-22 11:16:07 +00:00
|
|
|
iter->second.cleanupSentPkts();
|
|
|
|
|
|
|
|
// store other pkt info
|
|
|
|
UDPC::SentPktInfo::Ptr sentPktInfo = std::make_shared<UDPC::SentPktInfo>();
|
|
|
|
sentPktInfo->id = iter->second.lseq - 1;
|
|
|
|
iter->second.sentInfoMap.insert(std::make_pair(sentPktInfo->id, sentPktInfo));
|
2019-07-25 11:51:08 +00:00
|
|
|
} else {
|
|
|
|
// sendPkts or priorityPkts not empty
|
|
|
|
UDPC_PacketInfo pInfo;
|
|
|
|
bool isResending = false;
|
|
|
|
if(!iter->second.priorityPkts.empty()) {
|
|
|
|
// TODO verify getting struct copy is valid
|
|
|
|
pInfo = iter->second.priorityPkts.top();
|
|
|
|
iter->second.priorityPkts.pop();
|
|
|
|
isResending = true;
|
|
|
|
} else {
|
|
|
|
pInfo = iter->second.sendPkts.top();
|
|
|
|
iter->second.sendPkts.pop();
|
|
|
|
}
|
|
|
|
std::unique_ptr<char[]> buf = std::make_unique<char[]>(20 + pInfo.dataSize);
|
2019-08-18 09:34:45 +00:00
|
|
|
UDPC::preparePacket(
|
|
|
|
buf.get(),
|
|
|
|
c->protocolID,
|
|
|
|
iter->second.id,
|
|
|
|
iter->second.rseq,
|
|
|
|
iter->second.ack,
|
|
|
|
&iter->second.lseq,
|
|
|
|
pInfo.flags & 0xC);
|
|
|
|
std::memcpy(buf.get() + 20, pInfo.data, pInfo.dataSize);
|
|
|
|
|
|
|
|
struct sockaddr_in destinationInfo;
|
|
|
|
destinationInfo.sin_family = AF_INET;
|
|
|
|
destinationInfo.sin_addr.s_addr = iter->first;
|
|
|
|
destinationInfo.sin_port = htons(iter->second.port);
|
|
|
|
long int sentBytes = sendto(
|
|
|
|
c->socketHandle,
|
|
|
|
buf.get(),
|
|
|
|
pInfo.dataSize + 20,
|
|
|
|
0,
|
|
|
|
(struct sockaddr*) &destinationInfo,
|
|
|
|
sizeof(struct sockaddr_in));
|
|
|
|
if(sentBytes != 20 + pInfo.dataSize) {
|
|
|
|
// TODO log fail send packet
|
|
|
|
}
|
|
|
|
|
|
|
|
if((pInfo.flags & 0x4) == 0) {
|
|
|
|
// is check-received, store data in case packet gets lost
|
|
|
|
UDPC_PacketInfo sentPInfo;
|
|
|
|
std::memcpy(sentPInfo.data, buf.get(), 20 + pInfo.dataSize);
|
|
|
|
sentPInfo.flags = 0;
|
|
|
|
sentPInfo.dataSize = 20 + pInfo.dataSize;
|
|
|
|
sentPInfo.sender = UDPC::LOCAL_ADDR;
|
|
|
|
sentPInfo.receiver = iter->first;
|
|
|
|
sentPInfo.senderPort = c->socketInfo.sin_port;
|
|
|
|
sentPInfo.receiverPort = iter->second.port;
|
|
|
|
|
|
|
|
iter->second.sentPkts.push_back(std::move(pInfo));
|
2019-08-22 11:16:07 +00:00
|
|
|
iter->second.cleanupSentPkts();
|
2019-08-18 09:34:45 +00:00
|
|
|
} else {
|
2019-08-22 11:16:07 +00:00
|
|
|
// is not check-received, only id stored in data array
|
2019-08-18 09:34:45 +00:00
|
|
|
UDPC_PacketInfo sentPInfo;
|
|
|
|
sentPInfo.flags = 0x4;
|
|
|
|
sentPInfo.dataSize = 0;
|
|
|
|
sentPInfo.sender = UDPC::LOCAL_ADDR;
|
|
|
|
sentPInfo.receiver = iter->first;
|
|
|
|
sentPInfo.senderPort = c->socketInfo.sin_port;
|
|
|
|
sentPInfo.receiverPort = iter->second.port;
|
2019-08-22 11:16:07 +00:00
|
|
|
*((uint32_t*)(sentPInfo.data + 8)) = iter->second.lseq - 1;
|
2019-08-18 09:34:45 +00:00
|
|
|
|
|
|
|
iter->second.sentPkts.push_back(std::move(pInfo));
|
2019-08-22 11:16:07 +00:00
|
|
|
iter->second.cleanupSentPkts();
|
2019-08-18 09:34:45 +00:00
|
|
|
}
|
2019-08-22 11:16:07 +00:00
|
|
|
|
|
|
|
// store other pkt info
|
|
|
|
UDPC::SentPktInfo::Ptr sentPktInfo = std::make_shared<UDPC::SentPktInfo>();
|
|
|
|
sentPktInfo->id = iter->second.lseq - 1;
|
|
|
|
iter->second.sentInfoMap.insert(std::make_pair(sentPktInfo->id, sentPktInfo));
|
2019-07-21 05:29:31 +00:00
|
|
|
}
|
2019-06-06 07:02:48 +00:00
|
|
|
}
|
|
|
|
|
2019-08-18 10:14:14 +00:00
|
|
|
// 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);
|
2019-08-22 07:08:05 +00:00
|
|
|
newConnection.addr = receivedData.sin_addr.s_addr;
|
|
|
|
newConnection.port = ntohs(receivedData.sin_port);
|
|
|
|
|
|
|
|
c->idMap.insert(std::make_pair(newConnection.id, newConnection.addr));
|
|
|
|
c->conMap.insert(std::make_pair(newConnection.addr, std::move(newConnection)));
|
|
|
|
// TODO trigger event server established connection with client
|
|
|
|
} else if (c->flags.test(1)) {
|
|
|
|
// is client
|
|
|
|
auto iter = c->conMap.find(receivedData.sin_addr.s_addr);
|
|
|
|
if(iter == c->conMap.end() || !iter->second.flags.test(3)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
iter->second.flags.reset(3);
|
|
|
|
iter->second.id = conID;
|
|
|
|
iter->second.flags.set(4);
|
|
|
|
// TODO trigger event client established connection with server
|
2019-08-18 10:14:14 +00:00
|
|
|
}
|
2019-08-22 07:08:05 +00:00
|
|
|
return;
|
2019-08-18 10:14:14 +00:00
|
|
|
}
|
2019-08-18 09:34:45 +00:00
|
|
|
|
2019-08-22 07:08:05 +00:00
|
|
|
auto iter = c->conMap.find(receivedData.sin_addr.s_addr);
|
|
|
|
if(iter == c->conMap.end() || iter->second.flags.test(3)
|
|
|
|
|| !iter->second.flags.test(4) || iter->second.id != conID) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if(isPing) {
|
|
|
|
iter->second.flags.set(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// packet is valid
|
|
|
|
// TODO log received valid packet
|
|
|
|
|
2019-08-22 11:16:07 +00:00
|
|
|
// 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
|
|
|
|
|
2019-06-06 07:02:48 +00:00
|
|
|
// TODO impl
|
|
|
|
}
|
|
|
|
|
|
|
|
int UDPC_get_queue_send_available(void *ctx, uint32_t addr) {
|
2019-07-21 04:45:42 +00:00
|
|
|
UDPC::Context *c = UDPC::verifyContext(ctx);
|
|
|
|
if(!c) {
|
2019-06-06 07:02:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// TODO impl
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-06 07:42:07 +00:00
|
|
|
void UDPC_queue_send(void *ctx, uint32_t destAddr, uint16_t destPort,
|
|
|
|
uint32_t isChecked, void *data, uint32_t size) {
|
2019-07-21 04:45:42 +00:00
|
|
|
UDPC::Context *c = UDPC::verifyContext(ctx);
|
|
|
|
if(!c) {
|
2019-06-06 07:02:48 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// TODO impl
|
|
|
|
}
|
|
|
|
|
|
|
|
int UDPC_set_accept_new_connections(void *ctx, int isAccepting) {
|
2019-07-21 04:45:42 +00:00
|
|
|
UDPC::Context *c = UDPC::verifyContext(ctx);
|
|
|
|
if(!c) {
|
2019-06-06 07:02:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return c->isAcceptNewConnections.exchange(isAccepting == 0 ? false : true);
|
|
|
|
}
|
|
|
|
|
|
|
|
int UDPC_drop_connection(void *ctx, uint32_t addr, uint16_t port) {
|
2019-07-21 04:45:42 +00:00
|
|
|
UDPC::Context *c = UDPC::verifyContext(ctx);
|
|
|
|
if(!c) {
|
2019-06-06 07:02:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// TODO impl
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t UDPC_set_protocol_id(void *ctx, uint32_t id) {
|
2019-07-21 04:45:42 +00:00
|
|
|
UDPC::Context *c = UDPC::verifyContext(ctx);
|
|
|
|
if(!c) {
|
2019-06-06 07:02:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return c->protocolID.exchange(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
UDPC_LoggingType set_logging_type(void *ctx, UDPC_LoggingType loggingType) {
|
2019-07-21 04:45:42 +00:00
|
|
|
UDPC::Context *c = UDPC::verifyContext(ctx);
|
|
|
|
if(!c) {
|
2019-06-06 07:02:48 +00:00
|
|
|
return static_cast<UDPC_LoggingType>(0);
|
|
|
|
}
|
|
|
|
return static_cast<UDPC_LoggingType>(c->loggingType.exchange(loggingType));
|
|
|
|
}
|
|
|
|
|
2019-07-25 11:51:08 +00:00
|
|
|
UDPC_PacketInfo UDPC_get_received(void *ctx) {
|
2019-07-21 04:45:42 +00:00
|
|
|
UDPC::Context *c = UDPC::verifyContext(ctx);
|
|
|
|
if(!c) {
|
2019-07-25 11:51:08 +00:00
|
|
|
return UDPC_PacketInfo{{0}, 0, 0, 0, 0, 0, 0};
|
2019-06-06 07:02:48 +00:00
|
|
|
}
|
|
|
|
// TODO impl
|
2019-07-25 11:51:08 +00:00
|
|
|
return UDPC_PacketInfo{{0}, 0, 0, 0, 0, 0, 0};
|
2019-06-06 07:02:48 +00:00
|
|
|
}
|
|
|
|
|
2019-06-06 07:42:07 +00:00
|
|
|
const char *UDPC_atostr(void *ctx, uint32_t addr) {
|
2019-07-21 04:45:42 +00:00
|
|
|
UDPC::Context *c = UDPC::verifyContext(ctx);
|
|
|
|
if(!c) {
|
2019-06-06 07:02:48 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
int index = 0;
|
2019-07-21 04:45:42 +00:00
|
|
|
for(int x = 0; x < 4; ++x) {
|
2019-06-06 07:02:48 +00:00
|
|
|
unsigned char temp = (addr >> (x * 8)) & 0xFF;
|
|
|
|
|
2019-07-21 04:45:42 +00:00
|
|
|
if(temp >= 100) {
|
2019-06-06 07:02:48 +00:00
|
|
|
c->atostrBuf[index++] = '0' + temp / 100;
|
|
|
|
}
|
2019-07-21 04:45:42 +00:00
|
|
|
if(temp >= 10) {
|
2019-06-06 07:02:48 +00:00
|
|
|
c->atostrBuf[index++] = '0' + ((temp / 10) % 10);
|
|
|
|
}
|
|
|
|
c->atostrBuf[index++] = '0' + temp % 10;
|
|
|
|
|
2019-07-21 04:45:42 +00:00
|
|
|
if(x < 3) {
|
2019-06-06 07:02:48 +00:00
|
|
|
c->atostrBuf[index++] = '.';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c->atostrBuf[index] = 0;
|
|
|
|
|
|
|
|
return c->atostrBuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t UDPC_strtoa(const char *addrStr) {
|
|
|
|
uint32_t addr = 0;
|
|
|
|
uint32_t temp = 0;
|
|
|
|
uint32_t index = 0;
|
2019-07-21 04:45:42 +00:00
|
|
|
while(*addrStr != 0) {
|
|
|
|
if(*addrStr >= '0' && *addrStr <= '9') {
|
2019-06-06 07:02:48 +00:00
|
|
|
temp *= 10;
|
|
|
|
temp += *addrStr - '0';
|
2019-07-21 04:45:42 +00:00
|
|
|
} else if(*addrStr == '.' && temp <= 0xFF && index < 3) {
|
2019-07-07 05:44:37 +00:00
|
|
|
if(UDPC::isBigEndian()) {
|
|
|
|
addr |= (temp << (24 - 8 * index++));
|
|
|
|
} else {
|
|
|
|
addr |= (temp << (8 * index++));
|
|
|
|
}
|
2019-06-06 07:02:48 +00:00
|
|
|
temp = 0;
|
2019-06-06 07:42:07 +00:00
|
|
|
} else {
|
2019-06-06 07:02:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
++addrStr;
|
|
|
|
}
|
|
|
|
|
2019-07-21 04:45:42 +00:00
|
|
|
if(index == 3 && temp <= 0xFF) {
|
2019-07-07 05:44:37 +00:00
|
|
|
if(UDPC::isBigEndian()) {
|
|
|
|
addr |= temp;
|
|
|
|
} else {
|
|
|
|
addr |= temp << 24;
|
|
|
|
}
|
2019-06-06 07:02:48 +00:00
|
|
|
return addr;
|
2019-06-06 07:42:07 +00:00
|
|
|
} else {
|
2019-06-06 07:02:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|