]> git.seodisparate.com - UDPConnection/commitdiff
Add some impl of UDPConnection (still WIP)
authorStephen Seo <seo.disparate@gmail.com>
Thu, 31 Jan 2019 10:44:32 +0000 (19:44 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Thu, 31 Jan 2019 10:44:32 +0000 (19:44 +0900)
src/UDPC_Defines.h
src/UDPConnection.c
src/UDPConnection.h

index 83c1b30f24498675941fe270271cfb669b9f4433..63a6e5a29bee156bc691aa3119d1480210bbdd3d 100644 (file)
@@ -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_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
index 6f239a1a5abace6f72034ab13aa0659c947bdeae..4debe47b090902cef6c836732c4af03cf2b65dba 100644 (file)
@@ -1,6 +1,7 @@
 #include "UDPConnection.h"
 
 #include <stdlib.h>
+#include <string.h>
 
 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)
 {
     // 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)
@@ -259,3 +466,41 @@ int UDPC_INTERNAL_threadfn(void *context)
 
     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);
+}
index d1ce97757f6b986b1d28bc12dbc18797436104fb..d6ae457f0a18f6df4d1e93c0a1e2c2c7812c83bc 100644 (file)
@@ -24,7 +24,6 @@
   #define CleanupSocket(x) ((void)0)
 #endif
 
-#define UDPC_CD_AMOUNT 32
 
 /// This struct should not be used outside of this library
 typedef struct
@@ -33,11 +32,12 @@ typedef struct
     uint32_t id;
     /*
      * 0x1 - is resending
-     * 0x2 - is not received checked
+     * 0x2 - is check received packet
      * 0x4 - has been re-sent
      */
     uint32_t flags;
-    char *data;
+    char *data; // no-header in sendPktQueue, header in sentPkts
+    uint32_t size;
     struct timespec sent;
 } UDPC_INTERNAL_PacketInfo;
 
@@ -58,6 +58,7 @@ typedef struct
     float toggleT;
     float toggleTimer;
     float toggledTimer;
+    uint32_t addr;
     uint16_t port;
     UDPC_Deque *sentPkts;
     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
 
+/*
+ * 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