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);
            }
        }
Beispiel #2
0
        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);
                }
            }
        }