Пример #1
0
 private void CreateSendRecieveChannels()
 {
     this.noneSendChannel               = new SendChannel(SendOptions.None, sendDatagramsPool);
     this.inOrderSendChannel            = new SendChannel(SendOptions.InOrder, sendDatagramsPool);
     this.reliableSendChannel           = new SendChannel(SendOptions.Reliable, sendDatagramsPool);
     this.reliableInOrderSendChannel    = new SendChannel(SendOptions.ReliableInOrder, sendDatagramsPool);
     this.noneReceiveChannel            = new ReceiveChannel(SendOptions.None, this.localPeer, this);
     this.inOrderReceiveChannel         = new ReceiveChannel(SendOptions.InOrder, this.localPeer, this);
     this.reliableReceiveChannel        = new ReceiveChannel(SendOptions.Reliable, this.localPeer, this);
     this.reliableInOrderReceiveChannel = new ReceiveChannel(SendOptions.ReliableInOrder, this.localPeer, this);
 }
Пример #2
0
        // returns true if caller should continue adding any additional packets in datagram
        internal bool TryAddReceivedPacket(
            ushort seq,
            SendOptions opts,
            PacketType type,
            byte[]      buffer,
            int index,
            int payloadSize,
            bool isFirstPacketInDatagram)
        {
            // If we are not the keep alive master, i.e. this remote peer is, and this packet was
            // sent reliably reset ellpasedMilliseondsAtLastRealiablePacket[Received].
            if (IsKeepAliveMaster && ((opts & SendOptions.Reliable) == SendOptions.Reliable))
            {
                ellapasedSecondsSinceLastRealiablePacket = 0.0f;
            }

            switch (type)
            {
            case PacketType.Application:
            case PacketType.KeepAlive:
            case PacketType.AcceptJoin:
            {
                bool wasAppPacketAdded;

                ReceiveChannel channel = noneReceiveChannel;
                switch (opts)
                {
                case SendOptions.InOrder:           channel = inOrderReceiveChannel;            break;

                case SendOptions.Reliable:          channel = reliableReceiveChannel;           break;

                case SendOptions.ReliableInOrder:   channel = reliableInOrderReceiveChannel;    break;
                }

                if (!channel.TryAddReceivedPacket(seq, type, buffer, index, payloadSize, isFirstPacketInDatagram, out wasAppPacketAdded))
                {
                    return(false);
                }

                if (wasAppPacketAdded)
                {
                    unreadPacketCount++;
                }

                return(true);
            }

            case PacketType.ACK:
            {
                // Look for the oldest datagram with the same seq AND channel type
                // seq is for which we ASSUME the ACK is for.
                int      datagramIndex;
                Datagram sentDatagramAwaitingAck = null;
                for (datagramIndex = 0; datagramIndex < sentDatagramsAwaitingACK.Count; datagramIndex++)
                {
                    Datagram datagram = sentDatagramsAwaitingACK[datagramIndex];
                    if (datagram.Sequence == seq && datagram.SendOptions == opts)
                    {
                        sentDatagramAwaitingAck = datagram;
                        break;
                    }
                }

                if (sentDatagramAwaitingAck == null)
                {
                    // Possible reasons:
                    // 1) ACK has arrived too late and the datagram must have already been removed.
                    // 2) ACK duplicated and has already been processed
                    // 3) ACK was unsolicited (i.e. malicious or buggy peer)

                    // NOTE: If ACK "piggy-backed" on a reliable datagram that was re-sent
                    //       that datagram if recieved more than once would have been dropped
                    //       when processing the first Application packet so should never
                    //       get to here.

                    localPeer.Log(LogLevel.Warning, "Datagram for ACK not found - too late?");
                }
                else
                {
                    // recieving our first ACK from this peer means they have Accepted us
                    if (!hasAccepted)
                    {
                        hasAccepted = true;
                    }

                    // remove datagram
                    sentDatagramsAwaitingACK.RemoveAt(datagramIndex);

                    // Update QoS
                    // ----------
                    //
                    // If the datagram was not re-sent update latency, otherwise we do not
                    // know which send this ACK is for so cannot determine latency.
                    //
                    // Also update re-sends sample if datagram was not re-sent with: not
                    // re-sent. If was re-sent sample would have already been updated when
                    // re-sent.

                    if (sentDatagramAwaitingAck.ResentCount == 0)
                    {
                        TimeSpan rtt = localPeer.Stopwatch.Elapsed - sentDatagramAwaitingAck.EllapsedAtSent;
                        qualityOfService.UpdateLatency(rtt);
                        qualityOfService.UpdateResentSample(false);

                        localPeer.Log(LogLevel.Debug, String.Format("ACK from: {0}, channel: {1}, seq: {2}, RTT: {3}s", PeerName, opts.ToString(), seq.ToString(), rtt.TotalSeconds.ToString()));
                        localPeer.Log(LogLevel.Debug, String.Format("Latency now: {0}s", qualityOfService.RoudTripTime.TotalSeconds.ToString()));
                    }
                    else
                    {
                        localPeer.Log(LogLevel.Info, String.Format("ACK for re-sent datagram: {0}, channel: {1}, seq: {2}", PeerName, opts.ToString(), seq.ToString()));
                    }


                    // return datagram
                    sendDatagramsPool.Return(sentDatagramAwaitingAck);
                }

                return(true);
            }

            case PacketType.Ping:
            {
                return(Pong());
            }

            case PacketType.Pong:
            {
                if (localPeer.HasPingsAwaitingPong)
                {
                    PingDetail detail = localPeer.PingsAwaitingPong.Find(pd => pd.PeerIdPingSentTo == Id);
                    if (detail != null)
                    {
                        localPeer.RaisePongReceived(this, TimeSpan.FromSeconds(detail.EllapsedSeconds));
                        localPeer.RemovePingAwaitingPongDetail(detail);
                    }
                }

                return(true);
            }

            case PacketType.JoinRequest:
            {
                if (hasAccepted)
                {
                    // If peer has accepted must be is joining again (possible when did not
                    // say Bye and has restarted again before timed out). Drop this
                    // instance of peer and process Accept next update so both peers on
                    // the same page, i.e. that we are starting a new connection.
                    //
                    byte[] datagram = new byte[Const.FALCON_PACKET_HEADER_SIZE + payloadSize];
                    FalconHelper.WriteFalconHeader(datagram, 0, PacketType.JoinRequest, SendOptions.None, (ushort)seq, (ushort)payloadSize);
                    if (payloadSize > 0)
                    {
                        Buffer.BlockCopy(buffer, index, datagram, Const.FALCON_PACKET_HEADER_SIZE, payloadSize);
                    }
                    localPeer.RemovePeerOnNextUpdate(this);
                    localPeer.EnqueuePacketToProcessOnNextUpdate(this.EndPoint, datagram);
                    return(false);
                }
                return(Accept());
            }

            case PacketType.DiscoverRequest:
            {
                DiscoverReply();
                return(true);
            }

            case PacketType.DiscoverReply:
            {
                // do nothing, DiscoveryReply only relevant when peer not added
                return(true);
            }

            case PacketType.Bye:
            {
                localPeer.Log(LogLevel.Info, String.Format("Bye received from: {0}.", PeerName));
                localPeer.RemovePeerOnNextUpdate(this);
                return(false);
            }

            default:
            {
                localPeer.Log(LogLevel.Error, String.Format("Datagram dropped - unexpected type: {0}, received from authenticated peer: {1}.", type, PeerName));
                return(false);
            }
            }
        }