Esempio n. 1
0
        void ManageFragment(Datagram datagram)
        {
            if (!datagram.IsFragmented)
            {
                datagram.Dispose();
                throw new InvalidOperationException("Datagram isn't fragemented");
            }

            if (datagram.FragmentationInfo.Frame > datagram.FragmentationInfo.Frames)
            {
                logger.Error($"Invalid fragmented datagram frame {datagram.FragmentationInfo.Frame} > frames {datagram.FragmentationInfo.Frames}. Dropping...");
                datagram.Dispose();
                return;
            }

            FragmentHolder fragmentHolder = this.fragments.GetOrAdd(datagram.FragmentationInfo.FragmentationGroupId, (groupId) =>
            {
                return(new FragmentHolder(datagram.FragmentationInfo.FragmentationGroupId, datagram.FragmentationInfo.Frames));
            });

            fragmentHolder.SetFrame(datagram);

            if (fragmentHolder.IsCompleted)
            {
                if (this.fragments.TryRemove(datagram.FragmentationInfo.FragmentationGroupId, out FragmentHolder removed))
                {
                    var message = fragmentHolder.Merge(peer.Configuration.MemoryStreamPool);
                    ReleaseMessage(message, datagram.DeliveryType, datagram.Channel);
                    fragmentHolder.Dispose();
                }
            }
        }
Esempio n. 2
0
        void OnMtuExpand(Datagram datagram)
        {
            if (!CheckStatus(datagram, UdpConnectionStatus.Connected))
            {
                return;
            }

            int  size = datagram.GetTotalSize();
            byte fix  = 0;

            if (size > peer.Configuration.LimitMtu)
            {
                size = peer.Configuration.LimitMtu;
                fix  = 1;
            }

            logger.Debug($"MTU Successfully expanded to {size} by request from other side");
            var mtuDatagram = CreateSpecialDatagram(MessageType.ExpandMTUSuccess, 5);

            using (WardenStreamWriter writer = new WardenStreamWriter(mtuDatagram.BaseStream, true))
            {
                writer.WriteVarInt(size);
                writer.Write(fix);
            }
            if (size > this.Mtu)
            {
                this.Mtu = size;
            }
            _ = SendDatagramAsync(mtuDatagram);

            datagram.Dispose();
        }
        void OnPing(Datagram datagram)
        {
            if (!CheckStatus(datagram, UdpConnectionStatus.Connected))
            {
                return;
            }

            SendPong(datagram);
            datagram.Dispose();
        }
Esempio n. 4
0
 bool CheckStatus(Datagram datagram, params UdpConnectionStatus[] status)
 {
     if (!CheckStatus(status))
     {
         string expected = string.Join(",", status.Select(s => s.ToString()));
         logger.Debug($"Got {datagram.Type} in wrong connection status: {Status}, expected: {expected}. Dropping...");
         datagram.Dispose();
         return(false);
     }
     return(true);
 }
Esempio n. 5
0
        void OnDisconnectReq(Datagram datagram)
        {
            if (!CheckStatus(datagram, UdpConnectionStatus.Connected))
            {
                return;
            }

            SendDatagramAsync(CreateSpecialDatagram(MessageType.DisconnectResp));
            CloseInternal(DisconnectReason.ClosedByOtherPeer, datagram.ConvertToMessage());
            datagram.Dispose();
        }
Esempio n. 6
0
 void IChannelConnection.ReleaseDatagram(Datagram datagram)
 {
     if (datagram.IsFragmented)
     {
         ManageFragment(datagram);
     }
     else
     {
         ReleaseMessage(datagram.ConvertToMessage(), datagram.DeliveryType, datagram.Channel);
         datagram.Dispose();
     }
 }
Esempio n. 7
0
        void OnConnectResp(Datagram datagram)
        {
            if (!CheckStatus(datagram, UdpConnectionStatus.Connecting))
            {
                return;
            }

            ChangeStatus(UdpConnectionStatus.Connected);
            connectReq.Dispose();
            connectReq = null;
            datagram.Dispose();
        }
        void OnPong(Datagram datagram)
        {
            if (!CheckStatus(datagram, UdpConnectionStatus.Connected))
            {
                return;
            }

            int relate = ChannelBase.RelativeSequenceNumber(datagram.Sequence, lastPingSequence);

            if (relate != 0)
            {
                logger.Debug($"Got wrong pong, relate: {relate}");
                datagram.Dispose();
                return;
            }

            float latency = (float)(DateTime.UtcNow - lastPingSent).TotalMilliseconds;

            UpdateLatency(latency);

            datagram.Dispose();
        }
 public override void OnDatagram(Datagram datagram)
 {
     CheckDatagramValid(datagram);
     connection.ReleaseDatagram(datagram);
     lock (channelMutex)
     {
         int relate = RelativeSequenceNumber(datagram.Sequence, lastSequenceIn + 1);
         if (relate < 0)
         {
             logger.Debug($"Dropping old {datagram}");
             datagram.Dispose();
             return; //drop old
         }
         lastSequenceIn = datagram.Sequence;
     }
 }
Esempio n. 10
0
        internal void OnDatagram(Datagram datagram)
        {
            if (datagram.ConnectionKey != this.EndPoint.ConnectionKey)
            {
                logger.Warn($"Got wrong {datagram}: connection id mismatch");
                datagram.Dispose();
                return;
            }

            Statistics.PacketIn();
            Statistics.BytesIn(datagram.GetTotalSize());

            switch (datagram.Type)
            {
            case MessageType.ConnectReq:
                OnConnectReq(datagram); break;

            case MessageType.ConnectResp:
                OnConnectResp(datagram); break;

            case MessageType.DisconnectReq:
                OnDisconnectReq(datagram); break;

            case MessageType.DisconnectResp:
                OnDisconnectResp(datagram); break;

            case MessageType.Ping:
                OnPing(datagram); break;

            case MessageType.Pong:
                OnPong(datagram); break;

            case MessageType.ExpandMTURequest:
                OnMtuExpand(datagram); break;

            case MessageType.ExpandMTUSuccess:
                OnMtuSuccess(datagram); break;

            case MessageType.DeliveryAck:
                OnAckReceived(datagram); break;

            default:
                OnDataReceived(datagram); break;
            }
        }
Esempio n. 11
0
        void OnConnectReq(Datagram datagram)
        {
            switch (Status)
            {
            case UdpConnectionStatus.Connected:
                logger.Debug($"Got late {datagram.Type} resend connect resp");
                SendDatagramAsync(CreateSpecialDatagram(MessageType.ConnectResp));
                break;

            case UdpConnectionStatus.Waiting:
                var connectionAccepted = peer.OnAcceptConnection(new OnAcceptConnectionEventArgs(this.EndPoint.EndPoint, datagram.ConvertToMessage()));
                if (connectionAccepted)
                {
                    logger.Debug($"Accepting connection {this}");
                    SendDatagramAsync(CreateSpecialDatagram(MessageType.ConnectResp));
                    ChangeStatus(UdpConnectionStatus.Connected);
                }
                else
                {
                    logger.Debug($"Rejecting connection {this}");
                    SendDatagramAsync(CreateSpecialDatagram(MessageType.DisconnectResp));
                    ChangeStatus(UdpConnectionStatus.Disconnected);
                }
                break;

            case UdpConnectionStatus.Disconnected:
                logger.Debug($"Got late {datagram.Type}, but connection is closed. Resend disconnect resp");
                SendDatagramAsync(CreateSpecialDatagram(MessageType.DisconnectResp));
                break;

            default:
                logger.Debug($"Got {datagram.Type} in wrong connection status: {Status}. Dropping...");
                break;
            }

            datagram.Dispose();
        }
Esempio n. 12
0
        public override void OnAckReceived(Datagram datagram)
        {
            lock (channelMutex)
            {
                int relate = RelativeSequenceNumber(datagram.Sequence, ackWindowStart);
                if (relate < 0)
                {
                    logger.Trace("Got duplicate/late ack");
                    datagram.Dispose();
                    return; //late/duplicate ack
                }

                if (relate == 0)
                {
                    logger.Trace($"Got ack just in time, clearing pending {datagram}");
                    //connection.UpdateLatency(sendPendingPackets[ackWindowStart % WINDOW_SIZE].GetDelay());

                    sendPendingPackets[ackWindowStart % WINDOW_SIZE].Clear();
                    ackWindowStart = (ackWindowStart + 1) % MAX_SEQUENCE;

                    while (sendPendingPackets[ackWindowStart % WINDOW_SIZE].AckReceived)
                    {
                        logger.Trace($"Clearing early pending {datagram}");
                        sendPendingPackets[ackWindowStart % WINDOW_SIZE].Clear();
                        ackWindowStart = (ackWindowStart + 1) % MAX_SEQUENCE;
                    }

                    datagram.Dispose();
                    TrySendDelayedPackets();

                    return;
                }

                int sendRelate = RelativeSequenceNumber(datagram.Sequence, lastSequenceOut);
                if (sendRelate < 0)
                {
                    if (sendRelate < -WINDOW_SIZE)
                    {
                        logger.Trace("Very old ack received");
                        datagram.Dispose();
                        return;
                    }
                    //we have sent this message, it's just early
                    if (sendPendingPackets[datagram.Sequence % WINDOW_SIZE].GotAck())
                    {
                        //connection.UpdateLatency(sendPendingPackets[ackWindowStart % WINDOW_SIZE].GetDelay());
                        logger.Trace($"Got early ack {datagram} {sendRelate} {relate}");
                    }
                    else
                    {
                        logger.Debug($"Got ack {datagram} for packet we're not waiting for {sendRelate} {relate}");
                    }
                }
                else if (sendRelate > 0)
                {
                    logger.Debug("Got Ack for message we have not sent");
                }

                datagram.Dispose();

                //Probably gap in ack sequence need faster message resend
                //int curSequence = datagram.Sequence;
                //do
                //{
                //    curSequence--;
                //    if (curSequence < 0)
                //        curSequence = MAX_SEQUENCE - 1;

                //    int slot = curSequence % WINDOW_SIZE;
                //    if (!ackReceived[slot])
                //    {
                //        if (sendPendingPackets[slot].ReSendNum == 1)
                //        {
                //            sendPendingPackets[slot].TryReSend(SendImmidiately, connection.GetInitialResendDelay(), false);
                //        }
                //    }

                //} while (curSequence != ackWindowStart);
            }
        }
Esempio n. 13
0
        public override void OnDatagram(Datagram datagram)
        {
            CheckDatagramValid(datagram);

            connection.SendDatagramAsync(datagram.CreateAck());

            lock (channelMutex)
            {
                int relate = RelativeSequenceNumber(datagram.Sequence, recvWindowStart);
                if (relate == 0)
                {
                    //right in time
                    connection.ReleaseDatagram(datagram);
                    AdvanceWindow();

                    int nextSeqNr = (datagram.Sequence + 1) % MAX_SEQUENCE;

                    if (ordered)
                    {
                        while (recvWithheld[nextSeqNr % WINDOW_SIZE] != null)
                        {
                            connection.ReleaseDatagram(recvWithheld[nextSeqNr % WINDOW_SIZE]);
                            AdvanceWindow();
                            nextSeqNr++;
                        }
                    }
                    else
                    {
                        while (recvEarlyReceived[nextSeqNr % WINDOW_SIZE])
                        {
                            AdvanceWindow();
                            nextSeqNr++;
                        }
                    }

                    return;
                }

                if (relate < 0)
                {
                    //duplicate
                    logger.Trace($"Dropped duplicate {datagram}");
                    datagram.Dispose();
                    return;
                }

                if (relate > WINDOW_SIZE)
                {
                    //too early message
                    logger.Trace($"Dropped too early {datagram}");
                    datagram.Dispose();
                    return;
                }

                if (ordered)
                {
                    if (recvWithheld[datagram.Sequence % WINDOW_SIZE] != null)
                    {
                        //duplicate
                        logger.Trace($"Dropped duplicate {datagram}");
                        datagram.Dispose();
                        return;
                    }

                    recvWithheld[datagram.Sequence % WINDOW_SIZE] = datagram;
                }
                else
                {
                    if (recvEarlyReceived[datagram.Sequence % WINDOW_SIZE])
                    {
                        //duplicate
                        logger.Trace($"Dropped duplicate {datagram}");
                        datagram.Dispose();
                        return;
                    }

                    recvEarlyReceived[datagram.Sequence % WINDOW_SIZE] = true;
                    connection.ReleaseDatagram(datagram);
                }
            }
        }
Esempio n. 14
0
 void OnDisconnectResp(Datagram datagram)
 {
     CloseInternal(DisconnectReason.ClosedByThisPeer, null);
     datagram.Dispose();
 }