예제 #1
0
        private void AckHandler(IncomingCommand command)
        {
            uint currentRoundTripTime = command.TimestampOfReceive - command.AckReceivedSentTime;

            // Find a channel that the command came, and remove a sent command.
            UdpChannel channel = _channels[command.Channel];
            OutgoingCommand reliableCommand = channel.ReliableSendQueue.ReceiveAck(command);

            //if reliableCommand is null, current command is already received.
            if (reliableCommand == null)
                return;

            if (reliableCommand.CommandType == CommandType.SNTP)
            {
                ProcessSntp(command, currentRoundTripTime);
            }

            _roundTripTime.Update((int)currentRoundTripTime);

            if (_allowStatistics)
            {
                _statistics.UpdateRoundTripTime(_roundTripTime);
                _statistics.ReceiveAck(command.TimestampOfReceive);
            }
        }
        private void ProcessFragmentation(UdpChannel udpChannel, byte[] payload, bool encrypted)
        {
            lock (udpChannel)
            {
                uint available = AvailableSpace;

                short fragmentCount       = (short)((payload.Length + available - 1) / available);
                long  startSequenceNumber = udpChannel.OutgoingReliableSequenceNumber + 1;
                short fragmentNumber      = 0;

                for (long offset = 0; offset < payload.Length; offset += available)
                {
                    if (payload.Length - offset < available)
                    {
                        available = (uint)(payload.Length - offset);
                    }

                    byte[] array = new byte[available];

                    Buffer.BlockCopy(payload, (int)offset, array, 0, (int)available);

                    EnqueueOutgoingCommand(new OutgoingCommand(CommandType.Fragmented, udpChannel.ChannelNumber, encrypted, array)
                    {
                        FragmentNumber      = fragmentNumber,
                        StartSequenceNumber = startSequenceNumber,
                        FragmentCount       = fragmentCount,
                        FragmentOffset      = offset,
                        TotalLength         = payload.Length
                    });

                    fragmentNumber++;
                }
            }
        }
        private bool EnqueueCommand(CommandType commandType, byte[] payload, byte channel, bool encrypted)
        {
            if (channel >= ChannelCount)
            {
                if (_listener != null)
                {
                    string message = string.Format("Cannot send op: Selected channel ({0})>= channelCount ({1})", channel, ChannelCount);
                    _listener.OnStatusChanged(StatusCode.FailedToSend, message);
                }

                return(false);
            }

            UdpChannel udpChannel = _channels[channel];

            if (payload != null && payload.Length > AvailableSpace) //fragmentation
            {
                ProcessFragmentation(udpChannel, payload, encrypted);
            }
            else //non-fragmentation
            {
                EnqueueOutgoingCommand(new OutgoingCommand(commandType, udpChannel.ChannelNumber, encrypted, payload));
            }

            return(true);
        }
        /// <summary>
        /// Process a received command.
        /// (A ack command is processed by a receive thread, other commands is dispatched in a rendering thread.)
        /// </summary>
        private void ExecuteReceiveCommand(IncomingCommand command)
        {
            if (_udpSocket.State != SocketState.Connected)
            {
                return;
            }

            switch (command.Type)
            {
            case CommandType.Acknowledge:
                // Already process a acknowledge command in a receive thread.
                return;

            case CommandType.Disconnect:
                byte[] payload = command.GetPayload();
                int    offset  = 0;

                DisconnectReason disconnectType = (DisconnectReason)ByteRead.GetInt(payload, ref offset);

                var detailMessage = ByteRead.GetString <int>(payload, ref offset, Encoding.UTF8);
                Log(LogLevel.Error, "Disconnect this client[{0}] : {1}", disconnectType, detailMessage);

                Disconnect(disconnectType, false);

                return;

            case CommandType.Reliable:
            case CommandType.Unreliable:
                EnqueueIncomingCommand(command);
                return;

            case CommandType.Fragmented:
                if (command.FragmentNumber > command.FragmentCount ||
                    command.FragmentOffset >= command.TotalLength ||
                    command.FragmentOffset + command.GetPayload().Length > command.TotalLength)
                {
                    Log(LogLevel.Error, "Received fragment has bad size: {0}", command);
                    return;
                }

                if (EnqueueIncomingCommand(command))
                {
                    UdpChannel udpChannel = _channels[command.Channel];

                    ReliableReceiveQueue reliableReceiveQueue = udpChannel.ReliableReceiveQueue as ReliableReceiveQueue;
                    if (reliableReceiveQueue != null)
                    {
                        reliableReceiveQueue.ReceiveFragmentCommand(command);
                    }
                }
                return;

            default:
                Log(LogLevel.Error, "Unknown command received {0}", command.Type);
                return;
            }
        }
        internal void EnqueueOutgoingCommand(OutgoingCommand command)
        {
            UdpChannel udpChannel = _channels[command.Channel];

            lock (udpChannel)
            {
                SendQueueBase queue = command.IsReliable ? (SendQueueBase)udpChannel.ReliableSendQueue : udpChannel.UnreliableSendQueue;
                queue.EnqueueOutgoingCommand(command);
            }
        }
        private void EnqueueSentCommand(OutgoingCommand command, uint currentSendingTime)
        {
            UdpChannel channel = _channels[command.Channel];

            channel.ReliableSendQueue.EnqueueSentCommand(command, currentSendingTime, _roundTripTime.NewRoundTripTime(), (uint)DisconnectTimeout);

            if (_allowStatistics && command.SendAttempts > 1)
            {
                _statistics.ResendCommand();
            }
        }
예제 #7
0
        private void SendAckFromCommand(IncomingCommand command)
        {
            bool sendable;

            UdpChannel channel = _channels[command.Channel];
            lock (channel.AckQueue)
            {
                sendable = channel.AckQueue.EnqueueOutgoingCommand(command.CreateAck());
            }

            if (sendable)
            {
                SendAck();
            }
        }