001    /**
002     * Jetrix TetriNET Server
003     * Copyright (C) 2005  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.protocols;
021    
022    import java.io.ByteArrayOutputStream;
023    import java.io.IOException;
024    import java.io.InputStream;
025    
026    import net.jetrix.Protocol;
027    
028    /**
029     * Abstract protocol implementing the readLine(Reader) method.
030     *
031     * @since 0.3
032     *
033     * @author Emmanuel Bourg
034     * @version $Revision: 848 $, $Date: 2010-05-03 22:51:32 +0200 (lun., 03 mai 2010) $
035     */
036    public abstract class AbstractProtocol implements Protocol
037    {
038        /** Maximum size allowed for a message frame. */
039        private static final int MAX_SIZE = 8192;
040    
041        /** Maximum delay allowed for parsing a message frame (in milliseconds). */
042        private static final int MAX_DELAY = 10000;
043        
044        /**
045         * Reads the next message frame from the specified input stream.
046         * No charset decoding is performed at this stage.
047         */
048        public byte[] readFrame(InputStream in) throws IOException
049        {
050            ByteArrayOutputStream input = new ByteArrayOutputStream(256);
051            
052            long time = 0;
053            
054            int b;
055            while ((b = in.read()) != -1 && b != getEOL() && b != 0x0A && b != 0x0D && input.size() < MAX_SIZE)
056            {
057                input.write(b);
058                
059                if (input.size() == 1)
060                {
061                    // let's start monitoring the input speed
062                    time = System.currentTimeMillis();
063                }
064                else if (System.currentTimeMillis() - time > MAX_DELAY)
065                {
066                    throw new IOException("Slow input detected (" + input.size() + " bytes over " + (System.currentTimeMillis() - time) + "ms)");
067                }
068            }
069            
070            if (b == -1)
071            {
072                throw new IOException("End of stream");
073            }
074            
075            if (input.size() >= MAX_SIZE)
076            {
077                throw new IOException("Message frame exceeded the " + MAX_SIZE + " limit");
078            }
079            
080            return input.toByteArray();
081        }
082    
083        public String readLine(InputStream in, String encoding) throws IOException
084        {
085            return new String(readFrame(in), encoding);
086        }
087    
088        public boolean equals(Object o)
089        {
090            if (this == o)
091            {
092                return true;
093            }
094            if (o == null || getClass() != o.getClass())
095            {
096                return false;
097            }
098    
099            Protocol that = (Protocol) o;
100    
101            if (!getName().equals(that.getName()))
102            {
103                return false;
104            }
105    
106            return true;
107        }
108    
109        public int hashCode()
110        {
111            return getName().hashCode();
112        }
113    
114        public String toString()
115        {
116            return "[Protocol name=" + getName() + "]";
117        }
118    }