public override void ProcessDataPacket(ITcpDataPacket packet)
        {
            if (BasicTcpPacket.CompareSequences((ushort)(_sequenceIn + 1), packet.Sequence) == 0)
            {
                // This is exactly what we were expecting
                _sequenceIn++;
                if (packet.ResendCount > 0)
                {
                    PacketCountReceiveDataResend++;
                }
                else
                {
                    PacketCountReceiveDataFirst++;
                }
                SendAck(packet, true);
                Socket.BufferClientData(packet.Data);
            }
            else if (BasicTcpPacket.CompareSequences((ushort)(_sequenceIn + 1), packet.Sequence) > 0)
            {
                // This is an old packet, don't process (already did that), just send ack
#if (DEBUG)
                Logger.Debug("Got old Data packet, sending ACK, data already processed.");
#endif
                SendAck(packet, false);
            }
            else
            {
#if (DEBUG)
                Logger.Debug("Got unexpected sequence (expected " + _sequenceIn + ") from packet " + packet);
#endif
            }
        }
Beispiel #2
0
        public void ProcessPacket(byte[] packetData)
        {
            try
            {
                BasicTcpPacket packet = StandardTcpPacketFactory.instance.getPacket(packetData);
#if (DEBUG)
                Logger.Debug("Got packet : " + packet.ToString());
#endif
                switch (packet.Type)
                {
                case BasicTcpPacket.PKT_TYPE_DISCONNECT:
                    ProcessDisconnectPacket((StandardDisconnectPacket)packet);
                    break;

                case BasicTcpPacket.PKT_TYPE_ACK:
                    ProcessAckPacket((StandardAckPacket)packet);
                    break;

                case BasicTcpPacket.PKT_TYPE_DATA:
                    ProcessDataPacket((StandardTcpDataPacket)packet);
                    break;

                case BasicTcpPacket.PKT_TYPE_CONNECT_NAME_RQ:
                    ProcessNamedConnectionRequest((StandardNamedConnectRqPacket)packet);
                    break;

                case BasicTcpPacket.PKT_TYPE_CONNECT_NAME_RS:
                    _tcpConnectionHelper.ProcessConnectRs((StandardNamedConnectRsPacket)packet);
                    break;

                case BasicTcpPacket.PKT_TYPE_CONNECT_RS_ACK:
                    ProcessConnectRsAck((StandardConnectRsAckPacket)packet);
                    break;

                case BasicTcpPacket.PKT_TYPE_DISCONNECT_ACK:
                    _tcpConnectionHelper.ProcessDisconnectAck((StandardDisconnectAckPacket)packet);
                    break;

                case BasicTcpPacket.PKT_TYPE_DISCONNECT_RS:
                    _tcpConnectionHelper.ProcessDisconnectRs((StandardDisconnectRsPacket)packet);
                    break;

                default:
                    throw new UnknownPacketException("Failed to handle packet " + packet);
                }
            }
            catch (UnknownPacketException e)
            {
                Logger.Error("Failed to process TCP packet, unknown type : " + e.Message);
            }
        }
Beispiel #3
0
        // Received this data packet
        public override void ProcessDataPacket(ITcpDataPacket packet)
        {
            if (!Closed)
            {
                lock (_processDataLock)
                {
                    Stats.DataPacketsReceived++;
                    int compareSequences = BasicTcpPacket.CompareSequences(_nextDataSeqIn, packet.Sequence);
                    if (compareSequences == 0)
                    {
                        Stats.ExpectedDataPacketsReceived++;
                        if (BasicTcpPacket.CompareSequences(packet.Sequence, _highestDataSeqIn) > 0)
                        {
                            _highestDataSeqIn = packet.Sequence;
                        }
                        // This is exactly what we were expecting
                        // pop it in our list
                        ITcpDataPacket currentPacket = _recvWindow[_recvWindowsNextFree] = packet;
                        // Now flush our window until we get to a gap
                        while (_recvWindow[_recvWindowsNextFree] != null)
                        {
                            currentPacket = _recvWindow[_recvWindowsNextFree];
                            // Send Data Upstream (only it not closed)
                            if (!Socket.Closed && !Socket.Closing)
                            {
                                Socket.BufferClientData(currentPacket.Data);
                            }
#if DEBUG
                            else
                            {
                                Logger.Debug("Got a data packet, but not writing to socket, because its closed or closing");
                            }
#endif
                            // clear this space in our window
                            _recvWindow[_recvWindowsNextFree] = null;
                            // increment our pointer to next space
                            _recvWindowsNextFree = (byte)((_recvWindowsNextFree + 1) % WindowSize);
                            // increment our next next expected sequence number
                            _nextDataSeqIn++;
#if DEBUG
                            Logger.Debug("Processed sq=" + currentPacket.Sequence + " upstream, nextDataSeqIn=" +
                                         _nextDataSeqIn + ", recvWindowNextFree=" + _recvWindowsNextFree +
                                         ", highestDataSeqIn=" + _highestDataSeqIn);
#endif
                        }
                        // Send Ack (only when done with sending all the packets we can)
                        SendAck(currentPacket, currentPacket, true);
                        _lastAckedPacket = currentPacket;
                    }
                    else if (compareSequences > 0)
                    {
                        Stats.OldDataPacketsReceived++;
                        if (packet.ResendCount > 0)
                        {
                            Stats.OldDataResendPacketsReceived++;
                        }
                        // This is an old packet, don't process (already did that), just send ack
#if DEBUG
                        Logger.Debug("Got old Data packet (resend=" + packet.ResendCount +
                                     "), sending ACK, data already processed.");
#endif
                        SendAck(packet, _lastAckedPacket, false);
                    }
                    else
                    {
                        Stats.FutureDataPacketsReceived++;
                        // This is an out of sequence packet from the future,
                        // if it fits in our window, we need to save it for future use
                        int differenceInSequences = DifferenceInSequences(_nextDataSeqIn, packet.Sequence);
                        if (differenceInSequences < WindowSize)
                        {
                            // ok we can put it in
                            _recvWindow[(_recvWindowsNextFree + differenceInSequences) % WindowSize] = packet;
                            if (BasicTcpPacket.CompareSequences(packet.Sequence, _highestDataSeqIn) > 0)
                            {
                                _highestDataSeqIn = packet.Sequence;
                            }
#if DEBUG
                            Logger.Debug("Queued sq=" + packet.Sequence + " in window, nextDataSeqIn=" + _nextDataSeqIn +
                                         ", recvWindowNextFree=" + _recvWindowsNextFree + ", highestDataSeqIn=" +
                                         _highestDataSeqIn);
#endif
                            // Now we send an ack for the last in sequence packet we received
                            if (_lastAckedPacket != null)
                            {
                                SendAck(packet, _lastAckedPacket, false);
                                Stats.HoldingAcksSent++;
                            }
                        }
                        else
                        {
#if DEBUG
                            Logger.Debug("Got too far in the future sequence (expected " + _nextDataSeqIn + ") from packet " +
                                         packet + ", dropping");
#endif
                            // Now we send an ack for the last in sequence packet we received
                            if (_lastAckedPacket != null)
                            {
                                SendAck(_lastAckedPacket, _lastAckedPacket, false);
                                Stats.HoldingAcksSent++;
                            }
                        }
                    }
#if DEBUG
                    if (Stats.DataPacketsReceived % 1000 == 0)
                    {
                        Logger.Debug("Received Stats:\n" + Stats.GetReceiverStats());
                    }
#endif

                    Monitor.PulseAll(_processDataLock);
                }
            }
            else
            {
                Logger.Error("Failed to process data packet, the connection closed.");
            }
        }
Beispiel #4
0
        // 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);
            }
        }