Coverage report

  %line %branch
org.apache.commons.net.telnet.TelnetInputStream
66% 
89% 

 1  
 /*
 2  
  * Copyright 2003-2004 The Apache Software Foundation
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *     http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.apache.commons.net.telnet;
 17  
 
 18  
 import java.io.BufferedInputStream;
 19  
 import java.io.IOException;
 20  
 import java.io.InputStream;
 21  
 import java.io.InterruptedIOException;
 22  
 
 23  
 /***
 24  
  *
 25  
  * <p>
 26  
  *
 27  
  * <p>
 28  
  * <p>
 29  
  * @author Daniel F. Savarese
 30  
  * @author Bruno D'Avanzo
 31  
  ***/
 32  
 
 33  
 
 34  
 final class TelnetInputStream extends BufferedInputStream implements Runnable
 35  
 {
 36  
     static final int _STATE_DATA = 0, _STATE_IAC = 1, _STATE_WILL = 2,
 37  
                      _STATE_WONT = 3, _STATE_DO = 4, _STATE_DONT = 5,
 38  
                      _STATE_SB = 6, _STATE_SE = 7, _STATE_CR = 8, _STATE_IAC_SB = 9;
 39  
 
 40  
     private boolean __hasReachedEOF, __isClosed;
 41  
     private boolean __readIsWaiting;
 42  
     private int __receiveState, __queueHead, __queueTail, __bytesAvailable;
 43  
     private int[] __queue;
 44  
     private TelnetClient __client;
 45  
     private Thread __thread;
 46  
     private IOException __ioException;
 47  
 
 48  
     /* TERMINAL-TYPE option (start)*/
 49  32
     private int __suboption[] = new class="keyword">int[256];
 50  32
     private int __suboption_count = 0;
 51  
     /* TERMINAL-TYPE option (end)*/
 52  
 
 53  
     private boolean __threaded;
 54  
 
 55  
     TelnetInputStream(InputStream input, TelnetClient client,
 56  
                       boolean readerThread)
 57  
     {
 58  32
         super(input);
 59  32
         __client = client;
 60  32
         __receiveState = _STATE_DATA;
 61  32
         __isClosed = true;
 62  32
         __hasReachedEOF = false;
 63  
         // Make it 2049, because when full, one slot will go unused, and we
 64  
         // want a 2048 byte buffer just to have a round number (base 2 that is)
 65  32
         __queue = new int[2049];
 66  32
         __queueHead = 0;
 67  32
         __queueTail = 0;
 68  32
         __bytesAvailable = 0;
 69  32
         __ioException = null;
 70  32
         __readIsWaiting = false;
 71  32
         __threaded = false;
 72  32
         if(readerThread)
 73  24
             __thread = new Thread(this);
 74  
         else
 75  8
             __thread = null;
 76  32
     }
 77  
 
 78  
     TelnetInputStream(InputStream input, TelnetClient client) {
 79  0
         this(input, client, true);
 80  0
     }
 81  
 
 82  
     void _start()
 83  
     {
 84  24
         if(__thread == null)
 85  0
             return;
 86  
 
 87  
         int priority;
 88  24
         __isClosed = false;
 89  
         // Need to set a higher priority in case JVM does not use pre-emptive
 90  
         // threads.  This should prevent scheduler induced deadlock (rather than
 91  
         // deadlock caused by a bug in this code).
 92  24
         priority = Thread.currentThread().getPriority() + 1;
 93  24
         if (priority > Thread.MAX_PRIORITY)
 94  0
             priority = Thread.MAX_PRIORITY;
 95  24
         __thread.setPriority(priority);
 96  24
         __thread.setDaemon(true);
 97  24
         __thread.start();
 98  24
         __threaded = true;
 99  24
     }
 100  
 
 101  
 
 102  
     // synchronized(__client) critical sections are to protect against
 103  
     // TelnetOutputStream writing through the telnet client at same time
 104  
     // as a processDo/Will/etc. command invoked from TelnetInputStream
 105  
     // tries to write.
 106  
     private int __read() throws IOException
 107  
     {
 108  
         int ch;
 109  
 
 110  
 _loop:
 111  
         while (true)
 112  
         {
 113  
             // Exit only when we reach end of stream.
 114  127
             if ((ch = super.read()) < 0)
 115  0
                 return -1;
 116  
 
 117  103
             ch = (ch & 0xff);
 118  
 
 119  
             /* Code Section added for supporting AYT (start)*/
 120  103
             synchronized (__client)
 121  
             {
 122  103
                 __client._processAYTResponse();
 123  103
             }
 124  
             /* Code Section added for supporting AYT (end)*/
 125  
 
 126  
             /* Code Section added for supporting spystreams (start)*/
 127  103
             __client._spyRead(ch);
 128  
             /* Code Section added for supporting spystreams (end)*/
 129  
 
 130  
 _mainSwitch:
 131  103
             switch (__receiveState)
 132  
             {
 133  
 
 134  
             case _STATE_CR:
 135  0
                 if (ch == '\0')
 136  
                 {
 137  
                     // Strip null
 138  0
                     continue;
 139  
                 }
 140  
                 // How do we handle newline after cr?
 141  
                 //  else if (ch == '\n' && _requestedDont(TelnetOption.ECHO) &&
 142  
 
 143  
                 // Handle as normal data by falling through to _STATE_DATA case
 144  
 
 145  
             case _STATE_DATA:
 146  43
                 if (ch == TelnetCommand.IAC)
 147  
                 {
 148  27
                     __receiveState = _STATE_IAC;
 149  27
                     continue;
 150  
                 }
 151  
 
 152  
 
 153  16
                 if (ch == '\r')
 154  
                 {
 155  0
                     synchronized (__client)
 156  
                     {
 157  0
                         if (__client._requestedDont(TelnetOption.BINARY))
 158  0
                             __receiveState = _STATE_CR;
 159  
                         else
 160  0
                             __receiveState = _STATE_DATA;
 161  0
                     }
 162  
                 }
 163  
                 else
 164  16
                     __receiveState = _STATE_DATA;
 165  16
                 break;
 166  
 
 167  
             case _STATE_IAC:
 168  27
                 switch (ch)
 169  
                 {
 170  
                 case TelnetCommand.WILL:
 171  5
                     __receiveState = _STATE_WILL;
 172  5
                     continue;
 173  
                 case TelnetCommand.WONT:
 174  3
                     __receiveState = _STATE_WONT;
 175  3
                     continue;
 176  
                 case TelnetCommand.DO:
 177  13
                     __receiveState = _STATE_DO;
 178  13
                     continue;
 179  
                 case TelnetCommand.DONT:
 180  4
                     __receiveState = _STATE_DONT;
 181  4
                     continue;
 182  
                 /* TERMINAL-TYPE option (start)*/
 183  
                 case TelnetCommand.SB:
 184  2
                     __suboption_count = 0;
 185  2
                     __receiveState = _STATE_SB;
 186  2
                     continue;
 187  
                 /* TERMINAL-TYPE option (end)*/
 188  
                 case TelnetCommand.IAC:
 189  0
                     __receiveState = _STATE_DATA;
 190  0
                     break;
 191  
                 default:
 192  
                     break;
 193  
                 }
 194  0
                 __receiveState = _STATE_DATA;
 195  0
                 continue;
 196  
             case _STATE_WILL:
 197  5
                 synchronized (__client)
 198  
                 {
 199  5
                     __client._processWill(ch);
 200  5
                     __client._flushOutputStream();
 201  5
                 }
 202  5
                 __receiveState = _STATE_DATA;
 203  5
                 continue;
 204  
             case _STATE_WONT:
 205  3
                 synchronized (__client)
 206  
                 {
 207  3
                     __client._processWont(ch);
 208  3
                     __client._flushOutputStream();
 209  3
                 }
 210  3
                 __receiveState = _STATE_DATA;
 211  3
                 continue;
 212  
             case _STATE_DO:
 213  13
                 synchronized (__client)
 214  
                 {
 215  13
                     __client._processDo(ch);
 216  13
                     __client._flushOutputStream();
 217  13
                 }
 218  13
                 __receiveState = _STATE_DATA;
 219  13
                 continue;
 220  
             case _STATE_DONT:
 221  4
                 synchronized (__client)
 222  
                 {
 223  4
                     __client._processDont(ch);
 224  4
                     __client._flushOutputStream();
 225  4
                 }
 226  4
                 __receiveState = _STATE_DATA;
 227  4
                 continue;
 228  
             /* TERMINAL-TYPE option (start)*/
 229  
             case _STATE_SB:
 230  6
                 switch (ch)
 231  
                 {
 232  
                 case TelnetCommand.IAC:
 233  2
                     __receiveState = _STATE_IAC_SB;
 234  2
                     continue;
 235  
                 default:
 236  
                     // store suboption char
 237  4
                     __suboption[__suboption_count++] = ch;
 238  
                     break;
 239  
                 }
 240  4
                 __receiveState = _STATE_SB;
 241  4
                 continue;
 242  
             case _STATE_IAC_SB:
 243  2
                 switch (ch)
 244  
                 {
 245  
                 case TelnetCommand.SE:
 246  2
                     synchronized (__client)
 247  
                     {
 248  2
                         __client._processSuboption(__suboption, __suboption_count);
 249  2
                         __client._flushOutputStream();
 250  2
                     }
 251  2
                     __receiveState = _STATE_DATA;
 252  2
                     continue;
 253  
                 default:
 254  0
                     __receiveState = _STATE_SB;
 255  
                     break;
 256  
                 }
 257  0
                 __receiveState = _STATE_DATA;
 258  0
                 continue;
 259  
             /* TERMINAL-TYPE option (end)*/
 260  
             }
 261  
 
 262  16
             break;
 263  
         }
 264  
 
 265  16
         return ch;
 266  
     }
 267  
 
 268  
     // synchronized(__client) critical sections are to protect against
 269  
     // TelnetOutputStream writing through the telnet client at same time
 270  
     // as a processDo/Will/etc. command invoked from TelnetInputStream
 271  
     // tries to write.
 272  
     private void __processChar(int ch) throws InterruptedException
 273  
     {
 274  
         // Critical section because we're altering __bytesAvailable,
 275  
         // __queueTail, and the contents of _queue.
 276  16
         synchronized (__queue)
 277  
         {
 278  16
             while (__bytesAvailable >= __queue.length - 1)
 279  
             {
 280  0
                 if(__threaded)
 281  
                 {
 282  0
                     __queue.notify();
 283  
                     try
 284  
                     {
 285  0
                         __queue.wait();
 286  
                     }
 287  0
                     catch (InterruptedException e)
 288  
                     {
 289  0
                         throw e;
 290  0
                     }
 291  
                 }
 292  
             }
 293  
 
 294  
             // Need to do this in case we're not full, but block on a read
 295  16
             if (__readIsWaiting && __threaded)
 296  
             {
 297  0
                 __queue.notify();
 298  
             }
 299  
 
 300  16
             __queue[__queueTail] = ch;
 301  16
             ++__bytesAvailable;
 302  
 
 303  16
             if (++__queueTail >= __queue.length)
 304  0
                 __queueTail = 0;
 305  16
         }
 306  16
     }
 307  
 
 308  
     public int read() throws IOException
 309  
     {
 310  
         // Critical section because we're altering __bytesAvailable,
 311  
         // __queueHead, and the contents of _queue in addition to
 312  
         // testing value of __hasReachedEOF.
 313  1
         synchronized (__queue)
 314  
         {
 315  
 
 316  
             while (true)
 317  
             {
 318  2
                 if (__ioException != null)
 319  
                 {
 320  
                     IOException e;
 321  0
                     e = __ioException;
 322  0
                     __ioException = null;
 323  0
                     throw e;
 324  
                 }
 325  
 
 326  2
                 if (__bytesAvailable == 0)
 327  
                 {
 328  
                     // Return -1 if at end of file
 329  1
                     if (__hasReachedEOF)
 330  0
                         return -1;
 331  
 
 332  
                     // Otherwise, we have to wait for queue to get something
 333  1
                     if(__threaded)
 334  
                     {
 335  0
                         __queue.notify();
 336  
                         try
 337  
                         {
 338  0
                             __readIsWaiting = true;
 339  0
                             __queue.wait();
 340  0
                             __readIsWaiting = false;
 341  
                         }
 342  0
                         catch (InterruptedException e)
 343  
                         {
 344  0
                             throw new IOException("Fatal thread interruption during read.");
 345  0
                         }
 346  
                     }
 347  
                     else
 348  
                     {
 349  
                         //__alreadyread = false;
 350  1
                         __readIsWaiting = true;
 351  
                         int ch;
 352  
 
 353  
                         do
 354  
                         {
 355  
                             try
 356  
                             {
 357  1
                                 if ((ch = __read()) < 0)
 358  0
                                     if(ch != -2)
 359  0
                                         return (ch);
 360  
                             }
 361  0
                             catch (InterruptedIOException e)
 362  
                             {
 363  0
                                 synchronized (__queue)
 364  
                                 {
 365  0
                                     __ioException = e;
 366  0
                                     __queue.notifyAll();
 367  
                                     try
 368  
                                     {
 369  0
                                         __queue.wait(100);
 370  
                                     }
 371  0
                                     catch (InterruptedException interrupted)
 372  
                                     {
 373  0
                                     }
 374  0
                                 }
 375  0
                                 return (-1);
 376  1
                             }
 377  
 
 378  
 
 379  
                             try
 380  
                             {
 381  1
                                 if(ch != -2)
 382  
                                 {
 383  1
                                     __processChar(ch);
 384  
                                 }
 385  
                             }
 386  0
                             catch (InterruptedException e)
 387  
                             {
 388  0
                                 if (__isClosed)
 389  0
                                     return (-1);
 390  1
                             }
 391  
                         }
 392  1
                         while (super.available() > 0);
 393  
 
 394  1
                         __readIsWaiting = false;
 395  
                     }
 396  1
                     continue;
 397  
                 }
 398  
                 else
 399  
                 {
 400  
                     int ch;
 401  
 
 402  1
                     ch = __queue[__queueHead];
 403  
 
 404  1
                     if (++__queueHead >= __queue.length)
 405  0
                         __queueHead = 0;
 406  
 
 407  1
                     --__bytesAvailable;
 408  
 
 409  
 		    // Need to explicitly notify() so available() works properly
 410  1
 		    if(__bytesAvailable == 0 && __threaded) {
 411  0
 			    __queue.notify();
 412  
 		    }
 413  
 		    
 414  1
                     return ch;
 415  
                 }
 416  
             }
 417  0
         }
 418  
     }
 419  
 
 420  
 
 421  
     /***
 422  
      * Reads the next number of bytes from the stream into an array and
 423  
      * returns the number of bytes read.  Returns -1 if the end of the
 424  
      * stream has been reached.
 425  
      * <p>
 426  
      * @param buffer  The byte array in which to store the data.
 427  
      * @return The number of bytes read. Returns -1 if the
 428  
      *          end of the message has been reached.
 429  
      * @exception IOException If an error occurs in reading the underlying
 430  
      *            stream.
 431  
      ***/
 432  
     public int read(byte buffer[]) throws IOException
 433  
     {
 434  0
         return read(buffer, 0, buffer.length);
 435  
     }
 436  
 
 437  
 
 438  
     /***
 439  
      * Reads the next number of bytes from the stream into an array and returns
 440  
      * the number of bytes read.  Returns -1 if the end of the
 441  
      * message has been reached.  The characters are stored in the array
 442  
      * starting from the given offset and up to the length specified.
 443  
      * <p>
 444  
      * @param buffer The byte array in which to store the data.
 445  
      * @param offset  The offset into the array at which to start storing data.
 446  
      * @param length   The number of bytes to read.
 447  
      * @return The number of bytes read. Returns -1 if the
 448  
      *          end of the stream has been reached.
 449  
      * @exception IOException If an error occurs while reading the underlying
 450  
      *            stream.
 451  
      ***/
 452  
     public int read(byte buffer[], class="keyword">int offset, class="keyword">int length) throws IOException
 453  
     {
 454  
         int ch, off;
 455  
 
 456  1
         if (length < 1)
 457  0
             return 0;
 458  
 
 459  
         // Critical section because run() may change __bytesAvailable
 460  1
         synchronized (__queue)
 461  
         {
 462  1
             if (length > __bytesAvailable)
 463  1
                 length = __bytesAvailable;
 464  1
         }
 465  
 
 466  1
         if ((ch = read()) == -1)
 467  0
             return -1;
 468  
 
 469  1
         off = offset;
 470  
 
 471  
         do
 472  
         {
 473  1
             buffer[offset++] = (byte)ch;
 474  
         }
 475  1
         while (--length > 0 && (ch = read()) != -1);
 476  
 
 477  
         //__client._spyRead(buffer, off, offset - off);
 478  1
         return (offset - off);
 479  
     }
 480  
 
 481  
 
 482  
     /*** Returns false.  Mark is not supported. ***/
 483  
     public boolean markSupported()
 484  
     {
 485  0
         return false;
 486  
     }
 487  
 
 488  
     public int available() throws IOException
 489  
     {
 490  
         // Critical section because run() may change __bytesAvailable
 491  1
         synchronized (__queue)
 492  
         {
 493  1
             return __bytesAvailable;
 494  0
         }
 495  
     }
 496  
 
 497  
 
 498  
     // Cannot be synchronized.  Will cause deadlock if run() is blocked
 499  
     // in read because BufferedInputStream read() is synchronized.
 500  
     public void close() throws IOException
 501  
     {
 502  
         // Completely disregard the fact thread may still be running.
 503  
         // We can't afford to block on this close by waiting for
 504  
         // thread to terminate because few if any JVM's will actually
 505  
         // interrupt a system read() from the interrupt() method.
 506  32
         super.close();
 507  
 
 508  32
         synchronized (__queue)
 509  
         {
 510  32
             __hasReachedEOF = true;
 511  32
             __isClosed      = true;
 512  
 
 513  32
             if (__thread != null && __thread.isAlive())
 514  
             {
 515  24
                 __thread.interrupt();
 516  
             }
 517  
 
 518  32
             __queue.notifyAll();
 519  32
         }
 520  
 
 521  32
         __threaded = false;
 522  32
     }
 523  
 
 524  
     public void run()
 525  
     {
 526  
         int ch;
 527  
 
 528  
         try
 529  
         {
 530  
 _outerLoop:
 531  39
             while (!__isClosed)
 532  
             {
 533  
                 try
 534  
                 {
 535  39
                     if ((ch = __read()) < 0)
 536  0
                         break;
 537  
                 }
 538  0
                 catch (InterruptedIOException e)
 539  
                 {
 540  0
                     synchronized (__queue)
 541  
                     {
 542  0
                         __ioException = e;
 543  0
                         __queue.notifyAll();
 544  
                         try
 545  
                         {
 546  0
                             __queue.wait(100);
 547  
                         }
 548  0
                         catch (InterruptedException interrupted)
 549  
                         {
 550  0
                             if (__isClosed)
 551  0
                                 break _outerLoop;
 552  0
                         }
 553  0
                         continue;
 554  0
                     }
 555  0
                 } catch(RuntimeException re) {
 556  
                     // We treat any runtime exceptions as though the
 557  
                     // stream has been closed.  We close the
 558  
                     // underlying stream just to be sure.
 559  0
                     super.close();
 560  
                     // Breaking the loop has the effect of setting
 561  
                     // the state to closed at the end of the method.
 562  0
                     break _outerLoop;
 563  15
                 }
 564  
 
 565  
                 try
 566  
                 {
 567  15
                     __processChar(ch);
 568  
                 }
 569  0
                 catch (InterruptedException e)
 570  
                 {
 571  0
                     if (__isClosed)
 572  0
                         break _outerLoop;
 573  15
                 }
 574  
             }
 575  
         }
 576  24
         catch (IOException ioe)
 577  
         {
 578  24
             synchronized (__queue)
 579  
             {
 580  24
                 __ioException = ioe;
 581  24
             }
 582  0
         }
 583  
 
 584  24
         synchronized (__queue)
 585  
         {
 586  24
             __isClosed      = true; // Possibly redundant
 587  24
             __hasReachedEOF = true;
 588  24
             __queue.notify();
 589  24
         }
 590  
 
 591  24
         __threaded = false;
 592  24
     }
 593  
 }
 594  
 
 595  
 /* Emacs configuration
 596  
  * Local variables:        **
 597  
  * mode:             java  **
 598  
  * c-basic-offset:   4     **
 599  
  * indent-tabs-mode: nil   **
 600  
  * End:                    **
 601  
  */

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.