Add some impl of UDPConnection (still WIP)
This commit is contained in:
parent
48cf70ef49
commit
ff31b0f604
3 changed files with 285 additions and 9 deletions
|
@ -31,4 +31,20 @@ static const char *UDPC_ERR_MTXFAIL_STR = "Failed to create mutex";
|
||||||
static const char *UDPC_ERR_CVFAIL_STR = "Failed to create condition variable";
|
static const char *UDPC_ERR_CVFAIL_STR = "Failed to create condition variable";
|
||||||
static const char *UDPC_ERR_THREADFAIL_STR = "Failed to create thread";
|
static const char *UDPC_ERR_THREADFAIL_STR = "Failed to create thread";
|
||||||
|
|
||||||
|
#define UDPC_CD_AMOUNT 32
|
||||||
|
|
||||||
|
#define UDPC_GOOD_MODE_SEND_INTERVAL (1.0f/30.0f)
|
||||||
|
#define UDPC_BAD_MODE_SEND_INTERVAL (1.0f/10.0f)
|
||||||
|
#define UDPC_TIMEOUT_SECONDS 10.0f
|
||||||
|
#define UDPC_HEARTBEAT_PKT_INTERVAL (15.0f/100.0f)
|
||||||
|
#define UDPC_PKT_PROTOCOL_ID 1357924680
|
||||||
|
|
||||||
|
#define UDPC_ID_CONNECT 0x80000000
|
||||||
|
#define UDPC_ID_PING 0x40000000
|
||||||
|
#define UDPC_ID_NO_REC_CHK 0x20000000
|
||||||
|
#define UDPC_ID_RESENDING 0x10000000
|
||||||
|
|
||||||
|
#define UDPC_SENT_PKTS_MAX_SIZE 34
|
||||||
|
#define UDPC_SENT_PKTS_ALLOC_SIZE 35
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "UDPConnection.h"
|
#include "UDPConnection.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
UDPC_Context* UDPC_init(uint16_t listenPort, int isClient)
|
UDPC_Context* UDPC_init(uint16_t listenPort, int isClient)
|
||||||
{
|
{
|
||||||
|
@ -171,16 +172,222 @@ const char* UDPC_get_error_str(uint32_t error)
|
||||||
void UDPC_update(UDPC_Context *ctx)
|
void UDPC_update(UDPC_Context *ctx)
|
||||||
{
|
{
|
||||||
// get dt
|
// get dt
|
||||||
struct timespec ts;
|
struct timespec tsNow;
|
||||||
timespec_get(&ts, TIME_UTC);
|
timespec_get(&tsNow, TIME_UTC);
|
||||||
float dt = UDPC_ts_diff_to_seconds(&ts, &ctx->lastUpdated);
|
float dt = UDPC_ts_diff_to_seconds(&tsNow, &ctx->lastUpdated);
|
||||||
ctx->lastUpdated = ts;
|
ctx->lastUpdated = tsNow;
|
||||||
|
|
||||||
// check rtt
|
// check timed-out/rtt/send-interval
|
||||||
|
UDPC_INTERNAL_ConnectionData *cd;
|
||||||
|
UDPC_Deque *removedQueue = UDPC_Deque_init(
|
||||||
|
ctx->connected->alloc_size / sizeof(UDPC_INTERNAL_ConnectionData) * sizeof(int));
|
||||||
for(int x = 0; x * sizeof(UDPC_INTERNAL_ConnectionData) < ctx->connected->size; ++x)
|
for(int x = 0; x * sizeof(UDPC_INTERNAL_ConnectionData) < ctx->connected->size; ++x)
|
||||||
{
|
{
|
||||||
// TODO after fixing Deque
|
cd = UDPC_Deque_index_ptr(ctx->connected, sizeof(UDPC_INTERNAL_ConnectionData), x);
|
||||||
|
|
||||||
|
// check if connected timed out
|
||||||
|
if(UDPC_ts_diff_to_seconds(&tsNow, &cd->received) >= UDPC_TIMEOUT_SECONDS)
|
||||||
|
{
|
||||||
|
UDPC_Deque_push_back(removedQueue, &x, sizeof(int));
|
||||||
|
// TODO log timed out connection
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check good/bad mode
|
||||||
|
cd->toggleTimer += dt;
|
||||||
|
cd->toggledTimer += dt;
|
||||||
|
if((cd->flags & 0x2) != 0 && (cd->flags & 0x4) == 0)
|
||||||
|
{
|
||||||
|
// good mode, bad rtt
|
||||||
|
// TODO log switching to bad mode
|
||||||
|
cd->flags = cd->flags & 0xFFFFFFFD;
|
||||||
|
if(cd->toggledTimer >= 10.0f)
|
||||||
|
{
|
||||||
|
cd->toggleT *= 2.0f;
|
||||||
|
if(cd->toggleT > 60.0f)
|
||||||
|
{
|
||||||
|
cd->toggleT = 60.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cd->toggledTimer = 0.0f;
|
||||||
|
}
|
||||||
|
else if((cd->flags & 0x2) != 0)
|
||||||
|
{
|
||||||
|
// good mode, good rtt
|
||||||
|
if(cd->toggleTimer >= 10.0f)
|
||||||
|
{
|
||||||
|
cd->toggleTimer = 0.0f;
|
||||||
|
cd->toggleT /= 2.0f;
|
||||||
|
if(cd->toggleT < 1.0f)
|
||||||
|
{
|
||||||
|
cd->toggleT = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if((cd->flags & 0x2) == 0 && (cd->flags & 0x4) != 0)
|
||||||
|
{
|
||||||
|
// bad mode, good rtt
|
||||||
|
if(cd->toggledTimer >= cd->toggleT)
|
||||||
|
{
|
||||||
|
cd->toggleTimer = 0.0f;
|
||||||
|
cd->toggledTimer = 0.0f;
|
||||||
|
// TODO log switching to good mode
|
||||||
|
cd->flags |= 0x2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// bad mode, bad rtt
|
||||||
|
cd->toggledTimer = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check send interval
|
||||||
|
cd->timer += dt;
|
||||||
|
if(cd->timer >= ((cd->flags & 0x2) != 0
|
||||||
|
? UDPC_GOOD_MODE_SEND_INTERVAL : UDPC_BAD_MODE_SEND_INTERVAL))
|
||||||
|
{
|
||||||
|
cd->timer = 0.0f;
|
||||||
|
cd->flags |= 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// remove timed out
|
||||||
|
for(int x = 0; x * sizeof(int) < removedQueue->size; ++x)
|
||||||
|
{
|
||||||
|
UDPC_Deque_remove(ctx->connected, sizeof(UDPC_INTERNAL_ConnectionData),
|
||||||
|
*((int*)UDPC_Deque_index_rev_ptr(removedQueue, sizeof(int), x)));
|
||||||
|
}
|
||||||
|
UDPC_Deque_destroy(removedQueue);
|
||||||
|
|
||||||
|
// check triggerSend to send packets to connected
|
||||||
|
for(int x = 0; x * sizeof(UDPC_INTERNAL_ConnectionData) < ctx->connected->size; ++x)
|
||||||
|
{
|
||||||
|
cd = UDPC_Deque_index_ptr(ctx->connected, sizeof(UDPC_INTERNAL_ConnectionData), x);
|
||||||
|
if((cd->flags & 0x1) != 0)
|
||||||
|
{
|
||||||
|
cd->flags &= 0xFFFFFFFE;
|
||||||
|
if(cd->sendPktQueue->size == 0)
|
||||||
|
{
|
||||||
|
// send packet queue is empty, send heartbeat packet
|
||||||
|
if(UDPC_ts_diff_to_seconds(&tsNow, &cd->sent) < UDPC_HEARTBEAT_PKT_INTERVAL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *data = malloc(20);
|
||||||
|
UDPC_INTERNAL_prepare_pkt(data, cd->id, cd->rseq, cd->ack, &cd->lseq, cd->addr, 0);
|
||||||
|
|
||||||
|
struct sockaddr_in destinationInfo;
|
||||||
|
destinationInfo.sin_family = AF_INET;
|
||||||
|
destinationInfo.sin_addr.s_addr = htonl(cd->addr);
|
||||||
|
destinationInfo.sin_port = htons(cd->port);
|
||||||
|
long int sentBytes = sendto(
|
||||||
|
ctx->socketHandle,
|
||||||
|
data,
|
||||||
|
20,
|
||||||
|
0,
|
||||||
|
(struct sockaddr*) &destinationInfo,
|
||||||
|
sizeof(struct sockaddr_in));
|
||||||
|
if(sentBytes != 20)
|
||||||
|
{
|
||||||
|
// TODO log fail send packet
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UDPC_INTERNAL_PacketInfo sentInfo = {
|
||||||
|
cd->addr,
|
||||||
|
cd->lseq - 1,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
tsNow
|
||||||
|
};
|
||||||
|
UDPC_Deque_push_back(
|
||||||
|
cd->sentPkts, &sentInfo, sizeof(UDPC_INTERNAL_PacketInfo));
|
||||||
|
while(cd->sentPkts->size / sizeof(UDPC_INTERNAL_PacketInfo)
|
||||||
|
> UDPC_SENT_PKTS_MAX_SIZE)
|
||||||
|
{
|
||||||
|
UDPC_INTERNAL_PacketInfo *pinfo = UDPC_Deque_get_front_ptr(cd->sentPkts, sizeof(UDPC_INTERNAL_PacketInfo));
|
||||||
|
if(pinfo->data && pinfo->size != 0)
|
||||||
|
{
|
||||||
|
free(pinfo->data);
|
||||||
|
}
|
||||||
|
UDPC_Deque_pop_front(cd->sentPkts, sizeof(UDPC_INTERNAL_PacketInfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
else // sendPktQueue not empty
|
||||||
|
{
|
||||||
|
UDPC_INTERNAL_PacketInfo *pinfo = UDPC_Deque_get_front_ptr(
|
||||||
|
cd->sendPktQueue, sizeof(UDPC_INTERNAL_PacketInfo));
|
||||||
|
char *data = malloc(20 + pinfo->size);
|
||||||
|
UDPC_INTERNAL_prepare_pkt(data, cd->id, cd->rseq, cd->ack, &cd->lseq, cd->addr, ((pinfo->flags & 0x3) << 1));
|
||||||
|
memcpy(&data[20], pinfo->data, pinfo->size);
|
||||||
|
|
||||||
|
struct sockaddr_in destinationInfo;
|
||||||
|
destinationInfo.sin_family = AF_INET;
|
||||||
|
destinationInfo.sin_addr.s_addr = htonl(cd->addr);
|
||||||
|
destinationInfo.sin_port = htons(cd->port);
|
||||||
|
long int sentBytes = sendto(
|
||||||
|
ctx->socketHandle,
|
||||||
|
data,
|
||||||
|
20 + pinfo->size,
|
||||||
|
0,
|
||||||
|
(struct sockaddr*) &destinationInfo,
|
||||||
|
sizeof(struct sockaddr_in));
|
||||||
|
if(sentBytes != 20 + pinfo->size)
|
||||||
|
{
|
||||||
|
// TODO log fail sent packet
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if((pinfo->flags & 0x2) != 0)
|
||||||
|
{
|
||||||
|
UDPC_INTERNAL_PacketInfo sentInfo = {
|
||||||
|
cd->addr,
|
||||||
|
cd->lseq - 1,
|
||||||
|
pinfo->flags & 0x2,
|
||||||
|
data,
|
||||||
|
20 + pinfo->size,
|
||||||
|
tsNow
|
||||||
|
};
|
||||||
|
UDPC_Deque_push_back(
|
||||||
|
cd->sentPkts, &sentInfo, sizeof(UDPC_INTERNAL_PacketInfo));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UDPC_INTERNAL_PacketInfo sentInfo = {
|
||||||
|
cd->addr,
|
||||||
|
cd->lseq - 1,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
tsNow
|
||||||
|
};
|
||||||
|
UDPC_Deque_push_back(
|
||||||
|
cd->sentPkts, &sentInfo, sizeof(UDPC_INTERNAL_PacketInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
while(cd->sentPkts->size / sizeof(UDPC_INTERNAL_PacketInfo)
|
||||||
|
> UDPC_SENT_PKTS_MAX_SIZE)
|
||||||
|
{
|
||||||
|
UDPC_INTERNAL_PacketInfo *pinfoCached = UDPC_Deque_get_front_ptr(cd->sentPkts, sizeof(UDPC_INTERNAL_PacketInfo));
|
||||||
|
if(pinfoCached->data && pinfoCached->size != 0)
|
||||||
|
{
|
||||||
|
free(pinfoCached->data);
|
||||||
|
}
|
||||||
|
UDPC_Deque_pop_front(cd->sentPkts, sizeof(UDPC_INTERNAL_PacketInfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(pinfo->data);
|
||||||
|
UDPC_Deque_pop_front(cd->sendPktQueue, sizeof(UDPC_INTERNAL_PacketInfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// receive packet
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
float UDPC_ts_diff_to_seconds(struct timespec *ts0, struct timespec *ts1)
|
float UDPC_ts_diff_to_seconds(struct timespec *ts0, struct timespec *ts1)
|
||||||
|
@ -259,3 +466,41 @@ int UDPC_INTERNAL_threadfn(void *context)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UDPC_INTERNAL_prepare_pkt(
|
||||||
|
void *data,
|
||||||
|
uint32_t conID,
|
||||||
|
uint32_t rseq,
|
||||||
|
uint32_t ack,
|
||||||
|
uint32_t *seqID,
|
||||||
|
uint32_t addr,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
char *d = data;
|
||||||
|
uint32_t temp;
|
||||||
|
|
||||||
|
temp = htonl(UDPC_PKT_PROTOCOL_ID);
|
||||||
|
memcpy(d, &temp, 4);
|
||||||
|
if((flags & 0x4) == 0)
|
||||||
|
{
|
||||||
|
temp = htonl(conID | UDPC_ID_NO_REC_CHK);
|
||||||
|
memcpy(&d[4], &temp, 4);
|
||||||
|
}
|
||||||
|
else if((flags & 0x1) != 0)
|
||||||
|
{
|
||||||
|
temp = htonl(conID | UDPC_ID_PING);
|
||||||
|
memcpy(&d[4], &temp, 4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
temp = htonl(conID | ((flags & 0x2) != 0 ? UDPC_ID_RESENDING : 0));
|
||||||
|
memcpy(&d[4], &temp, 4);
|
||||||
|
}
|
||||||
|
temp = htonl(*seqID);
|
||||||
|
++(*seqID);
|
||||||
|
memcpy(&d[8], &temp, 4);
|
||||||
|
temp = htonl(rseq);
|
||||||
|
memcpy(&d[12], &temp, 4);
|
||||||
|
temp = htonl(ack);
|
||||||
|
memcpy(&d[16], &temp, 4);
|
||||||
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#define CleanupSocket(x) ((void)0)
|
#define CleanupSocket(x) ((void)0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define UDPC_CD_AMOUNT 32
|
|
||||||
|
|
||||||
/// This struct should not be used outside of this library
|
/// This struct should not be used outside of this library
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -33,11 +32,12 @@ typedef struct
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
/*
|
/*
|
||||||
* 0x1 - is resending
|
* 0x1 - is resending
|
||||||
* 0x2 - is not received checked
|
* 0x2 - is check received packet
|
||||||
* 0x4 - has been re-sent
|
* 0x4 - has been re-sent
|
||||||
*/
|
*/
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
char *data;
|
char *data; // no-header in sendPktQueue, header in sentPkts
|
||||||
|
uint32_t size;
|
||||||
struct timespec sent;
|
struct timespec sent;
|
||||||
} UDPC_INTERNAL_PacketInfo;
|
} UDPC_INTERNAL_PacketInfo;
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ typedef struct
|
||||||
float toggleT;
|
float toggleT;
|
||||||
float toggleTimer;
|
float toggleTimer;
|
||||||
float toggledTimer;
|
float toggledTimer;
|
||||||
|
uint32_t addr;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
UDPC_Deque *sentPkts;
|
UDPC_Deque *sentPkts;
|
||||||
UDPC_Deque *sendPktQueue;
|
UDPC_Deque *sendPktQueue;
|
||||||
|
@ -106,4 +107,18 @@ float UDPC_ts_diff_to_seconds(struct timespec *ts0, struct timespec *ts1);
|
||||||
|
|
||||||
int UDPC_INTERNAL_threadfn(void *context); // internal usage only
|
int UDPC_INTERNAL_threadfn(void *context); // internal usage only
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 0x1 - is ping
|
||||||
|
* 0x2 - is resending
|
||||||
|
* 0x4 - is checked received packet
|
||||||
|
*/
|
||||||
|
void UDPC_INTERNAL_prepare_pkt(
|
||||||
|
void *data,
|
||||||
|
uint32_t conID,
|
||||||
|
uint32_t rseq,
|
||||||
|
uint32_t ack,
|
||||||
|
uint32_t *seqID,
|
||||||
|
uint32_t addr,
|
||||||
|
int flags);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue