1 package org.apache.commons.net.telnet;
2
3 /* ====================================================================
4 * The Apache Software License, Version 1.1
5 *
6 * Copyright (c) 2001 The Apache Software Foundation. All rights
7 * reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. The end-user documentation included with the redistribution,
22 * if any, must include the following acknowledgment:
23 * "This product includes software developed by the
24 * Apache Software Foundation (http://www.apache.org/)."
25 * Alternately, this acknowledgment may appear in the software itself,
26 * if and wherever such third-party acknowledgments normally appear.
27 *
28 * 4. The names "Apache" and "Apache Software Foundation" and
29 * "Apache Commons" must not be used to endorse or promote products
30 * derived from this software without prior written permission. For
31 * written permission, please contact apache@apache.org.
32 *
33 * 5. Products derived from this software may not be called "Apache",
34 * nor may "Apache" appear in their name, without
35 * prior written permission of the Apache Software Foundation.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This software consists of voluntary contributions made by many
52 * individuals on behalf of the Apache Software Foundation. For more
53 * information on the Apache Software Foundation, please see
54 * <http://www.apache.org/>.
55 */
56
57 import java.io.BufferedInputStream;
58 import java.io.IOException;
59 import java.io.InputStream;
60 import java.io.InterruptedIOException;
61
62 /****
63 *
64 * <p>
65 *
66 * <p>
67 * <p>
68 * @author Daniel F. Savarese
69 ***/
70
71
72 final class TelnetInputStream extends BufferedInputStream implements Runnable
73 {
74 static final int _STATE_DATA = 0, _STATE_IAC = 1, _STATE_WILL = 2,
75 _STATE_WONT = 3, _STATE_DO = 4, _STATE_DONT = 5,
76 _STATE_SB = 6, _STATE_SE = 7, _STATE_CR = 8;
77
78 private boolean __hasReachedEOF, __isClosed;
79 private boolean __readIsWaiting;
80 private int __receiveState, __queueHead, __queueTail, __bytesAvailable;
81 private int[] __queue;
82 private TelnetClient __client;
83 private Thread __thread;
84 private IOException __ioException;
85
86 TelnetInputStream(InputStream input, TelnetClient client)
87 {
88 super(input);
89 __client = client;
90 __receiveState = _STATE_DATA;
91 __isClosed = true;
92 __hasReachedEOF = false;
93 // Make it 1025, because when full, one slot will go unused, and we
94 // want a 1024 byte buffer just to have a round number (base 2 that is)
95 //__queue = new int[1025];
96 __queue = new int[2049];
97 __queueHead = 0;
98 __queueTail = 0;
99 __bytesAvailable = 0;
100 __ioException = null;
101 __readIsWaiting = false;
102 __thread = new Thread(this);
103 }
104
105 void _start()
106 {
107 int priority;
108 __isClosed = false;
109 // Need to set a higher priority in case JVM does not use pre-emptive
110 // threads. This should prevent scheduler induced deadlock (rather than
111 // deadlock caused by a bug in this code).
112 priority = Thread.currentThread().getPriority() + 1;
113 if (priority > Thread.MAX_PRIORITY)
114 priority = Thread.MAX_PRIORITY;
115 __thread.setPriority(priority);
116 __thread.setDaemon(true);
117 __thread.start();
118 }
119
120
121 // synchronized(__client) critical sections are to protect against
122 // TelnetOutputStream writing through the telnet client at same time
123 // as a processDo/Will/etc. command invoked from TelnetInputStream
124 // tries to write.
125 private int __read() throws IOException
126 {
127 int ch;
128
129 _loop:
130 while (true)
131 {
132 // Exit only when we reach end of stream.
133 if ((ch = super.read()) < 0)
134 return -1;
135
136 ch = (ch & 0xff);
137
138 _mainSwitch:
139 switch (__receiveState)
140 {
141
142 case _STATE_CR:
143 if (ch == '\0')
144 {
145 // Strip null
146 continue;
147 }
148 // How do we handle newline after cr?
149 // else if (ch == '\n' && _requestedDont(TelnetOption.ECHO) &&
150
151 // Handle as normal data by falling through to _STATE_DATA case
152
153 case _STATE_DATA:
154 if (ch == TelnetCommand.IAC)
155 {
156 __receiveState = _STATE_IAC;
157 continue;
158 }
159
160
161 if (ch == '\r')
162 {
163 synchronized (__client)
164 {
165 if (__client._requestedDont(TelnetOption.BINARY))
166 __receiveState = _STATE_CR;
167 else
168 __receiveState = _STATE_DATA;
169 }
170 }
171 else
172 __receiveState = _STATE_DATA;
173 break;
174
175 case _STATE_IAC:
176 switch (ch)
177 {
178 case TelnetCommand.WILL:
179 __receiveState = _STATE_WILL;
180 continue;
181 case TelnetCommand.WONT:
182 __receiveState = _STATE_WONT;
183 continue;
184 case TelnetCommand.DO:
185 __receiveState = _STATE_DO;
186 continue;
187 case TelnetCommand.DONT:
188 __receiveState = _STATE_DONT;
189 continue;
190 case TelnetCommand.IAC:
191 __receiveState = _STATE_DATA;
192 break;
193 default:
194 break;
195 }
196 __receiveState = _STATE_DATA;
197 continue;
198 case _STATE_WILL:
199 synchronized (__client)
200 {
201 __client._processWill(ch);
202 __client._flushOutputStream();
203 }
204 __receiveState = _STATE_DATA;
205 continue;
206 case _STATE_WONT:
207 synchronized (__client)
208 {
209 __client._processWont(ch);
210 __client._flushOutputStream();
211 }
212 __receiveState = _STATE_DATA;
213 continue;
214 case _STATE_DO:
215 synchronized (__client)
216 {
217 __client._processDo(ch);
218 __client._flushOutputStream();
219 }
220 __receiveState = _STATE_DATA;
221 continue;
222 case _STATE_DONT:
223 synchronized (__client)
224 {
225 __client._processDont(ch);
226 __client._flushOutputStream();
227 }
228 __receiveState = _STATE_DATA;
229 continue;
230 }
231
232 break;
233 }
234
235 return ch;
236 }
237
238
239
240 public int read() throws IOException
241 {
242 // Critical section because we're altering __bytesAvailable,
243 // __queueHead, and the contents of _queue in addition to
244 // testing value of __hasReachedEOF.
245 synchronized (__queue)
246 {
247
248 while (true)
249 {
250 if (__ioException != null)
251 {
252 IOException e;
253 e = __ioException;
254 __ioException = null;
255 throw e;
256 }
257
258 if (__bytesAvailable == 0)
259 {
260 // Return -1 if at end of file
261 if (__hasReachedEOF)
262 return -1;
263
264 // Otherwise, we have to wait for queue to get something
265 __queue.notify();
266 try
267 {
268 __readIsWaiting = true;
269 __queue.wait();
270 __readIsWaiting = false;
271 }
272 catch (InterruptedException e)
273 {
274 throw new IOException("Fatal thread interruption during read.");
275 }
276 continue;
277 }
278 else
279 {
280 int ch;
281
282 ch = __queue[__queueHead];
283
284 if (++__queueHead >= __queue.length)
285 __queueHead = 0;
286
287 --__bytesAvailable;
288
289 return ch;
290 }
291 }
292 }
293 }
294
295
296 /****
297 * Reads the next number of bytes from the stream into an array and
298 * returns the number of bytes read. Returns -1 if the end of the
299 * stream has been reached.
300 * <p>
301 * @param buffer The byte array in which to store the data.
302 * @return The number of bytes read. Returns -1 if the
303 * end of the message has been reached.
304 * @exception IOException If an error occurs in reading the underlying
305 * stream.
306 ***/
307 public int read(byte buffer[]) throws IOException
308 {
309 return read(buffer, 0, buffer.length);
310 }
311
312
313 /****
314 * Reads the next number of bytes from the stream into an array and returns
315 * the number of bytes read. Returns -1 if the end of the
316 * message has been reached. The characters are stored in the array
317 * starting from the given offset and up to the length specified.
318 * <p>
319 * @param buffer The byte array in which to store the data.
320 * @param offset The offset into the array at which to start storing data.
321 * @param length The number of bytes to read.
322 * @return The number of bytes read. Returns -1 if the
323 * end of the stream has been reached.
324 * @exception IOException If an error occurs while reading the underlying
325 * stream.
326 ***/
327 public int read(byte buffer[], int offset, int length) throws IOException
328 {
329 int ch, off;
330
331 if (length < 1)
332 return 0;
333
334 // Critical section because run() may change __bytesAvailable
335 synchronized (__queue)
336 {
337 if (length > __bytesAvailable)
338 length = __bytesAvailable;
339 }
340
341 if ((ch = read()) == -1)
342 return -1;
343
344 off = offset;
345
346 do
347 {
348 buffer[offset++] = (byte)ch;
349 }
350 while (--length > 0 && (ch = read()) != -1);
351
352 return (offset - off);
353 }
354
355
356 /**** Returns false. Mark is not supported. ***/
357 public boolean markSupported()
358 {
359 return false;
360 }
361
362 public int available() throws IOException
363 {
364 // Critical section because run() may change __bytesAvailable
365 synchronized (__queue)
366 {
367 return __bytesAvailable;
368 }
369 }
370
371
372 // Cannot be synchronized. Will cause deadlock if run() is blocked
373 // in read because BufferedInputStream read() is synchronized.
374 public void close() throws IOException
375 {
376 // Completely disregard the fact thread may still be running.
377 // We can't afford to block on this close by waiting for
378 // thread to terminate because few if any JVM's will actually
379 // interrupt a system read() from the interrupt() method.
380 super.close();
381
382 synchronized (__queue)
383 {
384 __hasReachedEOF = true;
385 __isClosed = true;
386
387 if (__thread.isAlive())
388 {
389 __thread.interrupt();
390 }
391
392 __queue.notifyAll();
393 }
394 }
395
396 public void run()
397 {
398 int ch;
399
400 try
401 {
402 _outerLoop:
403 while (!__isClosed)
404 {
405 try
406 {
407 if ((ch = __read()) < 0)
408 break;
409 }
410 catch (InterruptedIOException e)
411 {
412 synchronized (__queue)
413 {
414 __ioException = e;
415 __queue.notifyAll();
416 try
417 {
418 __queue.wait(100);
419 }
420 catch (InterruptedException interrupted)
421 {
422 if (__isClosed)
423 break _outerLoop;
424 }
425 continue;
426 }
427 }
428
429
430 // Critical section because we're altering __bytesAvailable,
431 // __queueTail, and the contents of _queue.
432 synchronized (__queue)
433 {
434 while (__bytesAvailable >= __queue.length - 1)
435 {
436 __queue.notify();
437 try
438 {
439 __queue.wait();
440 }
441 catch (InterruptedException e)
442 {
443 if (__isClosed)
444 break _outerLoop;
445 }
446 }
447
448 // Need to do this in case we're not full, but block on a read
449 if (__readIsWaiting)
450 {
451 __queue.notify();
452 }
453
454 __queue[__queueTail] = ch;
455 ++__bytesAvailable;
456
457 if (++__queueTail >= __queue.length)
458 __queueTail = 0;
459 }
460 }
461 }
462 catch (IOException e)
463 {
464 synchronized (__queue)
465 {
466 __ioException = e;
467 }
468 }
469
470 synchronized (__queue)
471 {
472 __isClosed = true; // Possibly redundant
473 __hasReachedEOF = true;
474 __queue.notify();
475 }
476 }
477
478
479 }
This page was automatically generated by Maven