Files
2025-08-19 12:45:50 +02:00

310 lines
9.9 KiB
C#

using System;
namespace UdtSharp
{
public class ACKWindow
{
public ACKWindow(int size = 1024)
{
m_iSize = size;
m_piACKSeqNo = new int[m_iSize];
m_piACK = new int[m_iSize];
m_pTimeStamp = new ulong[m_iSize];
m_piACKSeqNo[0] = -1;
}
// Functionality:
// Write an ACK record into the window.
// Parameters:
// 0) [in] seq: ACK seq. no.
// 1) [in] ack: DATA ACK no.
// Returned value:
// None.
public void store(int seq, int ack)
{
m_piACKSeqNo[m_iHead] = seq;
m_piACK[m_iHead] = ack;
m_pTimeStamp[m_iHead] = Timer.getTime();
m_iHead = (m_iHead + 1) % m_iSize;
// overwrite the oldest ACK since it is not likely to be acknowledged
if (m_iHead == m_iTail)
m_iTail = (m_iTail + 1) % m_iSize;
}
// Functionality:
// Search the ACK-2 "seq" in the window, find out the DATA "ack" and caluclate RTT .
// Parameters:
// 0) [in] seq: ACK-2 seq. no.
// 1) [out] ack: the DATA ACK no. that matches the ACK-2 no.
// Returned value:
// RTT.
public int acknowledge(int seq, ref int ack)
{
if (m_iHead >= m_iTail)
{
// Head has not exceeded the physical boundary of the window
for (int i = m_iTail, n = m_iHead; i < n; ++i)
{
// looking for indentical ACK Seq. No.
if (seq == m_piACKSeqNo[i])
{
// return the Data ACK it carried
ack = m_piACK[i];
// calculate RTT
int rtt = (int)(Timer.getTime() - m_pTimeStamp[i]);
if (i + 1 == m_iHead)
{
m_iTail = m_iHead = 0;
m_piACKSeqNo[0] = -1;
}
else
m_iTail = (i + 1) % m_iSize;
return rtt;
}
}
// Bad input, the ACK node has been overwritten
return -1;
}
// Head has exceeded the physical window boundary, so it is behind tail
for (int j = m_iTail, n = m_iHead + m_iSize; j < n; ++j)
{
// looking for indentical ACK seq. no.
if (seq == m_piACKSeqNo[j % m_iSize])
{
// return Data ACK
j %= m_iSize;
ack = m_piACK[j];
// calculate RTT
int rtt = (int)(Timer.getTime() - m_pTimeStamp[j]);
if (j == m_iHead)
{
m_iTail = m_iHead = 0;
m_piACKSeqNo[0] = -1;
}
else
m_iTail = (j + 1) % m_iSize;
return rtt;
}
}
// bad input, the ACK node has been overwritten
return -1;
}
int[] m_piACKSeqNo; // Seq. No. for the ACK packet
int[] m_piACK; // Data Seq. No. carried by the ACK packet
ulong[] m_pTimeStamp; // The timestamp when the ACK was sent
int m_iSize; // Size of the ACK history window
int m_iHead; // Pointer to the lastest ACK record
int m_iTail; // Pointer to the oldest ACK record
}
////////////////////////////////////////////////////////////////////////////////
public class PktTimeWindow
{
public PktTimeWindow(int asize = 16, int psize = 16)
{
m_iAWSize = asize;
m_iPWSize = psize;
m_iMinPktSndInt = 1000000;
m_piPktWindow = new int[m_iAWSize];
m_piPktReplica = new int[m_iAWSize];
m_piProbeWindow = new int[m_iPWSize];
m_piProbeReplica = new int[m_iPWSize];
m_LastArrTime = Timer.getTime();
for (int i = 0; i < m_iAWSize; ++i)
m_piPktWindow[i] = 1000000;
for (int k = 0; k < m_iPWSize; ++k)
m_piProbeWindow[k] = 1000;
}
// Functionality:
// read the minimum packet sending interval.
// Parameters:
// None.
// Returned value:
// minimum packet sending interval (microseconds).
public int getMinPktSndInt()
{
return m_iMinPktSndInt;
}
// Functionality:
// Calculate the packes arrival speed.
// Parameters:
// None.
// Returned value:
// Packet arrival speed (packets per second).
public int getPktRcvSpeed()
{
// get median value, but cannot change the original value order in the window
Array.Copy(m_piPktWindow, m_piPktReplica, m_iAWSize - 1); // why -1 ???
Array.Sort(m_piPktReplica); // need -1 here ???
int median = m_piPktReplica[m_iAWSize / 2];
int count = 0;
int sumMicrosecond = 0;
int upper = median << 3;
int lower = median >> 3;
// median filtering
for (int i = 0, n = m_iAWSize; i < n; ++i)
{
if ((m_piPktWindow[i] < upper) && (m_piPktWindow[i] > lower))
{
++count;
sumMicrosecond += m_piPktWindow[i];
}
}
double packetsPerMicrosecond = (double)count / sumMicrosecond;
// claculate speed, or return 0 if not enough valid value
if (count > (m_iAWSize >> 1))
return (int)Math.Ceiling(1000000 * packetsPerMicrosecond);
else
return 0;
}
// Functionality:
// Estimate the bandwidth.
// Parameters:
// None.
// Returned value:
// Estimated bandwidth (packets per second).
public int getBandwidth()
{
// get median value, but cannot change the original value order in the window
Array.Copy(m_piProbeWindow, m_piProbeReplica, m_iPWSize - 1); // why -1 ???
Array.Sort(m_piProbeReplica); // need -1 here ???
int median = m_piProbeReplica[m_iPWSize / 2];
int count = 1;
int sum = median;
int upper = median << 3;
int lower = median >> 3;
// median filtering
for (int i = 0, n = m_iPWSize; i < n; ++i)
{
if ((m_piProbeWindow[i] < upper) && (m_piProbeWindow[i] > lower))
{
++count;
sum += m_piProbeWindow[i];
}
}
return (int)Math.Ceiling(1000000.0 / ((double)sum / (double)count));
}
// Functionality:
// Record time information of a packet sending.
// Parameters:
// 0) currtime: timestamp of the packet sending.
// Returned value:
// None.
public void onPktSent(int currtime)
{
int interval = currtime - m_iLastSentTime;
if ((interval < m_iMinPktSndInt) && (interval > 0))
m_iMinPktSndInt = interval;
m_iLastSentTime = currtime;
}
// Functionality:
// Record time information of an arrived packet.
// Parameters:
// None.
// Returned value:
// None.
public void onPktArrival()
{
m_CurrArrTime = Timer.getTime();
// record the packet interval between the current and the last one
m_piPktWindow[m_iPktWindowPtr] = (int)(m_CurrArrTime - m_LastArrTime);
// the window is logically circular
++m_iPktWindowPtr;
if (m_iPktWindowPtr == m_iAWSize)
m_iPktWindowPtr = 0;
// remember last packet arrival time
m_LastArrTime = m_CurrArrTime;
}
// Functionality:
// Record the arrival time of the first probing packet.
// Parameters:
// None.
// Returned value:
// None.
public void probe1Arrival()
{
m_ProbeTime = Timer.getTime();
}
// Functionality:
// Record the arrival time of the second probing packet and the interval between packet pairs.
// Parameters:
// None.
// Returned value:
// None.
public void probe2Arrival()
{
m_CurrArrTime = Timer.getTime();
// record the probing packets interval
m_piProbeWindow[m_iProbeWindowPtr] = (int)(m_CurrArrTime - m_ProbeTime);
// the window is logically circular
++m_iProbeWindowPtr;
if (m_iProbeWindowPtr == m_iPWSize)
m_iProbeWindowPtr = 0;
}
int m_iAWSize; // size of the packet arrival history window
int[] m_piPktWindow; // packet information window
int[] m_piPktReplica;
int m_iPktWindowPtr; // position pointer of the packet info. window.
int m_iPWSize; // size of probe history window size
int[] m_piProbeWindow; // record inter-packet time for probing packet pairs
int[] m_piProbeReplica;
int m_iProbeWindowPtr; // position pointer to the probing window
int m_iLastSentTime; // last packet sending time
int m_iMinPktSndInt; // Minimum packet sending interval
ulong m_LastArrTime; // last packet arrival time
ulong m_CurrArrTime; // current packet arrival time
ulong m_ProbeTime; // arrival time of the first probing packet
}
}