// remoteWindowStart is remote expected sequence number; everything below this has arrived properly // seqNr is the actual nr received internal override void ReceiveAcknowledge(double now, int seqNr) { // late (dupe), on time or early ack? int relate = NetUtility.RelativeSequenceNumber(seqNr, m_windowStart); if (relate < 0) { //m_connection.m_peer.LogDebug("Received late/dupe ack for #" + seqNr); return; // late/duplicate ack } if (relate == 0) { //m_connection.m_peer.LogDebug("Received right-on-time ack for #" + seqNr); // ack arrived right on time NetException.Assert(seqNr == m_windowStart); bool resetTimeout; m_receivedAcks[m_windowStart] = false; DestoreMessage(now, m_windowStart % m_windowSize, out resetTimeout); m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers; // advance window if we already have early acks while (m_receivedAcks.Get(m_windowStart)) { //m_connection.m_peer.LogDebug("Using early ack for #" + m_windowStart + "..."); m_receivedAcks[m_windowStart] = false; bool rt; DestoreMessage(now, m_windowStart % m_windowSize, out rt); resetTimeout |= rt; NetException.Assert(m_storedMessages[m_windowStart % m_windowSize].Message == null); // should already be destored m_windowStart = (m_windowStart + 1) % NetConstants.NumSequenceNumbers; //m_connection.m_peer.LogDebug("Advancing window to #" + m_windowStart); } if (resetTimeout) { m_connection.ResetTimeout(now); } return; } // // early ack... (if it has been sent!) // // If it has been sent either the m_windowStart message was lost // ... or the ack for that message was lost // //m_connection.m_peer.LogDebug("Received early ack for #" + seqNr); int sendRelate = NetUtility.RelativeSequenceNumber(seqNr, m_sendStart); if (sendRelate <= 0) { // yes, we've sent this message - it's an early (but valid) ack if (m_receivedAcks[seqNr]) { // we've already destored/been acked for this message } else { m_receivedAcks[seqNr] = true; } } else if (sendRelate > 0) { // uh... we haven't sent this message yet? Weird, dupe or error... NetException.Assert(false, "Got ack for message not yet sent?"); return; } // Ok, lets resend all missing acks int rnr = seqNr; do { rnr--; if (rnr < 0) { rnr = NetConstants.NumSequenceNumbers - 1; } if (m_receivedAcks[rnr]) { // m_connection.m_peer.LogDebug("Not resending #" + rnr + " (since we got ack)"); } else { int slot = rnr % m_windowSize; NetException.Assert(m_storedMessages[slot].Message != null); if (m_storedMessages[slot].NumSent == 1) { // just sent once; resend immediately since we found gap in ack sequence NetOutgoingMessage rmsg = m_storedMessages[slot].Message; //m_connection.m_peer.LogVerbose("Resending #" + rnr + " (" + rmsg + ")"); if (now - m_storedMessages[slot].LastSent < (m_resendDelay * 0.35)) { // already resent recently } else { m_storedMessages[slot].LastSent = now; m_storedMessages[slot].NumSent++; m_connection.m_statistics.MessageResent(MessageResendReason.HoleInSequence); Interlocked.Increment(ref rmsg.m_recyclingCount); // increment this since it's being decremented in QueueSendMessage m_connection.QueueSendMessage(rmsg, rnr); } } } } while (rnr != m_windowStart); }