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 } }