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(); } }
private void SendAckFromCommand(IncomingCommand command) { bool sendable; UdpChannel channel = _channels[command.Channel]; lock (channel.AckQueue) { sendable = channel.AckQueue.EnqueueOutgoingCommand(command.CreateAck()); } if (sendable) { SendAck(); } }