l2j_mobius/trunk/java/com/l2jserver/gameserver/network/ClientStats.java
2015-01-02 15:09:44 +00:00

250 lines
6.3 KiB
Java

/*
* Copyright (C) 2004-2015 L2J Server
*
* This file is part of L2J Server.
*
* L2J Server is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* L2J Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.gameserver.network;
import com.l2jserver.Config;
public class ClientStats
{
public int processedPackets = 0;
public int droppedPackets = 0;
public int unknownPackets = 0;
public int totalQueueSize = 0;
public int maxQueueSize = 0;
public int totalBursts = 0;
public int maxBurstSize = 0;
public int shortFloods = 0;
public int longFloods = 0;
public int totalQueueOverflows = 0;
public int totalUnderflowExceptions = 0;
private final int[] _packetsInSecond;
private long _packetCountStartTick = 0;
private int _head;
private int _totalCount = 0;
private int _floodsInMin = 0;
private long _floodStartTick = 0;
private int _unknownPacketsInMin = 0;
private long _unknownPacketStartTick = 0;
private int _overflowsInMin = 0;
private long _overflowStartTick = 0;
private int _underflowReadsInMin = 0;
private long _underflowReadStartTick = 0;
private volatile boolean _floodDetected = false;
private volatile boolean _queueOverflowDetected = false;
private final int BUFFER_SIZE;
public ClientStats()
{
BUFFER_SIZE = Config.CLIENT_PACKET_QUEUE_MEASURE_INTERVAL;
_packetsInSecond = new int[BUFFER_SIZE];
_head = BUFFER_SIZE - 1;
}
/**
* @return true if incoming packet need to be dropped
*/
protected final boolean dropPacket()
{
final boolean result = _floodDetected || _queueOverflowDetected;
if (result)
{
droppedPackets++;
}
return result;
}
/**
* Later during flood returns true (and send ActionFailed) once per second.
* @param queueSize
* @return true if flood detected first and ActionFailed packet need to be sent.
*/
protected final boolean countPacket(int queueSize)
{
processedPackets++;
totalQueueSize += queueSize;
if (maxQueueSize < queueSize)
{
maxQueueSize = queueSize;
}
if (_queueOverflowDetected && (queueSize < 2))
{
_queueOverflowDetected = false;
}
return countPacket();
}
/**
* @return Counts unknown packets and return true if threshold is reached.
*/
protected final boolean countUnknownPacket()
{
unknownPackets++;
final long tick = System.currentTimeMillis();
if ((tick - _unknownPacketStartTick) > 60000)
{
_unknownPacketStartTick = tick;
_unknownPacketsInMin = 1;
return false;
}
_unknownPacketsInMin++;
return _unknownPacketsInMin > Config.CLIENT_PACKET_QUEUE_MAX_UNKNOWN_PER_MIN;
}
/**
* @param count - current number of processed packets in burst
* @return burst length and return true if execution of the queue need to be aborted.
*/
protected final boolean countBurst(int count)
{
if (count > maxBurstSize)
{
maxBurstSize = count;
}
if (count < Config.CLIENT_PACKET_QUEUE_MAX_BURST_SIZE)
{
return false;
}
totalBursts++;
return true;
}
/**
* @return Counts queue overflows and return true if threshold is reached.
*/
protected final boolean countQueueOverflow()
{
_queueOverflowDetected = true;
totalQueueOverflows++;
final long tick = System.currentTimeMillis();
if ((tick - _overflowStartTick) > 60000)
{
_overflowStartTick = tick;
_overflowsInMin = 1;
return false;
}
_overflowsInMin++;
return _overflowsInMin > Config.CLIENT_PACKET_QUEUE_MAX_OVERFLOWS_PER_MIN;
}
/**
* @return Counts underflow exceptions and return true if threshold is reached.
*/
protected final boolean countUnderflowException()
{
totalUnderflowExceptions++;
final long tick = System.currentTimeMillis();
if ((tick - _underflowReadStartTick) > 60000)
{
_underflowReadStartTick = tick;
_underflowReadsInMin = 1;
return false;
}
_underflowReadsInMin++;
return _underflowReadsInMin > Config.CLIENT_PACKET_QUEUE_MAX_UNDERFLOWS_PER_MIN;
}
/**
* @return true if maximum number of floods per minute is reached.
*/
protected final boolean countFloods()
{
return _floodsInMin > Config.CLIENT_PACKET_QUEUE_MAX_FLOODS_PER_MIN;
}
private final boolean longFloodDetected()
{
return (_totalCount / BUFFER_SIZE) > Config.CLIENT_PACKET_QUEUE_MAX_AVERAGE_PACKETS_PER_SECOND;
}
/**
* Later during flood returns true (and send ActionFailed) once per second.
* @return true if flood detected first and ActionFailed packet need to be sent.
*/
private final synchronized boolean countPacket()
{
_totalCount++;
final long tick = System.currentTimeMillis();
if ((tick - _packetCountStartTick) > 1000)
{
_packetCountStartTick = tick;
// clear flag if no more flooding during last seconds
if (_floodDetected && !longFloodDetected() && (_packetsInSecond[_head] < (Config.CLIENT_PACKET_QUEUE_MAX_PACKETS_PER_SECOND / 2)))
{
_floodDetected = false;
}
// wrap head of the buffer around the tail
if (_head <= 0)
{
_head = BUFFER_SIZE;
}
_head--;
_totalCount -= _packetsInSecond[_head];
_packetsInSecond[_head] = 1;
return _floodDetected;
}
final int count = ++_packetsInSecond[_head];
if (!_floodDetected)
{
if (count > Config.CLIENT_PACKET_QUEUE_MAX_PACKETS_PER_SECOND)
{
shortFloods++;
}
else if (longFloodDetected())
{
longFloods++;
}
else
{
return false;
}
_floodDetected = true;
if ((tick - _floodStartTick) > 60000)
{
_floodStartTick = tick;
_floodsInMin = 1;
}
else
{
_floodsInMin++;
}
return true; // Return true only in the beginning of the flood
}
return false;
}
}