Files
gatuna/gatuna-win/PingTest.cs
T

102 lines
2.6 KiB
C#
Raw Normal View History

using System.Collections.Concurrent;
namespace gatuna;
sealed class PingTest
{
readonly TunnelLink _link;
readonly byte[] _serverMac;
readonly CancellationTokenSource _cts = new();
readonly ConcurrentDictionary<ulong, long> _outstanding = new();
readonly ConcurrentQueue<double> _rtts = new();
long _sent;
long _received;
double _lastRttMs;
double _jitterSum;
long _jitterCount;
public event Action<PingStats>? StatsUpdated;
public event Action<string>? Log;
public bool Running { get; private set; }
public PingTest(TunnelLink link, byte[] serverMac)
{
_link = link;
_serverMac = serverMac;
}
public void Start()
{
Running = true;
_ = RunLoop();
}
public void Stop()
{
Running = false;
_cts.Cancel();
}
async Task RunLoop()
{
var rng = new Random();
var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(10));
while (!_cts.IsCancellationRequested)
{
var nonce = (ulong)Interlocked.Increment(ref _sent);
var ticks = DateTime.UtcNow.Ticks;
_outstanding[nonce] = ticks;
_link.SendTo(_serverMac, new Frame.Ping(nonce));
var interval = rng.Next(10, 101);
try
{
await Task.Delay(interval, _cts.Token);
}
catch { break; }
}
Running = false;
}
public void HandlePong(ulong nonce)
{
if (_outstanding.TryRemove(nonce, out var sentTicks))
{
var rttMs = (DateTime.UtcNow.Ticks - sentTicks) / (double)TimeSpan.TicksPerMillisecond;
_rtts.Enqueue(rttMs);
Interlocked.Increment(ref _received);
if (_jitterCount > 0)
{
_jitterSum += Math.Abs(rttMs - _lastRttMs);
}
_lastRttMs = rttMs;
Interlocked.Increment(ref _jitterCount);
EmitStats();
}
}
void EmitStats()
{
var sent = Interlocked.Read(ref _sent);
var recv = Interlocked.Read(ref _received);
var loss = sent > 0 ? (1.0 - (double)recv / sent) * 100.0 : 0;
var rttList = _rtts.ToArray();
var avg = rttList.Length > 0 ? rttList.Average() : 0;
var jitter = _jitterCount > 1 ? _jitterSum / (_jitterCount - 1) : 0;
StatsUpdated?.Invoke(new PingStats(sent, recv, loss, avg, jitter));
}
}
readonly record struct PingStats(
long Sent,
long Received,
double LossPct,
double AvgLatencyMs,
double JitterMs);