public override void OnDatagram(Datagram datagram) { CheckDatagramValid(datagram); connection.SendDatagramAsync(datagram.CreateAck()); lock (channelMutex) { int relate = RelativeSequenceNumber(datagram.Sequence, recvWindowStart); if (relate == 0) { //right in time connection.ReleaseDatagram(datagram); AdvanceWindow(); int nextSeqNr = (datagram.Sequence + 1) % MAX_SEQUENCE; if (ordered) { while (recvWithheld[nextSeqNr % WINDOW_SIZE] != null) { connection.ReleaseDatagram(recvWithheld[nextSeqNr % WINDOW_SIZE]); AdvanceWindow(); nextSeqNr++; } } else { while (recvEarlyReceived[nextSeqNr % WINDOW_SIZE]) { AdvanceWindow(); nextSeqNr++; } } return; } if (relate < 0) { //duplicate logger.Trace($"Dropped duplicate {datagram}"); datagram.Dispose(); return; } if (relate > WINDOW_SIZE) { //too early message logger.Trace($"Dropped too early {datagram}"); datagram.Dispose(); return; } if (ordered) { if (recvWithheld[datagram.Sequence % WINDOW_SIZE] != null) { //duplicate logger.Trace($"Dropped duplicate {datagram}"); datagram.Dispose(); return; } recvWithheld[datagram.Sequence % WINDOW_SIZE] = datagram; } else { if (recvEarlyReceived[datagram.Sequence % WINDOW_SIZE]) { //duplicate logger.Trace($"Dropped duplicate {datagram}"); datagram.Dispose(); return; } recvEarlyReceived[datagram.Sequence % WINDOW_SIZE] = true; connection.ReleaseDatagram(datagram); } } }