]> git.seodisparate.com - UDPConnection/commitdiff
Add UDPC_set_con_timeout_millis(...)
authorStephen Seo <seo.disparate@gmail.com>
Thu, 13 Mar 2025 03:07:21 +0000 (12:07 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Thu, 13 Mar 2025 03:08:12 +0000 (12:08 +0900)
Add new function to set the connection timeout time. By default, this
timeout time is 10 seconds. If a packet hasn't been received for this
duration, then the connection is considered "timed out" and is dropped.

Previously this time was a constant 10 seconds. This commit allows
changing the connection timeout time. However, it cannot be less than
the heartbeat interval time.

src/UDPC.h
src/UDPC_Defines.hpp
src/UDPConnection.cpp
src/test/UDPC_NetworkTest.c

index 68648e63366571e2fe39a9a87699f46e64ec0927..ba08061558cb53761e3be526e57d85be4d572985 100644 (file)
@@ -273,6 +273,10 @@ typedef struct UDPC_EXPORT UDPC_Event {
     } v;
 } UDPC_Event;
 
+/// The connection timeout time default in milliseconds.
+/// Use this for UDPC_set_con_timeout_millis().
+#define UDPC_CON_TIMEOUT_DEFAULT 10000
+
 /*!
  * \brief Creates an UDPC_ConnectionId with the given addr and port
  *
@@ -940,11 +944,37 @@ UDPC_EXPORT void UDPC_atostr_unsafe_free_ptr(const char **addrBuf);
  * for any connection. (See <a href="#details">details</a> for info on "good
  * mode" and "bad mode".)
  *
+ * \warning The connection timeout time is adjusted if it is less than the new
+ * value for the heartbeat interval time. The new connection timeout time is
+ * calculated as 3 times the heartbeat interval time. It may be necessary to
+ * set the connection timeout time with UDPC_set_con_timeout_millis().
+ *
  * \return 0 on success, 1 if clamped to minimum, 2 if clamped to maximum, -1
  * if the given context is invalid.
  */
 UDPC_EXPORT int UDPC_set_heartbeat_millis(UDPC_HContext ctx, unsigned int millis);
 
+/*!
+ * \brief Sets the connection timeout time.
+ *
+ * By default, UDPC times out a connection if a packet hasn't been received for
+ * 10 seconds, or 10,000 milliseconds (the default value).
+ *
+ * This function sets the connection timeout time. It is an error to set this
+ * value to be less than the currently set heartbeat interval time, which can
+ * be set with UDPC_set_heartbeat_millis().
+ *
+ * Pass \ref UDPC_CON_TIMEOUT_DEFAULT to set the timeout to the default.
+ *
+ * \warning This function does no sanity checking other than ensuring the
+ * timeout is not set to less than the heartbeat time. A sane maximum would be
+ * the default timeout time, which is 10 seconds, or 10,000 milliseconds.
+ *
+ * \return 0 on success, -1 the given context is invalid, -2 if the given value
+ * is invalid (less than the currently set heartbeat interval time).
+ */
+UDPC_EXPORT int UDPC_set_con_timeout_millis(UDPC_HContext ctx, unsigned int millis);
+
 // =============================================================================
 // Helpers
 
index 08779aa8aedc9af75e17f61439c053492851862b..00da43c9cd68b0333580e53d8ea6f3fea5778490 100644 (file)
@@ -284,6 +284,8 @@ public:
     std::chrono::milliseconds heartbeatDuration;
     std::shared_mutex heartbeatMutex;
 
+    std::chrono::milliseconds conTimeoutDuration;
+    std::shared_mutex conTimeoutMutex;
 }; // struct Context
 
 Context *verifyContext(UDPC_HContext ctx);
index 8c1934f4acb31a09c15ecd127b27e4e26404b7b7..3ea7d857e85a494d814f45b55df55dafd7086cd7 100644 (file)
@@ -259,7 +259,9 @@ atostrBufIndex(0),
 setThreadedUpdateMutex(),
 enableDisableFuncRunningCount(0),
 heartbeatDuration(UDPC::HEARTBEAT_PKT_INTERVAL_DT),
-heartbeatMutex()
+heartbeatMutex(),
+conTimeoutDuration(UDPC_CON_TIMEOUT_DEFAULT),
+conTimeoutMutex()
 {
     std::memset(atostrBuf, 0, UDPC_ATOSTR_SIZE);
 
@@ -447,7 +449,12 @@ void UDPC::Context::update_impl() {
         std::lock_guard<std::mutex> conMapLock(conMapMutex);
         for(auto iter = conMap.begin(); iter != conMap.end(); ++iter) {
             temp_dt_fs = now - iter->second.received;
-            if(temp_dt_fs >= UDPC::CONNECTION_TIMEOUT) {
+            std::chrono::milliseconds conTimeoutTime;
+            {
+                std::shared_lock<std::shared_mutex> lock(conTimeoutMutex);
+                conTimeoutTime = conTimeoutDuration;
+            }
+            if(temp_dt_fs >= conTimeoutTime) {
                 removed.push_back(iter->first);
                 UDPC_CHECK_LOG(this,
                     UDPC_LoggingType::UDPC_VERBOSE,
@@ -2855,12 +2862,48 @@ int UDPC_set_heartbeat_millis(UDPC_HContext ctx, unsigned int millis) {
         ret = 2;
     }
 
-    std::unique_lock<std::shared_mutex> lock(c->heartbeatMutex);
-    c->heartbeatDuration = std::chrono::milliseconds(millis);
+    const std::chrono::milliseconds chrono_millis(millis);
+    {
+        std::unique_lock<std::shared_mutex> lock(c->heartbeatMutex);
+        c->heartbeatDuration = chrono_millis;
+    }
+
+    {
+        std::unique_lock<std::shared_mutex> lock(c->conTimeoutMutex);
+        if (c->conTimeoutDuration < chrono_millis) {
+            c->conTimeoutDuration = chrono_millis * 3;
+        }
+    }
 
     return ret;
 }
 
+int UDPC_set_con_timeout_millis(UDPC_HContext ctx, unsigned int millis) {
+    UDPC::Context *c = UDPC::verifyContext(ctx);
+    if (!c) {
+        return -1;
+    }
+
+    const std::chrono::milliseconds mseconds(millis);
+
+    std::chrono::milliseconds heartbeatTime;
+    {
+        std::shared_lock<std::shared_mutex> heartbeatLock(c->heartbeatMutex);
+        heartbeatTime = c->heartbeatDuration;
+    }
+
+    if (mseconds < heartbeatTime) {
+        return -2;
+    }
+
+    {
+        std::unique_lock<std::shared_mutex> conTimeoutLock(c->conTimeoutMutex);
+        c->conTimeoutDuration = mseconds;
+    }
+
+    return 0;
+}
+
 UDPC_IPV6_ADDR_TYPE UDPC_strtoa(const char *addrStr) {
     UDPC_IPV6_ADDR_TYPE result = in6addr_loopback;
     std::cmatch matchResults;
index a6f638440cabe0ac7cc3b6fee157a75194df2f72..2f971837c3d34e182d6b0d1360f42aa4339d5e23 100644 (file)
@@ -33,7 +33,7 @@ static void handleSIGINT(int signal) {
 #define SEND_IDS_SIZE 64
 #define WHITELIST_FILES_SIZE 64
 
-void usage() {
+void usage(void) {
     puts("[-c | -s] - client or server (default server)");
     puts("-ll <addr> - listen addr");
     puts("-lp <port> - listen port");
@@ -50,6 +50,7 @@ void usage() {
     puts("-p <\"fallback\" or \"strict\"> - set auth policy");
     puts("--hostname <hostname> - dont run test, just lookup hostname");
     puts("--heartbeat <interval> - set heartbeat interval in milliseconds");
+    puts("--con-timeout <millis> - set connection timeout time in milliseconds");
 }
 
 void sleep_seconds(unsigned int seconds) {
@@ -109,6 +110,7 @@ int main(int argc, char **argv) {
     unsigned char whitelist_pks[WHITELIST_FILES_SIZE][crypto_sign_PUBLICKEYBYTES];
     int authPolicy = UDPC_AUTH_POLICY_FALLBACK;
     unsigned long heartbeat_millis = 0;
+    unsigned long con_timeout_millis = 10000;
 
     while(argc > 0) {
         if(strcmp(argv[0], "-c") == 0) {
@@ -204,6 +206,14 @@ int main(int argc, char **argv) {
                 // Clamp to unsigned int maximum value, assuming 4 bytes.
                 heartbeat_millis = 0xFFFFFFFF;
             }
+        } else if (strcmp(argv[0], "--con-timeout") == 0 && argc > 1) {
+            --argc; ++argv;
+            con_timeout_millis = strtoul(argv[0], NULL, 10);
+            if (con_timeout_millis == 0) {
+                printf("ERROR: Failed to parse connection timeout milliseconds!\n");
+                usage();
+                return 1;
+            }
         } else {
             printf("ERROR: invalid argument \"%s\"\n", argv[0]);
             usage();
@@ -323,6 +333,7 @@ int main(int argc, char **argv) {
         for(unsigned int i = 0; i < whitelist_pk_files_index; ++i) {
             if((unsigned int)UDPC_add_whitelist_pk(context, whitelist_pks[i]) != i + 1) {
                 puts("Failed to add pubkey to whitelist");
+                UDPC_destroy(context);
                 return 1;
             }
         }
@@ -335,6 +346,14 @@ int main(int argc, char **argv) {
         puts("WARNING: Clamped heartbeat interval to maxiumum 5000!");
     }
 
+    ret = UDPC_set_con_timeout_millis(context, con_timeout_millis);
+    if (ret < 0) {
+        printf("ERROR: Failed to set connection timeout time to %lu millis (too low)!\n",
+               con_timeout_millis);
+        UDPC_destroy(context);
+        return 1;
+    }
+
     UDPC_enable_threaded_update(context);
 
     unsigned int tick = 0;