private void OnPacketReceived(DataPacket dataPacket) { TypedMessage msg = TypedMessage.FromByteArray(dataPacket.payload); if (dataPacket.channel < (byte)EStreamChannel.KEstreamChannelDataChannelStart) { if (dataPacket.channel == (byte)EStreamChannel.KEstreamChannelDiscovery) { throw new NotImplementedException(); } else if (dataPacket.channel == (byte)EStreamChannel.KEstreamChannelControl) { ProcessControlMessage((EStreamControlMessage)msg.messageType, msg.message); } else if (dataPacket.channel == (byte)EStreamChannel.KEstreamChannelStats) { ProcessStatsMessage((EStreamStatsMessage)msg.messageType, msg.message); } } else { ProcessStreamDataMessage(dataPacket.channel, (EStreamDataMessage)msg.messageType, msg.message); } }
private void RecvThread() { while (Active) { try { var from = new IPEndPoint(0, 0); var recvBuffer = udpClient.Receive(ref from); if (recvBuffer == null || recvBuffer.Length == 0) { continue; } NetworkPacket packet = NetworkPacket.FromByteArray(recvBuffer); if ((packet.from != remoteId && packet.from != 0) || (packet.to != localId && packet.to != 0)) { continue; } switch (packet.packetType) { case PacketType.SYN: case PacketType.SYN_ACK: throw new InvalidOperationException(); case PacketType.FIN: SendRawPacket(new NetworkPacket() { packetType = PacketType.FIN, from = localId, to = remoteId }); Reset(); break; case PacketType.Raw: if (packet.channel != (byte)EStreamChannel.KEstreamChannelDiscovery) { throw new InvalidOperationException(); } TypedMessage msg = TypedMessage.FromByteArray(packet.payload); EStreamDiscoveryMessage msgType = (EStreamDiscoveryMessage)msg.messageType; switch (msgType) { case EStreamDiscoveryMessage.KEstreamDiscoveryPingRequest: msg.messageType = (byte)EStreamDiscoveryMessage.KEstreamDiscoveryPingResponse; SendRawPacket(new NetworkPacket() { packetType = PacketType.Raw, from = packet.to, to = packet.from, channel = (byte)EStreamChannel.KEstreamChannelDiscovery, payload = msg.ToByteArray() }); break; default: throw new InvalidOperationException(); } break; case PacketType.Reliable: case PacketType.ReliableFragment: case PacketType.Unreliable: case PacketType.UnreliableFragment: ChannelData channelData = channels.GetOrNew(packet.channel); if (!channelData.receiveQueue.ContainsKey(packet.seq)) { channelData.receiveQueue.Add(packet.seq, packet); if (packet.seq < channelData.remoteSeq) { Console.WriteLine("WARNING! Late packet " + packet.seq + " we are already at " + channelData.remoteSeq); } } else { Console.WriteLine("WARNING! Got a resend of " + packet.seq); } // TODO: Clear the recv queue ushort?lastValidPacketSeq = channelData.remoteSeq > 0 ? (ushort)(channelData.remoteSeq - 1) : (ushort?)null; bool droppedIncompletePacket = false; foreach (NetworkPacket firstPacket in channelData.receiveQueue.Values) { if (firstPacket.seq < channelData.remoteSeq) { continue; } if (firstPacket.packetType == PacketType.ReliableFragment || firstPacket.packetType == PacketType.UnreliableFragment) { continue; } // Check if the packet has all the fragments bool isComplete = true; for (ushort neededSeq = firstPacket.seq; neededSeq <= firstPacket.seq + firstPacket.fragment; ++neededSeq) { if (!channelData.receiveQueue.ContainsKey(neededSeq)) { isComplete = false; break; } else { lastValidPacketSeq = neededSeq; } } if (!isComplete) { // The packet is not yet fully complete if (firstPacket.packetType == PacketType.Unreliable) { droppedIncompletePacket = true; continue; // this is unreliable so check if maybe next packet is complete } else { break; // we cannot skip any packet on reliable transports } } if (channelData.remoteSeq != firstPacket.seq) { Console.WriteLine("WARNING! Dropping unreliable packets! Jump from " + channelData.remoteSeq + " to " + firstPacket.seq + (droppedIncompletePacket ? " (previous incomplete)" : "")); } // We have a complete packet, receive it List <NetworkPacket> reassembleList = new List <NetworkPacket>(); for (ushort seq = firstPacket.seq; seq <= firstPacket.seq + firstPacket.fragment; ++seq) { if (seq != firstPacket.seq) { if (firstPacket.packetType == PacketType.Reliable) { Debug.Assert(channelData.receiveQueue[seq].packetType == PacketType.ReliableFragment); } else if (firstPacket.packetType == PacketType.Unreliable) { Debug.Assert(channelData.receiveQueue[seq].packetType == PacketType.UnreliableFragment); } else { Debug.Assert(false); } } reassembleList.Add(channelData.receiveQueue[seq]); } DataPacket dataPacket = ReassembleDataPacket(reassembleList); try { OnPacketReceived?.Invoke(dataPacket); } catch (Exception e) { Console.WriteLine(e); } channelData.remoteSeq = (ushort)(firstPacket.seq + firstPacket.fragment + 1); } if ((packet.packetType == PacketType.Reliable || packet.packetType == PacketType.ReliableFragment) && lastValidPacketSeq.HasValue) { using (MemoryStream ms = new MemoryStream()) using (BinaryWriter writer = new BinaryWriter(ms)) { writer.Write(channelData.receiveQueue[lastValidPacketSeq.Value].timestamp); writer.Flush(); SendRawPacket(new NetworkPacket() { packetType = PacketType.ReliableACK, from = localId, to = remoteId, channel = packet.channel, seq = lastValidPacketSeq.Value, payload = ms.ToArray() }); } } break; case PacketType.ReliableACK: //Console.WriteLine("ACKed channel=" + packet.channel + ", seq=" + packet.seq); // TODO break; } } catch (SocketException) { } catch (Exception e) { Console.WriteLine(e); } } }