private void ProcessAckVectorHeader(RdpeudpPacket eudpPacket)
{
// Update OutSnAckOfAcksSeqNum if necessary
UpdateOutSnAckOfAcksSeqNum(eudpPacket.fecHeader.snSourceAck);
if (eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_ACK) && !eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_SYN))
{
//Contains ack, analyze ack value, update outPacketDic, caculate RTT, and move send window
if (eudpPacket.ackVectorHeader.Value.uAckVectorSize > 0) // Deal with ack vector.
{
uint currentposition = OutSnAckOfAcksSeqNum;
lock (outPacketDic)
{
foreach (AckVector AckVectorElement in eudpPacket.ackVectorHeader.Value.AckVectorElement)
{
if (AckVectorElement.State == VECTOR_ELEMENT_STATE.DATAGRAM_RECEIVED)
{
// update outPacketDic only if this vector element is to ack received
for (byte i = 0; i < AckVectorElement.Length + 1; i++, currentposition++)
{
if (outPacketDic.ContainsKey(currentposition))
{
outPacketDic[currentposition].Acknowledged = true;
}
}
}
else
{
currentposition = currentposition + AckVectorElement.Length + 1;
}
}
// If this packet is not a delay ack, calculate RTT, only the last acknowleged source packet is used to caculate RTT
if (outPacketDic.ContainsKey(currentposition - 1))
{
if (!eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_ACKDELAYED)
&& !outPacketDic[currentposition - 1].estimatedRTT) // Also make sure this packet has not been used to estimate RTT. If the packet has been used to estimated RTT, this packet may be a resent ACK for keep alive
{
RTT = new TimeSpan(RTT.Ticks / 8 * 7 + (DateTime.Now - outPacketDic[currentposition - 1].SendTime).Ticks / 8); // Count the RTT.
outPacketDic[currentposition - 1].estimatedRTT = true;
}
}
// Update send window, this method will update outPacketDic
UpdateSendWindow();
}
sendWindowLock.Set();
}
}
}