FileDocCategorySizeDatePackage
TelnetInputStream.javaAPI DocApache Commons NET 1.4.1 API18804Sat Dec 03 10:05:48 GMT 2005org.apache.commons.net.telnet

TelnetInputStream

public final class TelnetInputStream extends BufferedInputStream implements Runnable

author
Daniel F. Savarese
author
Bruno D'Avanzo

Fields Summary
static final int
_STATE_DATA
static final int
_STATE_IAC
static final int
_STATE_WILL
static final int
_STATE_WONT
static final int
_STATE_DO
static final int
_STATE_DONT
static final int
_STATE_SB
static final int
_STATE_SE
static final int
_STATE_CR
static final int
_STATE_IAC_SB
private boolean
__hasReachedEOF
private boolean
__isClosed
private boolean
__readIsWaiting
private int
__receiveState
private int
__queueHead
private int
__queueTail
private int
__bytesAvailable
private int[]
__queue
private TelnetClient
__client
private Thread
__thread
private IOException
__ioException
private int[]
__suboption
private int
__suboption_count
private boolean
__threaded
Constructors Summary
TelnetInputStream(InputStream input, TelnetClient client, boolean readerThread)


       
                       
    
        super(input);
        __client = client;
        __receiveState = _STATE_DATA;
        __isClosed = true;
        __hasReachedEOF = false;
        // Make it 2049, because when full, one slot will go unused, and we
        // want a 2048 byte buffer just to have a round number (base 2 that is)
        __queue = new int[2049];
        __queueHead = 0;
        __queueTail = 0;
        __bytesAvailable = 0;
        __ioException = null;
        __readIsWaiting = false;
        __threaded = false;
        if(readerThread)
            __thread = new Thread(this);
        else
            __thread = null;
    
TelnetInputStream(InputStream input, TelnetClient client)

        this(input, client, true);
    
Methods Summary
private void__processChar(int ch)

        // Critical section because we're altering __bytesAvailable,
        // __queueTail, and the contents of _queue.
        synchronized (__queue)
        {
            while (__bytesAvailable >= __queue.length - 1)
            {
                if(__threaded)
                {
                    __queue.notify();
                    try
                    {
                        __queue.wait();
                    }
                    catch (InterruptedException e)
                    {
                        throw e;
                    }
                }
            }

            // Need to do this in case we're not full, but block on a read
            if (__readIsWaiting && __threaded)
            {
                __queue.notify();
            }

            __queue[__queueTail] = ch;
            ++__bytesAvailable;

            if (++__queueTail >= __queue.length)
                __queueTail = 0;
        }
    
private int__read()

        int ch;

_loop:
        while (true)
        {
            // Exit only when we reach end of stream.
            if ((ch = super.read()) < 0)
                return -1;

            ch = (ch & 0xff);

            /* Code Section added for supporting AYT (start)*/
            synchronized (__client)
            {
                __client._processAYTResponse();
            }
            /* Code Section added for supporting AYT (end)*/

            /* Code Section added for supporting spystreams (start)*/
            __client._spyRead(ch);
            /* Code Section added for supporting spystreams (end)*/

_mainSwitch:
            switch (__receiveState)
            {

            case _STATE_CR:
                if (ch == '\0")
                {
                    // Strip null
                    continue;
                }
                // How do we handle newline after cr?
                //  else if (ch == '\n' && _requestedDont(TelnetOption.ECHO) &&

                // Handle as normal data by falling through to _STATE_DATA case

            case _STATE_DATA:
                if (ch == TelnetCommand.IAC)
                {
                    __receiveState = _STATE_IAC;
                    continue;
                }


                if (ch == '\r")
                {
                    synchronized (__client)
                    {
                        if (__client._requestedDont(TelnetOption.BINARY))
                            __receiveState = _STATE_CR;
                        else
                            __receiveState = _STATE_DATA;
                    }
                }
                else
                    __receiveState = _STATE_DATA;
                break;

            case _STATE_IAC:
                switch (ch)
                {
                case TelnetCommand.WILL:
                    __receiveState = _STATE_WILL;
                    continue;
                case TelnetCommand.WONT:
                    __receiveState = _STATE_WONT;
                    continue;
                case TelnetCommand.DO:
                    __receiveState = _STATE_DO;
                    continue;
                case TelnetCommand.DONT:
                    __receiveState = _STATE_DONT;
                    continue;
                /* TERMINAL-TYPE option (start)*/
                case TelnetCommand.SB:
                    __suboption_count = 0;
                    __receiveState = _STATE_SB;
                    continue;
                /* TERMINAL-TYPE option (end)*/
                case TelnetCommand.IAC:
                    __receiveState = _STATE_DATA;
                    break;
                default:
                    break;
                }
                __receiveState = _STATE_DATA;
                continue;
            case _STATE_WILL:
                synchronized (__client)
                {
                    __client._processWill(ch);
                    __client._flushOutputStream();
                }
                __receiveState = _STATE_DATA;
                continue;
            case _STATE_WONT:
                synchronized (__client)
                {
                    __client._processWont(ch);
                    __client._flushOutputStream();
                }
                __receiveState = _STATE_DATA;
                continue;
            case _STATE_DO:
                synchronized (__client)
                {
                    __client._processDo(ch);
                    __client._flushOutputStream();
                }
                __receiveState = _STATE_DATA;
                continue;
            case _STATE_DONT:
                synchronized (__client)
                {
                    __client._processDont(ch);
                    __client._flushOutputStream();
                }
                __receiveState = _STATE_DATA;
                continue;
            /* TERMINAL-TYPE option (start)*/
            case _STATE_SB:
                switch (ch)
                {
                case TelnetCommand.IAC:
                    __receiveState = _STATE_IAC_SB;
                    continue;
                default:
                    // store suboption char
                    __suboption[__suboption_count++] = ch;
                    break;
                }
                __receiveState = _STATE_SB;
                continue;
            case _STATE_IAC_SB:
                switch (ch)
                {
                case TelnetCommand.SE:
                    synchronized (__client)
                    {
                        __client._processSuboption(__suboption, __suboption_count);
                        __client._flushOutputStream();
                    }
                    __receiveState = _STATE_DATA;
                    continue;
                default:
                    __receiveState = _STATE_SB;
                    break;
                }
                __receiveState = _STATE_DATA;
                continue;
            /* TERMINAL-TYPE option (end)*/
            }

            break;
        }

        return ch;
    
void_start()

        if(__thread == null)
            return;

        int priority;
        __isClosed = false;
        // Need to set a higher priority in case JVM does not use pre-emptive
        // threads.  This should prevent scheduler induced deadlock (rather than
        // deadlock caused by a bug in this code).
        priority = Thread.currentThread().getPriority() + 1;
        if (priority > Thread.MAX_PRIORITY)
            priority = Thread.MAX_PRIORITY;
        __thread.setPriority(priority);
        __thread.setDaemon(true);
        __thread.start();
        __threaded = true;
    
public intavailable()

        // Critical section because run() may change __bytesAvailable
        synchronized (__queue)
        {
            return __bytesAvailable;
        }
    
public voidclose()

        // Completely disregard the fact thread may still be running.
        // We can't afford to block on this close by waiting for
        // thread to terminate because few if any JVM's will actually
        // interrupt a system read() from the interrupt() method.
        super.close();

        synchronized (__queue)
        {
            __hasReachedEOF = true;
            __isClosed      = true;

            if (__thread != null && __thread.isAlive())
            {
                __thread.interrupt();
            }

            __queue.notifyAll();
        }

        __threaded = false;
    
public booleanmarkSupported()
Returns false. Mark is not supported.

        return false;
    
public intread()

        // Critical section because we're altering __bytesAvailable,
        // __queueHead, and the contents of _queue in addition to
        // testing value of __hasReachedEOF.
        synchronized (__queue)
        {

            while (true)
            {
                if (__ioException != null)
                {
                    IOException e;
                    e = __ioException;
                    __ioException = null;
                    throw e;
                }

                if (__bytesAvailable == 0)
                {
                    // Return -1 if at end of file
                    if (__hasReachedEOF)
                        return -1;

                    // Otherwise, we have to wait for queue to get something
                    if(__threaded)
                    {
                        __queue.notify();
                        try
                        {
                            __readIsWaiting = true;
                            __queue.wait();
                            __readIsWaiting = false;
                        }
                        catch (InterruptedException e)
                        {
                            throw new IOException("Fatal thread interruption during read.");
                        }
                    }
                    else
                    {
                        //__alreadyread = false;
                        __readIsWaiting = true;
                        int ch;

                        do
                        {
                            try
                            {
                                if ((ch = __read()) < 0)
                                    if(ch != -2)
                                        return (ch);
                            }
                            catch (InterruptedIOException e)
                            {
                                synchronized (__queue)
                                {
                                    __ioException = e;
                                    __queue.notifyAll();
                                    try
                                    {
                                        __queue.wait(100);
                                    }
                                    catch (InterruptedException interrupted)
                                    {
                                    }
                                }
                                return (-1);
                            }


                            try
                            {
                                if(ch != -2)
                                {
                                    __processChar(ch);
                                }
                            }
                            catch (InterruptedException e)
                            {
                                if (__isClosed)
                                    return (-1);
                            }
                        }
                        while (super.available() > 0);

                        __readIsWaiting = false;
                    }
                    continue;
                }
                else
                {
                    int ch;

                    ch = __queue[__queueHead];

                    if (++__queueHead >= __queue.length)
                        __queueHead = 0;

                    --__bytesAvailable;

		    // Need to explicitly notify() so available() works properly
		    if(__bytesAvailable == 0 && __threaded) {
			    __queue.notify();
		    }
		    
                    return ch;
                }
            }
        }
    
public intread(byte[] buffer)
Reads the next number of bytes from the stream into an array and returns the number of bytes read. Returns -1 if the end of the stream has been reached.

param
buffer The byte array in which to store the data.
return
The number of bytes read. Returns -1 if the end of the message has been reached.
exception
IOException If an error occurs in reading the underlying stream.

        return read(buffer, 0, buffer.length);
    
public intread(byte[] buffer, int offset, int length)
Reads the next number of bytes from the stream into an array and returns the number of bytes read. Returns -1 if the end of the message has been reached. The characters are stored in the array starting from the given offset and up to the length specified.

param
buffer The byte array in which to store the data.
param
offset The offset into the array at which to start storing data.
param
length The number of bytes to read.
return
The number of bytes read. Returns -1 if the end of the stream has been reached.
exception
IOException If an error occurs while reading the underlying stream.

        int ch, off;

        if (length < 1)
            return 0;

        // Critical section because run() may change __bytesAvailable
        synchronized (__queue)
        {
            if (length > __bytesAvailable)
                length = __bytesAvailable;
        }

        if ((ch = read()) == -1)
            return -1;

        off = offset;

        do
        {
            buffer[offset++] = (byte)ch;
        }
        while (--length > 0 && (ch = read()) != -1);

        //__client._spyRead(buffer, off, offset - off);
        return (offset - off);
    
public voidrun()

        int ch;

        try
        {
_outerLoop:
            while (!__isClosed)
            {
                try
                {
                    if ((ch = __read()) < 0)
                        break;
                }
                catch (InterruptedIOException e)
                {
                    synchronized (__queue)
                    {
                        __ioException = e;
                        __queue.notifyAll();
                        try
                        {
                            __queue.wait(100);
                        }
                        catch (InterruptedException interrupted)
                        {
                            if (__isClosed)
                                break _outerLoop;
                        }
                        continue;
                    }
                } catch(RuntimeException re) {
                    // We treat any runtime exceptions as though the
                    // stream has been closed.  We close the
                    // underlying stream just to be sure.
                    super.close();
                    // Breaking the loop has the effect of setting
                    // the state to closed at the end of the method.
                    break _outerLoop;
                }

                try
                {
                    __processChar(ch);
                }
                catch (InterruptedException e)
                {
                    if (__isClosed)
                        break _outerLoop;
                }
            }
        }
        catch (IOException ioe)
        {
            synchronized (__queue)
            {
                __ioException = ioe;
            }
        }

        synchronized (__queue)
        {
            __isClosed      = true; // Possibly redundant
            __hasReachedEOF = true;
            __queue.notify();
        }

        __threaded = false;