public IncomingCommand QueueIncomingCommand(Protocol command, Packet packet, uint fragmentCount) { Channel channel = command.ChannelID == 0xFF ? null : Channels[command.ChannelID]; var notifyError = fragmentCount > 0 ? null : new IncomingCommand(); if (State == PeerState.DISCONNECT_LATER) { return(notifyError); } uint unreliableSequenceNumber = 0; uint reliableSequenceNumber = 0; if (!(command is Protocol.Send.Unsequenced)) { reliableSequenceNumber = command.ReliableSequenceNumber; ushort reliableWindow = (ushort)(reliableSequenceNumber / RELIABLE_WINDOW_SIZE); ushort currentWindow = (ushort)(channel.IncomingReliableSequenceNumber / RELIABLE_WINDOW_SIZE); if (reliableSequenceNumber < channel.IncomingReliableSequenceNumber) { reliableWindow += RELIABLE_WINDOWS; } if (reliableWindow < currentWindow || reliableWindow >= currentWindow + FREE_RELIABLE_WINDOWS - 1u) { return(notifyError); } } LList <IncomingCommand> .Node currentCommand; IncomingCommand incomingCommand; switch (command) { case Protocol.Send.Fragment _: case Protocol.Send.Reliable _: if (reliableSequenceNumber == channel.IncomingReliableSequenceNumber) { return(notifyError); } for (currentCommand = channel.IncomingReliableCommands.End.Prev; currentCommand != channel.IncomingReliableCommands.End; currentCommand = currentCommand.Prev) { incomingCommand = currentCommand.Value; if (reliableSequenceNumber >= channel.IncomingReliableSequenceNumber) { if (incomingCommand.ReliableSequenceNumber < channel.IncomingReliableSequenceNumber) { continue; } } else if (incomingCommand.ReliableSequenceNumber >= channel.IncomingReliableSequenceNumber) { break; } if (incomingCommand.ReliableSequenceNumber <= reliableSequenceNumber) { if (incomingCommand.ReliableSequenceNumber < reliableSequenceNumber) { break; } return(notifyError); } } break; case Protocol.Send.Unreliable sendUnreliable: unreliableSequenceNumber = sendUnreliable.UnreliableSequenceNumber; if (reliableSequenceNumber == channel.IncomingReliableSequenceNumber && unreliableSequenceNumber <= channel.IncomingUnreliableSequenceNumber) { return(notifyError); } for (currentCommand = channel.IncomingUnreliableCommands.End.Prev; currentCommand != channel.IncomingUnreliableCommands.End; currentCommand = currentCommand.Prev) { incomingCommand = currentCommand.Value; if (!(incomingCommand.Command is Protocol.Send.Unreliable)) { continue; } if (reliableSequenceNumber >= channel.IncomingReliableSequenceNumber) { if (incomingCommand.ReliableSequenceNumber < channel.IncomingReliableSequenceNumber) { continue; } } else if (incomingCommand.ReliableSequenceNumber >= channel.IncomingReliableSequenceNumber) { break; } if (incomingCommand.ReliableSequenceNumber < reliableSequenceNumber) { break; } if (incomingCommand.ReliableSequenceNumber > reliableSequenceNumber) { continue; } if (incomingCommand.UnreliableSequenceNumber <= unreliableSequenceNumber) { if (incomingCommand.UnreliableSequenceNumber < unreliableSequenceNumber) { break; } return(notifyError); } } break; case Protocol.Send.Unsequenced _: currentCommand = channel.IncomingUnreliableCommands.End; break; default: return(notifyError); } incomingCommand = new IncomingCommand { ReliableSequenceNumber = command.ReliableSequenceNumber, UnreliableSequenceNumber = (ushort)(unreliableSequenceNumber & 0xFFFF), Command = command, FragmentCount = fragmentCount, FragmentsRemaining = fragmentCount, Packet = packet, Fragments = new BitArray((int)fragmentCount), // CHECKME: (fragmentCount + 31) / 32 }; currentCommand.Next.Insert(incomingCommand.Node); switch (command) { case Protocol.Send.Fragment _: case Protocol.Send.Reliable _: DispatchIncomingReliableCommands(channel); break; default: DispatchIncomingUnreliableCommands(channel); break; } return(incomingCommand); }
private int HandleSendFragment(Peer peer, Protocol.Send.Fragment command, Buffer buffer) { if (command.ChannelID >= peer.ChannelCount) { return(-1); } if (peer.State != PeerState.CONNECTED && peer.State != PeerState.DISCONNECT_LATER) { return(-1); } if (command.DataLength > buffer.BytesLeft) { return(-1); } uint fragmentLength = command.DataLength; var channel = peer.Channels[command.ChannelID]; uint startSequenceNumber = command.StartSequenceNumber; ushort startWindow = (ushort)(startSequenceNumber / Peer.RELIABLE_WINDOW_SIZE); ushort currentWindow = (ushort)(channel.IncomingReliableSequenceNumber / Peer.RELIABLE_WINDOW_SIZE); if (startSequenceNumber < channel.IncomingReliableSequenceNumber) { startWindow += Peer.RELIABLE_WINDOWS; } if (startWindow < currentWindow || startWindow >= currentWindow + Peer.FREE_RELIABLE_WINDOWS - 1) { return(0); } uint fragmentNumber = command.FragmentNumber; uint fragmentCount = command.FragmentCount; uint fragmentOffset = command.FragmentOffset; uint totalLength = command.TotalLength; if (fragmentOffset >= totalLength || fragmentOffset + fragmentLength > totalLength || fragmentNumber >= fragmentCount) { return(-1); } IncomingCommand startCommand = null; for (var currentCommand = channel.IncomingReliableCommands.End.Prev; currentCommand != channel.IncomingReliableCommands.End; currentCommand = currentCommand.Prev) { var incomingCommand = currentCommand.Value; if (startSequenceNumber >= channel.IncomingReliableSequenceNumber) { if (incomingCommand.ReliableSequenceNumber < channel.IncomingReliableSequenceNumber) { continue; } } else if (incomingCommand.ReliableSequenceNumber >= channel.IncomingReliableSequenceNumber) { break; } if (incomingCommand.ReliableSequenceNumber <= startSequenceNumber) { if (incomingCommand.ReliableSequenceNumber < startSequenceNumber) { break; } if (!(incomingCommand.Command is Protocol.Send.Fragment) || totalLength != incomingCommand.Packet.DataLength || fragmentCount != incomingCommand.FragmentCount) { return(-1); } startCommand = incomingCommand; break; } } if (startCommand == null) { var packet = new Packet(totalLength, PacketFlags.RELIABLE); var hostCommand = command; hostCommand.ReliableSequenceNumber = (ushort)startSequenceNumber; hostCommand.StartSequenceNumber = (ushort)startSequenceNumber; hostCommand.DataLength = (ushort)fragmentLength; hostCommand.FragmentNumber = fragmentNumber; hostCommand.FragmentCount = fragmentCount; hostCommand.FragmentOffset = fragmentOffset; hostCommand.TotalLength = totalLength; startCommand = peer.QueueIncomingCommand(hostCommand, packet, fragmentCount); } if (!startCommand.Fragments[(int)fragmentNumber]) { startCommand.FragmentsRemaining--; startCommand.Fragments[(int)fragmentNumber] = true; if (fragmentOffset + fragmentLength > startCommand.Packet.DataLength) { fragmentLength = startCommand.Packet.DataLength - fragmentOffset; } buffer.ReadBytes(startCommand.Packet.Data, fragmentOffset, fragmentLength); if (startCommand.FragmentsRemaining <= 0) { peer.DispatchIncomingReliableCommands(channel); } } return(0); }