} 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
*
* 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
std::chrono::milliseconds heartbeatDuration;
std::shared_mutex heartbeatMutex;
+ std::chrono::milliseconds conTimeoutDuration;
+ std::shared_mutex conTimeoutMutex;
}; // struct Context
Context *verifyContext(UDPC_HContext ctx);
setThreadedUpdateMutex(),
enableDisableFuncRunningCount(0),
heartbeatDuration(UDPC::HEARTBEAT_PKT_INTERVAL_DT),
-heartbeatMutex()
+heartbeatMutex(),
+conTimeoutDuration(UDPC_CON_TIMEOUT_DEFAULT),
+conTimeoutMutex()
{
std::memset(atostrBuf, 0, UDPC_ATOSTR_SIZE);
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,
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;
#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");
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) {
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) {
// 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();
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;
}
}
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;