001    /**
002     * Jetrix TetriNET Server
003     * Copyright (C) 2001-2003  Emmanuel Bourg
004     *
005     * This program is free software; you can redistribute it and/or
006     * modify it under the terms of the GNU General Public License
007     * as published by the Free Software Foundation; either version 2
008     * of the License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with this program; if not, write to the Free Software
017     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
018     */
019    
020    package net.jetrix.filter;
021    
022    import java.util.*;
023    
024    import net.jetrix.*;
025    import net.jetrix.messages.channel.PlineMessage;
026    
027    /**
028     * Blocks spam over pline.
029     *
030     * @author Emmanuel Bourg
031     * @version $Revision: 798 $, $Date: 2009-02-18 16:24:28 +0100 (Wed, 18 Feb 2009) $
032     */
033    public class FloodFilter extends GenericFilter
034    {
035        private long timestamp[][];
036        private int index[];
037        private int capacity = 8;
038        private int delay = 5000;
039    
040        /** Minimum time between two warnings (in seconds) */
041        private int warningPeriod = 10;
042    
043        /** Date of the last warning */
044        private long lastWarning;
045    
046        public void init()
047        {       
048            // reading parameters
049            capacity = config.getInt("capacity", capacity);
050            delay = config.getInt("delay", delay);
051            warningPeriod = config.getInt("warningPeriod", warningPeriod);
052    
053            timestamp = new long[6][capacity];
054            index = new int[6];
055        }
056    
057        public void onMessage(PlineMessage m, List<Message> out)
058        {
059            int slot = m.getSlot();
060            // no check for server messages
061            if (slot < 1 || slot > 6)
062            {
063                out.add(m);
064                return;
065            }
066    
067            String text = m.getText();
068            float charsByLine = 70;
069            int lineCount = (int) Math.ceil(text.length() / charsByLine);
070    
071            long now = System.currentTimeMillis();
072            boolean isRateExceeded = false;
073            for (int i = 0; i < lineCount; i++)
074            {
075                isRateExceeded = isRateExceeded || isRateExceeded(slot - 1, now);
076            }
077    
078            if (slot > 0 && isRateExceeded)
079            {
080                if ((now - lastWarning) > warningPeriod * 1000)
081                {
082                    User user = getChannel().getPlayer(slot);
083                    out.add(new PlineMessage("filter.flood.blocked", user.getName()));
084                    lastWarning = now;
085                }
086            }
087            else
088            {
089                out.add(m);
090            }
091        }
092    
093        /**
094         * Records a message timestamp and checks the data rate.
095         *
096         * @param slot  message source slot
097         * @param t     message timestamp
098         *
099         * @return <tt>true</tt> if over <tt>capacity</tt> messages in less than the <tt>delay</tt> specified
100         */
101        private boolean isRateExceeded(int slot, long t)
102        {
103            long t1 = timestamp[slot][index[slot]];
104            timestamp[slot][index[slot]] = t;
105            index[slot] = (index[slot] + 1) % capacity;
106    
107            return (t - t1) < delay;
108        }
109    
110        public String getName()
111        {
112            return "Flood Filter";
113        }
114    
115        public String getDescription()
116        {
117            return "Blocks exceeding messages on pline";
118        }
119    
120        public String getVersion()
121        {
122            return "1.0";
123        }
124    
125        public String getAuthor()
126        {
127            return "Emmanuel Bourg";
128        }
129    
130    }