#include "UDPConnection.h"
#include <stdlib.h>
+#include <string.h>
UDPC_Context* UDPC_init(uint16_t listenPort, int isClient)
{
void UDPC_update(UDPC_Context *ctx)
{
// get dt
- struct timespec ts;
- timespec_get(&ts, TIME_UTC);
- float dt = UDPC_ts_diff_to_seconds(&ts, &ctx->lastUpdated);
- ctx->lastUpdated = ts;
+ struct timespec tsNow;
+ timespec_get(&tsNow, TIME_UTC);
+ float dt = UDPC_ts_diff_to_seconds(&tsNow, &ctx->lastUpdated);
+ ctx->lastUpdated = tsNow;
+
+ // 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)
+ {
+ 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 rtt
+ // check triggerSend to send packets to connected
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);
+ 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)
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);
+}