public BasicTcpPacket getPacket(byte[] bytes) { BasicTcpPacket packet; switch (bytes[BasicTcpPacket.PKT_POS_TYPE]) { case BasicTcpPacket.PKT_TYPE_DISCONNECT: packet = new StandardDisconnectPacket(); break; case BasicTcpPacket.PKT_TYPE_DISCONNECT_ACK: packet = new StandardDisconnectAckPacket(); break; case BasicTcpPacket.PKT_TYPE_DISCONNECT_RS: packet = new StandardDisconnectRsPacket(); break; case BasicTcpPacket.PKT_TYPE_CONNECT_RS_ACK: packet = new StandardConnectRsAckPacket(); break; case BasicTcpPacket.PKT_TYPE_CONNECT_NAME_RS: packet = new StandardNamedConnectRsPacket(); break; case BasicTcpPacket.PKT_TYPE_CONNECT_NAME_RQ: packet = new StandardNamedConnectRqPacket(); break; case BasicTcpPacket.PKT_TYPE_DATA: packet = new StandardTcpDataPacket(); break; case BasicTcpPacket.PKT_TYPE_ACK: packet = new StandardAckPacket(); break; case BasicTcpPacket.PKT_TYPE_NOP: packet = new StandardTcpNopPacket(); break; default: throw new UnknownPacketException("Failed to determine packet type"); } packet.ProcessPacket(bytes); return packet; }
private void SendAck(ITcpPacket packet, bool firstSend) { StandardAckPacket outPacket = new StandardAckPacket(packet.Sequence); outPacket.ConnectionId = ConnectionId; try { Transport.SendData(outPacket); #if DEBUG Logger.Debug("Sent ack [" + outPacket + "]"); #endif if (firstSend) { PacketCountTransmitAckFirst++; } else { PacketCountTransmitAckResend++; } } catch (Exception e) { Logger.Error("Failed to send ack to peer for packet " + packet.Sequence + " : " + e.Message); } }
public override void ProcessAck(StandardAckPacket packet) { if (packet.Sequence == _sequenceOut) { PacketCountReceiveAckValid++; _ackEvent.Set(); } else { PacketCountReceiveAckInvalid++; #if DEBUG Logger.Debug("Dropping unexpected ack : " + packet); #endif } }
private void ProcessAckPacket(StandardAckPacket packet) { try { TcpConnectionHolder conn = _tcpConnections.GetRemoteConnection(packet.ConnectionId); // Lock sending while we process this packet (we will still be able to receive) // Now TcpConnection doesn't have to be threadsafe, but each connection // can process acks independently at full speed. lock (conn.SendLock) { // now process the ackPacket; conn.Connection.ProcessAck(packet); } } catch (ConnectionException e) { Logger.Error("Dropping ack packet [" + packet + "], failed to get a connection : " + e.Message); } }
private void SendAck(ITcpDataPacket packet, ITcpDataPacket lastDataPacket, bool firstSend) { StandardAckPacket outPacket = new StandardAckPacket(packet.Sequence) { ConnectionId = ConnectionId, ResendCount = packet.ResendCount, CurrentDataAck = lastDataPacket.Sequence }; try { Transport.SendData(outPacket); if (firstSend) Stats.AcksSent++; else Stats.AcksResent++; #if DEBUG Logger.Debug("Sent ack [" + outPacket + "]"); #endif } catch (Exception e) { Logger.Error("Failed to send ack to peer for packet " + packet.Sequence + " : " + e.Message, e); } }
// received this ack public override void ProcessAck(StandardAckPacket packet) { Stats.AcksReceived++; lock (_ackWaitingLock) { // update the rtt based on this packet if its a fresh ack and there is something in the window if (packet.ResendCount == 0 && _sendWindow[_oldestUnackedPacket] != null) { // Is this packets seq ahead of the ones we are expecting int seqDiff = BasicTcpPacket.CompareSequences(_sendWindow[_oldestUnackedPacket].Sequence, packet.Sequence); if (seqDiff <= 0) { int distance = DifferenceInSequences(_sendWindow[_oldestUnackedPacket].Sequence, packet.Sequence); if (distance < WindowSize) { var matchingDataPacket = _sendWindow[(_oldestUnackedPacket + distance) % WindowSize]; if (matchingDataPacket != null && matchingDataPacket.Sequence == packet.Sequence) { long rtt = Environment.TickCount - matchingDataPacket.Timestamp; AdjustRetryInterval(rtt); #if DEBUG Logger.Debug("RTT of " + matchingDataPacket + " is " + rtt + ", srtt=" + _srtt + ", deviation=" + _deviation + ", retryInterval=" + _retryInterval); #endif } else { Logger.Error("Got an ack " + packet + " but can't find matching data packet, oldest unacked is " + _sendWindow[_oldestUnackedPacket] + ", nextSeqOut=" + _nextDataSeqOut + ", nextSeqIn=" + _nextDataSeqIn + ", lastAckPaket=" + _lastAckPacket); } } else { Logger.Error("Got an ack for a message too far in the future [distance=" + distance + "]"); } } else { #if DEBUG Logger.Debug("Got an ack from the past, cannot use it to calculate RTT"); #endif } } // loop through expected acks clearing them until we are in sync with incoming ack packet while (_sendWindow[_oldestUnackedPacket] != null) { // current data packet in the window var currentDataPacket = _sendWindow[_oldestUnackedPacket]; int seqDiff = BasicTcpPacket.CompareSequences(currentDataPacket.Sequence, packet.CurrentDataAck); // If this incoming packet's currentDataAck is the one we are expecting (==) or one ahead of our current // expected ack < (indicating receiver has all those up until this one) if (seqDiff <= 0) { // null the packet (its acked) _sendWindow[_oldestUnackedPacket] = null; // oldestUnackedPaket is now the next one _oldestUnackedPacket = (byte)((_oldestUnackedPacket + 1) % WindowSize); #if DEBUG Logger.Debug("Cleared old packet " + currentDataPacket.Sequence + ", oldestUnackedPacket=" + _oldestUnackedPacket); #endif // save the last ack we received (and the count) _lastAckPacketSeq = currentDataPacket.Sequence; // and we have received it once _lastAckPacketCount = 1; // if the current pack is the exact one we received an ack for // then lets reset the timer and leave the loop if (seqDiff == 0) { lock (_retryTimer) { // reset the time against the next unacked packet long timeLeft = _retryInterval - (Environment.TickCount - currentDataPacket.Timestamp); if (timeLeft <= 0) timeLeft = 1; if (_retryTimer.Enabled) { _retryTimer.Stop(); } _retryTimer.Interval = timeLeft; #if DEBUG Logger.Debug("Setup retransmit timeout for " + currentDataPacket.Sequence + " to " + timeLeft + "ms."); #endif _retryTimer.Start(); } break; } } else { if (packet.CurrentDataAck == _lastAckPacketSeq) { // this is an old ack, if we get 3, we retrasmit the next one _lastAckPacketCount++; #if DEBUG Logger.Debug("Discarding the repeated ack " + packet + "[" + _lastAckPacketCount + " times], checking for retransmit"); #endif // we only resend via fast transmit if it is a count of 3 and it hasn't been resent before if (_lastAckPacketCount == 3) { RunFastRetransmit(currentDataPacket); } } else { // old ack too far back to care #if DEBUG Logger.Debug("Discarding old ack " + packet); #endif Stats.OldAcksReceived++; } break; } } #if DEBUG Logger.Debug("Finished processing ack " + packet.Sequence + ", expecting next ack to be " + (_sendWindow[_oldestUnackedPacket] == null ? "none" : _sendWindow[_oldestUnackedPacket].Sequence.ToString())); #endif Monitor.PulseAll(_ackWaitingLock); } }
public abstract void ProcessAck(StandardAckPacket packet);