Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 package org.apache.commons.net.telnet;
 

Author(s):
Bruno D'Avanzo
 
 
 
 final class TelnetInputStream extends BufferedInputStream implements Runnable
 {
    
End of file has been reached
 
     private static final int EOF = -1;

    
Read would block
 
     private static final int WOULD_BLOCK = -2;
 
     // TODO should these be private enums?
     static final int _STATE_DATA = 0, _STATE_IAC = 1, _STATE_WILL = 2,
                      _STATE_WONT = 3, _STATE_DO = 4, _STATE_DONT = 5,
                      _STATE_SB = 6, _STATE_SE = 7, _STATE_CR = 8, _STATE_IAC_SB = 9;
 
     private boolean __hasReachedEOF// @GuardedBy("__queue")
     private volatile boolean __isClosed;
     private boolean __readIsWaiting;
     private final int[] __queue;
     private final TelnetClient __client;
     private final Thread __thread;
     private IOException __ioException;
 
     /* TERMINAL-TYPE option (start)*/
     private final int __suboption[] = new int[512];
     private int __suboption_count = 0;
     /* TERMINAL-TYPE option (end)*/
 
     private volatile boolean __threaded;
 
     TelnetInputStream(InputStream inputTelnetClient client,
                       boolean readerThread)
     {
         super(input);
          = client;
          = ;
          = true;
          = 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)
          = new int[2049];
          = 0;
          = 0;
          = 0;
          = null;
          = false;
          = false;
         if(readerThread) {
              = new Thread(this);
         } else {
              = null;
         }
     }
 
     TelnetInputStream(InputStream inputTelnetClient client) {
         this(inputclienttrue);
     }
 
     void _start()
     {
         if( == null) {
             return;
         }
 
         int priority;
          = false;
        // TODO remove this
        // 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 > .) {
            priority = .;
        }
        .setPriority(priority);
        .setDaemon(true);
        .start();
         = true// tell _processChar that we are running threaded
    }
    // synchronized(__client) critical sections are to protect against
    // TelnetOutputStream writing through the telnet client at same time
    // as a processDo/Will/etc. command invoked from TelnetInputStream
    // tries to write.
    
Get the next byte of data. IAC commands are processed internally and do not return data.

Parameters:
mayBlock true if method is allowed to block
Returns:
the next byte of data, or -1 (EOF) if end of stread reached, or -2 (WOULD_BLOCK) if mayBlock is false and there is no data available
    private int __read(boolean mayBlockthrows IOException
    {
        int ch;
        while (true)
        {
            // If there is no more data AND we were told not to block, just return WOULD_BLOCK (-2). (More efficient than exception.)
            if(!mayBlock && super.available() == 0) {
                return ;
            }
            // Otherwise, exit only when we reach end of stream.
            if ((ch = super.read()) < 0) {
                return ;
            }
            ch = (ch & 0xff);
            /* Code Section added for supporting AYT (start)*/
            synchronized ()
            {
                ._processAYTResponse();
            }
            /* Code Section added for supporting AYT (end)*/
            /* Code Section added for supporting spystreams (start)*/
            ._spyRead(ch);
            /* Code Section added for supporting spystreams (end)*/
            switch ()
            {
            case :
                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
                //$FALL-THROUGH$
            case :
                if (ch == .)
                {
                     = ;
                    continue;
                }
                if (ch == '\r')
                {
                    synchronized ()
                    {
                        if (._requestedDont(.)) {
                             = ;
                        } else {
                             = ;
                        }
                    }
                } else {
                     = ;
                }
                break;
            case :
                switch (ch)
                {
                case .:
                     = ;
                    continue;
                case .:
                     = ;
                    continue;
                case .:
                     = ;
                    continue;
                case .:
                     = ;
                    continue;
                /* TERMINAL-TYPE option (start)*/
                case .:
                     = 0;
                     = ;
                    continue;
                /* TERMINAL-TYPE option (end)*/
                case .:
                     = ;
                    break// exit to enclosing switch to return IAC from read
                case .// unexpected byte! ignore it (don't send it as a command)
                     = ;
                    continue;
                default:
                     = ;
                    ._processCommand(ch); // Notify the user
                    continue// move on the next char
                }
                break// exit and return from read
            case :
                synchronized ()
                {
                    ._processWill(ch);
                    ._flushOutputStream();
                }
                 = ;
                continue;
            case :
                synchronized ()
                {
                    ._processWont(ch);
                    ._flushOutputStream();
                }
                 = ;
                continue;
            case :
                synchronized ()
                {
                    ._processDo(ch);
                    ._flushOutputStream();
                }
                 = ;
                continue;
            case :
                synchronized ()
                {
                    ._processDont(ch);
                    ._flushOutputStream();
                }
                 = ;
                continue;
            /* TERMINAL-TYPE option (start)*/
            case :
                switch (ch)
                {
                case .:
                     = ;
                    continue;
                default:
                    // store suboption char
                    if ( < .) {
                        [++] = ch;
                    }
                    break;
                }
                 = ;
                continue;
            case // IAC received during SB phase
                switch (ch)
                {
                case .:
                    synchronized ()
                    {
                        ._processSuboption();
                        ._flushOutputStream();
                    }
                     = ;
                    continue;
                case .// De-dup the duplicated IAC
                    if ( < .) {
                        [++] = ch;
                    }
                    break;
                default:            // unexpected byte! ignore it
                    break;
                }
                 = ;
                continue;
            /* TERMINAL-TYPE option (end)*/
            }
            break;
        }
        return ch;
    }
    // synchronized(__client) critical sections are to protect against
    // TelnetOutputStream writing through the telnet client at same time
    // as a processDo/Will/etc. command invoked from TelnetInputStream
    // tries to write. Returns true if buffer was previously empty.
    private boolean __processChar(int chthrows InterruptedException
    {
        // Critical section because we're altering __bytesAvailable,
        // __queueTail, and the contents of _queue.
        boolean bufferWasEmpty;
        synchronized ()
        {
            bufferWasEmpty = ( == 0);
            while ( >= . - 1)
            {
                // The queue is full. We need to wait before adding any more data to it. Hopefully the stream owner
                // will consume some data soon!
                if()
                {
                    .notify();
                    try
                    {
                        .wait();
                    }
                    catch (InterruptedException e)
                    {
                        throw e;
                    }
                }
                else
                {
                    // We've been asked to add another character to the queue, but it is already full and there's
                    // no other thread to drain it. This should not have happened!
                    throw new IllegalStateException("Queue is full! Cannot process another character.");
                }
            }
            // Need to do this in case we're not full, but block on a read
            if ( && )
            {
                .notify();
            }
            [] = ch;
            ++;
            if (++ >= .) {
                 = 0;
            }
        }
        return bufferWasEmpty;
    }
    @Override
    public int read() throws IOException
    {
        // Critical section because we're altering __bytesAvailable,
        // __queueHead, and the contents of _queue in addition to
        // testing value of __hasReachedEOF.
        synchronized ()
        {
            while (true)
            {
                if ( != null)
                {
                    IOException e;
                    e = ;
                     = null;
                    throw e;
                }
                if ( == 0)
                {
                    // Return EOF if at end of file
                    if () {
                        return ;
                    }
                    // Otherwise, we have to wait for queue to get something
                    if()
                    {
                        .notify();
                        try
                        {
                             = true;
                            .wait();
                             = false;
                        }
                        catch (InterruptedException e)
                        {
                            throw new InterruptedIOException("Fatal thread interruption during read.");
                        }
                    }
                    else
                    {
                        //__alreadyread = false;
                         = true;
                        int ch;
                        boolean mayBlock = true;    // block on the first read only
                        do
                        {
                            try
                            {
                                if ((ch = __read(mayBlock)) < 0) { // must be EOF
                                    if(ch != ) {
                                        return (ch);
                                    }
                                }
                            }
                            catch (InterruptedIOException e)
                            {
                                synchronized ()
                                {
                                     = e;
                                    .notifyAll();
                                    try
                                    {
                                        .wait(100);
                                    }
                                    catch (InterruptedException interrupted)
                                    {
                                    }
                                }
                                return ;
                            }
                            try
                            {
                                if(ch != )
                                {
                                    __processChar(ch);
                                }
                            }
                            catch (InterruptedException e)
                            {
                                if () {
                                    return ;
                                }
                            }
                            // Reads should not block on subsequent iterations. Potentially, this could happen if the
                            // remaining buffered socket data consists entirely of Telnet command sequence and no "user" data.
                            mayBlock = false;
                        }
                        // Continue reading as long as there is data available and the queue is not full.
                        while (super.available() > 0 &&  < . - 1);
                         = false;
                    }
                    continue;
                }
                else
                {
                    int ch;
                    ch = [];
                    if (++ >= .) {
                         = 0;
                    }
                    --;
            // Need to explicitly notify() so available() works properly
            if( == 0 && ) {
                .notify();
            }
                    return ch;
                }
            }
        }
    }


    
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.

Parameters:
buffer The byte array in which to store the data.
Returns:
The number of bytes read. Returns -1 if the end of the message has been reached.
Throws:
java.io.IOException If an error occurs in reading the underlying stream.
    @Override
    public int read(byte buffer[]) throws IOException
    {
        return read(buffer, 0, buffer.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.

Parameters:
buffer The byte array in which to store the data.
offset The offset into the array at which to start storing data.
length The number of bytes to read.
Returns:
The number of bytes read. Returns -1 if the end of the stream has been reached.
Throws:
java.io.IOException If an error occurs while reading the underlying stream.
    @Override
    public int read(byte buffer[], int offsetint lengththrows IOException
    {
        int choff;
        if (length < 1) {
            return 0;
        }
        // Critical section because run() may change __bytesAvailable
        synchronized ()
        {
            if (length > ) {
                length = ;
            }
        }
        if ((ch = read()) == ) {
            return ;
        }
        off = offset;
        do
        {
            buffer[offset++] = (byte)ch;
        }
        while (--length > 0 && (ch = read()) != );
        //__client._spyRead(buffer, off, offset - off);
        return (offset - off);
    }


    
Returns false. Mark is not supported. *
    @Override
    public boolean markSupported()
    {
        return false;
    }
    @Override
    public int available() throws IOException
    {
        // Critical section because run() may change __bytesAvailable
        synchronized ()
        {
            if () { // Must not call super.available when running threaded: NET-466
                return ;
            } else {
                return  + super.available();
            }
        }
    }
    // Cannot be synchronized.  Will cause deadlock if run() is blocked
    // in read because BufferedInputStream read() is synchronized.
    @Override
    public void close() throws IOException
    {
        // 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 ()
        {
             = true;
                  = true;
            if ( != null && .isAlive())
            {
                .interrupt();
            }
            .notifyAll();
        }
    }
//    @Override
    public void run()
    {
        int ch;
        try
        {
_outerLoop:
            while (!)
            {
                try
                {
                    if ((ch = __read(true)) < 0) {
                        break;
                    }
                }
                catch (InterruptedIOException e)
                {
                    synchronized ()
                    {
                         = e;
                        .notifyAll();
                        try
                        {
                            .wait(100);
                        }
                        catch (InterruptedException interrupted)
                        {
                            if () {
                                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;
                }
                // Process new character
                boolean notify = false;
                try
                {
                    notify = __processChar(ch);
                }
                catch (InterruptedException e)
                {
                    if () {
                        break _outerLoop;
                    }
                }
                // Notify input listener if buffer was previously empty
                if (notify) {
                    .notifyInputListener();
                }
            }
        }
        catch (IOException ioe)
        {
            synchronized ()
            {
                 = ioe;
            }
            .notifyInputListener();
        }
        synchronized ()
        {
                  = true// Possibly redundant
             = true;
            .notify();
        }
         = false;
    }
/* Emacs configuration
 * Local variables:        **
 * mode:             java  **
 * c-basic-offset:   4     **
 * indent-tabs-mode: nil   **
 * End:                    **
 */
New to GrepCode? Check out our FAQ X