Example #1
0
        private void Update(object state)
        {
            if (!Monitor.TryEnter(_updateGlobalLock))
            {
                return;
            }
            _forceQuitTimer.Restart();

            try
            {
                long now = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;

                Parallel.ForEach(_playerSessions, delegate(KeyValuePair <IPEndPoint, PlayerNetworkSession> pair)
                {
                    PlayerNetworkSession session = pair.Value;

                    if (session == null)
                    {
                        return;
                    }
                    if (session.Evicted)
                    {
                        return;
                    }

                    Player player = session.Player;

                    long lastUpdate     = session.LastUpdatedTime.Ticks / TimeSpan.TicksPerMillisecond;
                    bool serverHasNoLag = ServerInfo.AvailableBytes < 1000;

                    if (serverHasNoLag && lastUpdate + InacvitityTimeout + 3000 < now)
                    {
                        session.Evicted = true;
                        // Disconnect user
                        ThreadPool.QueueUserWorkItem(delegate(object o)
                        {
                            PlayerNetworkSession s = o as PlayerNetworkSession;
                            if (s != null)
                            {
                                Player p = s.Player;
                                if (p != null)
                                {
                                    p.Disconnect("You've been kicked with reason: Network timeout.");
                                }
                                else
                                {
                                    if (ServerInfo.PlayerSessions.TryRemove(session.EndPoint, out session))
                                    {
                                        session.Player  = null;
                                        session.State   = ConnectionState.Unconnected;
                                        session.Evicted = true;
                                        session.Clean();
                                    }
                                }
                            }
                        }, session);

                        return;
                    }


                    if (serverHasNoLag && session.State != ConnectionState.Connected && player != null && lastUpdate + 3000 < now)
                    {
                        ThreadPool.QueueUserWorkItem(delegate(object o)
                        {
                            PlayerNetworkSession s = o as PlayerNetworkSession;
                            if (s != null)
                            {
                                Player p = s.Player;
                                if (p != null)
                                {
                                    p.Disconnect("You've been kicked with reason: Lost connection.");
                                }
                            }
                        }, session);

                        return;
                    }

                    if (player == null)
                    {
                        return;
                    }

                    if (serverHasNoLag && lastUpdate + InacvitityTimeout < now && !session.WaitForAck)
                    {
                        player.DetectLostConnection();
                        session.WaitForAck = true;
                    }

                    if (player.Rto == 0)
                    {
                        return;
                    }

                    long rto  = Math.Max(100, player.Rto);
                    var queue = session.WaitingForAcksQueue;

                    foreach (KeyValuePair <int, Datagram> datagramPair in queue)
                    {
                        // We don't do too much processing in each step, becasue one bad queue will hold the others.
                        //if (_forceQuitTimer.ElapsedMilliseconds > 100)
                        //{
                        //	Log.WarnFormat("Update aborted early");
                        //	return;
                        //}

                        var datagram = datagramPair.Value;

                        if (!datagram.Timer.IsRunning)
                        {
                            Log.ErrorFormat("Timer not running for #{0}", datagram.Header.datagramSequenceNumber);
                            datagram.Timer.Restart();
                            continue;
                        }

                        if (player.Rtt == -1)
                        {
                            return;
                        }

                        //if (session.WaitForAck) return;

                        long elapsedTime    = datagram.Timer.ElapsedMilliseconds;
                        long datagramTimout = rto * (datagram.TransmissionCount + session.ResendCount + 1);
                        datagramTimout      = Math.Min(datagramTimout, 3000);

                        //if(elapsedTime > 5000)
                        //{
                        //	Datagram deleted;
                        //	queue.TryRemove(datagram.Header.datagramSequenceNumber, out deleted);
                        //}
                        //else
                        if (serverHasNoLag && elapsedTime >= datagramTimout)
                        {
                            //if (session.WaitForAck) return;

                            //session.WaitForAck = session.ResendCount++ > 3;

                            Datagram deleted;
                            if (queue.TryRemove(datagram.Header.datagramSequenceNumber, out deleted))
                            {
                                session.ErrorCount++;

                                if (deleted.TransmissionCount > 3)
                                {
                                    if (Log.IsDebugEnabled)
                                    {
                                        Log.WarnFormat("TIMEOUT, Retransmission count remove from ACK queue #{0} Type: {2} (0x{2:x2}) for {1} ({3} > {4}) RTO {5}",
                                                       deleted.Header.datagramSequenceNumber.IntValue(),
                                                       player.Username,
                                                       deleted.FirstMessageId,
                                                       elapsedTime,
                                                       datagramTimout,
                                                       rto);
                                    }

                                    deleted.PutPool();

                                    //session.WaitForAck = true;

                                    Interlocked.Increment(ref ServerInfo.NumberOfFails);

                                    continue;
                                }

                                if (!session.Evicted)
                                {
                                    ThreadPool.QueueUserWorkItem(delegate(object data)
                                    {
                                        if (Log.IsDebugEnabled)
                                        {
                                            Log.WarnFormat("TIMEOUT, Resent #{0} Type: {2} (0x{2:x2}) for {1} ({3} > {4}) RTO {5}",
                                                           deleted.Header.datagramSequenceNumber.IntValue(),
                                                           player.Username,
                                                           deleted.FirstMessageId,
                                                           elapsedTime,
                                                           datagramTimout,
                                                           player.Rto);
                                        }
                                        SendDatagram(session, (Datagram)data);
                                        Interlocked.Increment(ref ServerInfo.NumberOfResends);
                                    }, datagram);
                                }
                            }
                        }
                    }
                });
            }
            finally
            {
                if (_forceQuitTimer.ElapsedMilliseconds > 100)
                {
                    Log.WarnFormat("Update took unexpected long time: {0}", _forceQuitTimer.ElapsedMilliseconds);
                }

                Monitor.Exit(_updateGlobalLock);
                _cleanerTimer.Change(10, Timeout.Infinite);
            }
        }
Example #2
0
        private void Update(object state)
        {
            if (!Monitor.TryEnter(_updateGlobalLock))
            {
                return;
            }

            try
            {
                long now = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;

                Parallel.ForEach(_playerSessions.Values.ToArray(), delegate(PlayerNetworkSession session)
                {
                    if (session == null)
                    {
                        return;
                    }
                    if (session.Evicted)
                    {
                        return;
                    }

                    try
                    {
                        Player player = session.Player;

                        long lastUpdate = session.LastUpdatedTime.Ticks / TimeSpan.TicksPerMillisecond;
                        if (lastUpdate + InacvitityTimeout + 3000 + Math.Min(5000, ServerInfo.AvailableBytes) < now)
                        {
                            session.Evicted = true;
                            // Disconnect user
                            ThreadPool.QueueUserWorkItem(delegate(object o)
                            {
                                PlayerNetworkSession s = o as PlayerNetworkSession;
                                if (s != null)
                                {
                                    Player p = s.Player;
                                    if (p != null)
                                    {
                                        p.Disconnect("You've been kicked with reason: Network timeout.");
                                    }
                                    else
                                    {
                                        if (ServerInfo.PlayerSessions.TryRemove(session.EndPoint, out session))
                                        {
                                            session.Player  = null;
                                            session.State   = ConnectionState.Unconnected;
                                            session.Evicted = true;
                                            session.Clean();
                                        }
                                    }
                                }
                            }, session);

                            return;
                        }


                        if (session.State != ConnectionState.Connected && player != null && lastUpdate + 3000 < now)
                        {
                            ThreadPool.QueueUserWorkItem(delegate(object o)
                            {
                                PlayerNetworkSession s = o as PlayerNetworkSession;
                                if (s != null)
                                {
                                    Player p = s.Player;
                                    if (p != null)
                                    {
                                        p.Disconnect("You've been kicked with reason: Lost connection.");
                                    }
                                }
                            }, session);

                            return;
                        }

                        if (player == null)
                        {
                            return;
                        }

                        if (lastUpdate + InacvitityTimeout < now)
                        {
                            player.DetectLostConnection();
                        }

                        long rto  = Math.Max(100, player.Rto);
                        var queue = session.WaitingForAcksQueue;
                        foreach (var datagram in queue.Values)
                        {
                            if (!datagram.Timer.IsRunning)
                            {
                                Log.ErrorFormat("Timer not running for #{0}", datagram.Header.datagramSequenceNumber);
                                datagram.Timer.Restart();
                                continue;
                            }

                            if (player.Rtt == -1)
                            {
                                continue;
                            }

                            long elapsedTime = datagram.Timer.ElapsedMilliseconds;
                            if (elapsedTime >= rto * (datagram.TransmissionCount + 2))
                            {
                                Datagram deleted;
                                if (queue.TryRemove(datagram.Header.datagramSequenceNumber, out deleted))
                                {
                                    session.ErrorCount++;

                                    if (deleted.TransmissionCount > 1)
                                    {
                                        Log.DebugFormat("Remove from ACK queue #{0} Type: {2} (0x{2:x2}) for {1} ({3} > {4}) RTT {5}",
                                                        deleted.Header.datagramSequenceNumber.IntValue(),
                                                        player.Username,
                                                        deleted.FirstMessageId,
                                                        elapsedTime,
                                                        rto,
                                                        player.Rtt);


                                        foreach (MessagePart part in deleted.MessageParts)
                                        {
                                            part.PutPool();
                                        }
                                        deleted.PutPool();

                                        continue;
                                    }

                                    if (!session.Evicted)
                                    {
                                        ThreadPool.QueueUserWorkItem(delegate(object data)
                                        {
                                            try
                                            {
                                                Log.DebugFormat("Resent #{0} Type: {2} (0x{2:x2}) for {1} ({3} > {4}) RTT {5}",
                                                                deleted.Header.datagramSequenceNumber.IntValue(),
                                                                player.Username,
                                                                deleted.FirstMessageId,
                                                                elapsedTime,
                                                                rto,
                                                                player.Rtt);
                                                SendDatagram(session, (Datagram)data);
                                            }
                                            catch (Exception e)
                                            {
                                            }
                                        }, datagram);
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception e)
                    {
                    }
                });
            }
            finally
            {
                Monitor.Exit(_updateGlobalLock);
            }
        }