Implemented hearthbit client side + tests

This commit is contained in:
Martino Ferrari
2026-08-09 18:51:51 +02:00
parent 915a192b16
commit 1ddb4fe356
12 changed files with 994 additions and 285 deletions
@@ -24,6 +24,7 @@ UDPSClient::UDPSClient()
useMulticast(false),
silenceTimeoutTicks(0u),
reconnectDelayTicks(0u),
keepAliveIntervalTicks(0u),
maxPayloadSize(UDPS_CLIENT_DEFAULT_MAX_PAYLOAD),
cpuMask(0xFFFFFFFFu),
stackSize(65536u),
@@ -33,6 +34,7 @@ UDPSClient::UDPSClient()
connected(false),
lastDataTicks(0u),
disconnectTick(0u),
lastKeepAliveTicks(0u),
localPort(0u),
lastGcTicks(0u) {
@@ -93,6 +95,10 @@ bool UDPSClient::Initialise(StructuredDataI &data) {
(void) data.Read("ReconnectDelay", reconnectS);
reconnectDelayTicks = static_cast<uint64>(reconnectS) * HighResolutionTimer::Frequency();
uint32 keepAliveS = UDPS_CLIENT_DEFAULT_KEEPALIVE_INTERVAL_S;
(void) data.Read("KeepAliveInterval", keepAliveS);
keepAliveIntervalTicks = static_cast<uint64>(keepAliveS) * HighResolutionTimer::Frequency();
uint32 mps = UDPS_CLIENT_DEFAULT_MAX_PAYLOAD;
(void) data.Read("MaxPayloadSize", mps);
maxPayloadSize = mps;
@@ -185,6 +191,18 @@ ErrorManagement::ErrorType UDPSClient::Execute(ExecutionInfo &info) {
}
}
// Unicast keepalive: UDPSServer evicts silent unicast clients after its
// ClientTimeout (default 30 s). Re-sending CONNECT would also re-trigger
// a CONFIG resend; an ACK refreshes the server's last-seen with no side
// effects, so it is the keepalive packet of choice. Multicast clients
// hold a persistent TCP control connection and need no keepalive.
if (!useMulticast && (keepAliveIntervalTicks > 0u)) {
if ((now - lastKeepAliveTicks) >= keepAliveIntervalTicks) {
SendKeepAlive();
lastKeepAliveTicks = now;
}
}
// Periodic GC of stale reassembly slots (~every 1 s)
uint64 gcFreq = HighResolutionTimer::Frequency();
if ((now - lastGcTicks) >= gcFreq) {
@@ -204,6 +222,7 @@ bool UDPSClient::Connect() {
if (ok) {
connected = true;
lastDataTicks = HighResolutionTimer::Counter();
lastKeepAliveTicks = lastDataTicks;
if (listener != NULL_PTR(UDPSClientListener *)) {
listener->OnUDPSConnected();
}
@@ -378,6 +397,25 @@ void UDPSClient::Disconnect() {
}
}
// ---------------------------------------------------------------------------
// Private: SendKeepAlive
// ---------------------------------------------------------------------------
void UDPSClient::SendKeepAlive() {
if (useMulticast || !recvSocket.IsValid()) {
return;
}
uint8 ackPkt[UDPS_HEADER_SIZE];
UDPSBuildHeader(ackPkt, UDPS_TYPE_ACK, 0u, 0u, 1u, 0u);
InternetHost serverDest(serverPort, serverAddr.Buffer());
(void) recvSocket.SetDestination(serverDest);
uint32 sendSize = UDPS_HEADER_SIZE;
if (!recvSocket.Write(reinterpret_cast<const char8 *>(ackPkt), sendSize)) {
/* Non-fatal: if the server is truly gone, the silence timeout
* triggers the usual disconnect + reconnect. */
}
}
// ---------------------------------------------------------------------------
// Private: ReceiveAndProcess
// ---------------------------------------------------------------------------