feat: implement real ping RTT calculation instead of hardcoded 50ms

This commit is contained in:
Jose Luis Montañes Ojados
2026-01-16 19:43:31 +01:00
parent 184fff202f
commit 13f444193d
3 changed files with 79 additions and 5 deletions

View File

@@ -4,6 +4,8 @@ import (
"bytes"
"encoding/binary"
"log"
"math"
"time"
"go-ts/pkg/protocol"
)
@@ -114,8 +116,59 @@ func (c *Client) handlePacket(pkt *protocol.Packet) error {
c.Conn.SendPacket(pong)
case protocol.PacketTypePong:
// Server acknowledged our Ping
log.Printf("Received Pong for sequence %d", pkt.Header.PacketID)
// Server acknowledged our Ping - calculate RTT
receivedAt := time.Now()
// Decrypt Pong body if needed to get the PingID it's acknowledging
var pongData []byte
if pkt.Header.FlagUnencrypted() {
pongData = pkt.Data
} else if c.Handshake != nil && c.Handshake.Step >= 6 && len(c.Handshake.SharedIV) > 0 {
crypto := &protocol.CryptoState{
SharedIV: c.Handshake.SharedIV,
SharedMac: c.Handshake.SharedMac,
GenerationID: 0,
}
key, nonce := crypto.GenerateKeyNonce(&pkt.Header, false) // Server->Client
meta := make([]byte, 3)
binary.BigEndian.PutUint16(meta[0:2], pkt.Header.PacketID)
meta[2] = pkt.Header.Type
decrypted, err := protocol.DecryptEAX(key, nonce, meta, pkt.Data, pkt.Header.MAC[:])
if err == nil {
pongData = decrypted
}
}
// Extract PingID from Pong body
var pingID uint16
if len(pongData) >= 2 {
pingID = binary.BigEndian.Uint16(pongData[0:2])
} else {
pingID = pkt.Header.PacketID // fallback
}
// Calculate RTT if we have the send time
if sentTime, ok := c.PingSentTimes[pingID]; ok {
rtt := receivedAt.Sub(sentTime).Seconds() * 1000 // RTT in ms
delete(c.PingSentTimes, pingID)
// Update rolling average using Welford's algorithm
c.PingSampleCount++
if c.PingSampleCount == 1 {
c.PingRTT = rtt
c.PingDeviation = 0
} else {
oldMean := c.PingRTT
c.PingRTT = oldMean + (rtt-oldMean)/float64(c.PingSampleCount)
// Rolling deviation: exponential smoothing
c.PingDeviation = c.PingDeviation*0.9 + math.Abs(rtt-c.PingRTT)*0.1
}
log.Printf("Received Pong for Ping %d: RTT=%.2fms, AvgRTT=%.2fms, Dev=%.2fms",
pingID, rtt, c.PingRTT, c.PingDeviation)
} else {
log.Printf("Received Pong for unknown Ping %d", pingID)
}
case protocol.PacketTypeAck:
// Server acknowledged our packet
var data []byte