View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.net.telnet;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertFalse;
21  import static org.junit.jupiter.api.Assertions.assertNotNull;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.OutputStream;
27  import java.io.PipedInputStream;
28  import java.io.PipedOutputStream;
29  import java.time.Duration;
30  
31  import org.apache.commons.lang3.ThreadUtils;
32  import org.junit.jupiter.api.AfterEach;
33  import org.junit.jupiter.api.BeforeEach;
34  import org.junit.jupiter.api.Test;
35  
36  /**
37   * JUnit test class for TelnetClient.s Implements protocol compliance tests
38   */
39  class TelnetClientTest implements TelnetNotificationHandler {
40  
41      /**
42       * Handy holder to hold both sides of the connection used in testing for clarity.
43       */
44      private final class TestConnection {
45          private final TelnetTestSimpleServer server;
46          private final TelnetClient client;
47          private final int port;
48  
49          TestConnection(final TelnetTestSimpleServer server, final TelnetClient client, final int port) {
50              this.server = server;
51              this.client = client;
52              this.port = port;
53          }
54  
55          protected void close() {
56              closeConnection(server, client, port);
57          }
58      }
59  
60      // four connections with different properties
61      // to use in tests.
62      private TestConnection STANDARD;
63      private TestConnection OPTIONS;
64      private TestConnection ANSI;
65      private TestConnection NOREAD;
66      private TestConnection SMALL_BUFFER;
67  
68      private final int NUM_CONNECTIONS = 5;
69  
70      protected int numdo;
71      protected int numdont;
72      protected int numwill;
73      protected int numwont;
74  
75      protected int[] lastSubnegotiation;
76      protected int lastSubnegotiationLength;
77  
78      void closeConnection(final TelnetTestSimpleServer server, final TelnetClient client, final int port) {
79          if (server != null) {
80              server.disconnect();
81              server.stop();
82          }
83          try {
84              if (client != null) {
85                  client.disconnect();
86              }
87          } catch (final IOException e) {
88              System.err.println("failed to close client-server connection on port " + port);
89              System.err.println("ERROR in closeConnection(), " + e.getMessage());
90          }
91  
92      }
93  
94      /*
95       * Helper method. compares two arrays of int
96       */
97      protected boolean equalBytes(final byte a1[], final byte a2[]) {
98          if (a1.length != a2.length) {
99              return false;
100         }
101         boolean result = true;
102         for (int ii = 0; ii < a1.length; ii++) {
103 
104             if (a1[ii] != a2[ii]) {
105                 result = false;
106                 break;
107             }
108         }
109         return result;
110     }
111 
112     /**
113      * Callback method called when TelnetClient receives an option negotiation command. <p>
114      *
115      * @param negotiationCode   type of negotiation command received (RECEIVED_DO, RECEIVED_DONT, RECEIVED_WILL, RECEIVED_WONT) <p>
116      * @param optionCode   code of the option negotiated <p>
117      */
118     @Override
119     public void receivedNegotiation(final int negotiationCode, final int optionCode) {
120         switch (negotiationCode) {
121         case TelnetNotificationHandler.RECEIVED_DO:
122             numdo++;
123             break;
124         case TelnetNotificationHandler.RECEIVED_DONT:
125             numdont++;
126             break;
127         case TelnetNotificationHandler.RECEIVED_WILL:
128             numwill++;
129             break;
130         case TelnetNotificationHandler.RECEIVED_WONT:
131             numwont++;
132             break;
133         default:
134             break;
135         }
136     }
137 
138     /*
139      * open connections needed for the tests for the test.
140      */
141     @BeforeEach
142     protected void setUp() throws Exception {
143         final SimpleOptionHandler subnegotiationSizeHandler = new SimpleOptionHandler(99, false, false, true, false) {
144             @Override
145             public int[] answerSubnegotiation(final int[] suboptionData, final int suboptionLength) {
146                 lastSubnegotiation = suboptionData;
147                 lastSubnegotiationLength = suboptionLength;
148                 return null;
149             }
150         };
151 
152         int socket = 0;
153         for (int port = 3333; socket < NUM_CONNECTIONS && port < 4000; port++) {
154             TelnetTestSimpleServer server = null;
155             TelnetClient client = null;
156             try {
157                 server = new TelnetTestSimpleServer(port);
158                 switch (socket) {
159                 case 0:
160                     client = new TelnetClient();
161                     // redundant but makes code clearer.
162                     client.setReaderThread(true);
163                     client.addOptionHandler(subnegotiationSizeHandler);
164                     client.connect("127.0.0.1", port);
165                     STANDARD = new TestConnection(server, client, port);
166                     break;
167                 case 1:
168                     client = new TelnetClient();
169                     final TerminalTypeOptionHandler ttopt = new TerminalTypeOptionHandler("VT100", false, false, true, false);
170                     final EchoOptionHandler echoopt = new EchoOptionHandler(true, false, true, false);
171                     final SuppressGAOptionHandler gaopt = new SuppressGAOptionHandler(true, true, true, true);
172 
173                     client.addOptionHandler(ttopt);
174                     client.addOptionHandler(echoopt);
175                     client.addOptionHandler(gaopt);
176                     client.connect("127.0.0.1", port);
177                     OPTIONS = new TestConnection(server, client, port);
178                     break;
179                 case 2:
180                     client = new TelnetClient("ANSI");
181                     client.connect("127.0.0.1", port);
182                     ANSI = new TestConnection(server, client, port);
183                     break;
184                 case 3:
185                     client = new TelnetClient();
186                     client.setReaderThread(false);
187                     client.connect("127.0.0.1", port);
188                     NOREAD = new TestConnection(server, client, port);
189                     break;
190                 case 4:
191                     client = new TelnetClient(8);
192                     client.addOptionHandler(subnegotiationSizeHandler);
193                     client.connect("127.0.0.1", port);
194                     SMALL_BUFFER = new TestConnection(server, client, port);
195                     break;
196                 }
197                 // only increment socket number on success
198                 socket++;
199             } catch (final IOException e) {
200                 closeConnection(server, client, port);
201             }
202         }
203         if (socket < NUM_CONNECTIONS) {
204             System.err.println("Only created " + socket + " clients; wanted " + NUM_CONNECTIONS);
205         }
206         Thread.sleep(1000);
207     }
208 
209     /*
210      * @throws Exception
211      */
212     @AfterEach
213     protected void tearDown() throws Exception {
214         NOREAD.close();
215         ANSI.close();
216         OPTIONS.close();
217         STANDARD.close();
218         SMALL_BUFFER.close();
219         ThreadUtils.sleepQuietly(Duration.ofMillis(1000));
220     }
221 
222     /*
223      * test of AYT functionality
224      */
225     @Test
226     void testAYT() throws Exception {
227         boolean aytTrueOk = false;
228         boolean aytFalseOk = false;
229 
230         final byte[] AYT = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.AYT };
231         final byte[] response = { (byte) '[', (byte) 'Y', (byte) 'e', (byte) 's', (byte) ']' };
232         final String[] inputs = new String[1];
233         final String[] outputs = new String[1];
234         inputs[0] = new String(AYT);
235         outputs[0] = new String(response);
236 
237         final OutputStream os = ANSI.server.getOutputStream();
238         final InputStream is = ANSI.server.getInputStream();
239         final TelnetTestResponder tr = new TelnetTestResponder(is, os, inputs, outputs, 30000);
240         assertNotNull(tr);
241         final boolean res1 = ANSI.client.sendAYT(Duration.ofSeconds(2));
242 
243         if (res1) {
244             aytTrueOk = true;
245         }
246 
247         Thread.sleep(1000);
248         is.skip(is.available());
249 
250         final boolean res2 = ANSI.client.sendAYT(Duration.ofSeconds(2));
251 
252         if (!res2) {
253             aytFalseOk = true;
254         }
255 
256         assertTrue(aytTrueOk);
257         assertTrue(aytFalseOk);
258     }
259 
260     /*
261      * protocol compliance test in case of option handler removal
262      */
263     @Test
264     void testDeleteOptionHandler() throws Exception {
265         boolean removeOk = false;
266         boolean removeInvalidOk1 = false;
267         boolean removeInvalidOk2 = false;
268 
269         final byte[] buffread = new byte[6];
270         final byte[] send = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.DO, (byte) TelnetOption.ECHO, (byte) TelnetCommand.IAC, (byte) TelnetCommand.DO,
271                 (byte) TelnetOption.SUPPRESS_GO_AHEAD, (byte) TelnetCommand.IAC, (byte) TelnetCommand.WILL, (byte) TelnetOption.SUPPRESS_GO_AHEAD };
272 
273         final byte[] expected = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.WONT, (byte) TelnetOption.SUPPRESS_GO_AHEAD, (byte) TelnetCommand.IAC,
274                 (byte) TelnetCommand.DONT, (byte) TelnetOption.SUPPRESS_GO_AHEAD };
275 
276         final InputStream is = OPTIONS.server.getInputStream();
277         final OutputStream os = OPTIONS.server.getOutputStream();
278         Thread.sleep(1000);
279         is.skip(is.available());
280         os.write(send);
281         os.flush();
282         Thread.sleep(1000);
283         if (is.available() == 0) {
284             OPTIONS.client.deleteOptionHandler(TelnetOption.SUPPRESS_GO_AHEAD);
285             Thread.sleep(1000);
286             if (is.available() == 6) {
287                 is.read(buffread);
288                 if (equalBytes(buffread, expected)) {
289                     removeOk = true;
290                 }
291             }
292         }
293 
294         try {
295             OPTIONS.client.deleteOptionHandler(TelnetOption.SUPPRESS_GO_AHEAD);
296         } catch (final Exception e) {
297             removeInvalidOk1 = true;
298         }
299 
300         try {
301             OPTIONS.client.deleteOptionHandler(550);
302         } catch (final Exception e) {
303             removeInvalidOk2 = true;
304         }
305 
306         assertTrue(removeOk);
307         assertTrue(removeInvalidOk1);
308         assertTrue(removeInvalidOk2);
309         assertTrue(OPTIONS.client.getLocalOptionState(TelnetOption.ECHO));
310         assertFalse(OPTIONS.client.getLocalOptionState(TelnetOption.SUPPRESS_GO_AHEAD));
311         assertFalse(OPTIONS.client.getLocalOptionState(TelnetOption.SUPPRESS_GO_AHEAD));
312     }
313 
314     /*
315      * tests the initial condition of the sessions
316      */
317     @Test
318     void testInitial() throws Exception {
319         boolean connect1Ok = false;
320         boolean connect2Ok = false;
321         boolean connect3Ok = false;
322         boolean init2Ok = false;
323         boolean addInvalidOk1 = false;
324         boolean addInvalidOk2 = false;
325         final byte[] buffread2 = new byte[9];
326         final byte[] expected2 = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.WILL, (byte) TelnetOption.ECHO, (byte) TelnetCommand.IAC,
327                 (byte) TelnetCommand.WILL, (byte) TelnetOption.SUPPRESS_GO_AHEAD, (byte) TelnetCommand.IAC, (byte) TelnetCommand.DO,
328                 (byte) TelnetOption.SUPPRESS_GO_AHEAD, };
329 
330         final SimpleOptionHandler hand = new SimpleOptionHandler(550);
331         try {
332             STANDARD.client.addOptionHandler(hand);
333         } catch (final Exception e) {
334             addInvalidOk1 = true;
335         }
336 
337         try {
338             OPTIONS.client.addOptionHandler(hand);
339         } catch (final Exception e) {
340             addInvalidOk2 = true;
341         }
342 
343         final InputStream is1 = STANDARD.server.getInputStream();
344         Thread.sleep(1000);
345         if (is1.available() == 0) {
346             connect1Ok = true;
347         }
348 
349         Thread.sleep(1000);
350         final InputStream is2 = OPTIONS.server.getInputStream();
351         if (is2.available() == 9) {
352             is2.read(buffread2);
353             connect2Ok = true;
354 
355             if (equalBytes(buffread2, expected2)) {
356                 init2Ok = true;
357             }
358         }
359 
360         final InputStream is3 = ANSI.server.getInputStream();
361         Thread.sleep(1000);
362         if (is3.available() == 0) {
363             connect3Ok = true;
364         }
365 
366         assertTrue(connect1Ok);
367         assertTrue(connect2Ok);
368         assertTrue(connect3Ok);
369         assertFalse(STANDARD.client.getLocalOptionState(TelnetOption.ECHO));
370         assertFalse(STANDARD.client.getRemoteOptionState(TelnetOption.ECHO));
371         assertFalse(OPTIONS.client.getLocalOptionState(TelnetOption.ECHO));
372         assertFalse(OPTIONS.client.getRemoteOptionState(TelnetOption.ECHO));
373         assertFalse(ANSI.client.getLocalOptionState(TelnetOption.TERMINAL_TYPE));
374         assertFalse(ANSI.client.getRemoteOptionState(TelnetOption.TERMINAL_TYPE));
375         assertTrue(init2Ok);
376         assertTrue(addInvalidOk1);
377         assertTrue(addInvalidOk2);
378     }
379 
380     /*
381      * test of max subnegotiation length
382      */
383     @Test
384     void testMaxSubnegotiationLength() throws Exception {
385         final byte[] send = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.SB, (byte) 99, (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6,
386                 (byte) 7, (byte) 8, (byte) 9, (byte) 10, (byte) 11, (byte) 12, (byte) 13, (byte) 14, (byte) 15, (byte) TelnetCommand.IAC,
387                 (byte) TelnetCommand.SE, };
388 
389         final OutputStream os1 = SMALL_BUFFER.server.getOutputStream();
390         os1.write(send);
391         os1.flush();
392         Thread.sleep(500);
393 
394         // we sent 16 bytes, but the buffer size should just be 8
395         assertEquals(8, lastSubnegotiationLength);
396         assertEquals(8, lastSubnegotiation.length);
397         assertEquals(99, lastSubnegotiation[0]);
398         assertEquals(1, lastSubnegotiation[1]);
399         assertEquals(2, lastSubnegotiation[2]);
400         assertEquals(3, lastSubnegotiation[3]);
401         assertEquals(4, lastSubnegotiation[4]);
402         assertEquals(5, lastSubnegotiation[5]);
403         assertEquals(6, lastSubnegotiation[6]);
404         assertEquals(7, lastSubnegotiation[7]);
405 
406         final OutputStream os2 = STANDARD.server.getOutputStream();
407         os2.write(send);
408         os2.flush();
409         Thread.sleep(500);
410 
411         // the standard subnegotiation buffer size is 512
412         assertEquals(16, lastSubnegotiationLength);
413         assertEquals(512, lastSubnegotiation.length);
414         assertEquals(99, lastSubnegotiation[0]);
415         assertEquals(1, lastSubnegotiation[1]);
416         assertEquals(2, lastSubnegotiation[2]);
417         assertEquals(3, lastSubnegotiation[3]);
418         assertEquals(4, lastSubnegotiation[4]);
419         assertEquals(5, lastSubnegotiation[5]);
420         assertEquals(6, lastSubnegotiation[6]);
421         assertEquals(7, lastSubnegotiation[7]);
422     }
423 
424     /*
425      * test of option negotiation notification
426      */
427     @Test
428     void testNotification() throws Exception {
429         final byte[] buffread1 = new byte[6];
430         final byte[] send1 = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.DO, (byte) 15, (byte) TelnetCommand.IAC, (byte) TelnetCommand.WILL, (byte) 15, };
431 
432         final byte[] buffread2 = new byte[9];
433         final byte[] send2 = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.DO, (byte) TelnetOption.TERMINAL_TYPE, (byte) TelnetCommand.IAC,
434                 (byte) TelnetCommand.DONT, (byte) TelnetOption.ECHO, (byte) TelnetCommand.IAC, (byte) TelnetCommand.DO, (byte) TelnetOption.SUPPRESS_GO_AHEAD,
435                 (byte) TelnetCommand.IAC, (byte) TelnetCommand.WONT, (byte) TelnetOption.SUPPRESS_GO_AHEAD };
436 
437         final byte[] buffread2b = new byte[11];
438 
439         numdo = 0;
440         numdont = 0;
441         numwill = 0;
442         numwont = 0;
443         OPTIONS.client.registerNotifHandler(this);
444 
445         final InputStream is1 = STANDARD.server.getInputStream();
446         final OutputStream os1 = STANDARD.server.getOutputStream();
447         is1.skip(is1.available());
448         os1.write(send1);
449         os1.flush();
450         Thread.sleep(500);
451         if (is1.available() > 0) {
452             is1.read(buffread1);
453         }
454 
455         final InputStream is2 = OPTIONS.server.getInputStream();
456         final OutputStream os2 = OPTIONS.server.getOutputStream();
457         Thread.sleep(500);
458         is2.skip(is2.available());
459         os2.write(send2);
460         os2.flush();
461         Thread.sleep(500);
462         if (is2.available() > 0) {
463             is2.read(buffread2);
464             Thread.sleep(1000);
465             if (is2.available() > 0) {
466                 is2.read(buffread2b);
467             }
468         }
469 
470         assertEquals(2, numdo);
471         assertEquals(1, numdont);
472         assertEquals(1, numwont);
473         assertEquals(0, numwill);
474     }
475 
476     /*
477      * protocol compliance test for option negotiation
478      */
479     @Test
480     void testOptionNegotiation() throws Exception {
481         boolean negotiation1Ok = false;
482         final byte[] buffread1 = new byte[6];
483         final byte[] send1 = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.DO, (byte) 15, (byte) TelnetCommand.IAC, (byte) TelnetCommand.WILL, (byte) 15, };
484         final byte[] expected1 = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.WONT, (byte) 15, (byte) TelnetCommand.IAC, (byte) TelnetCommand.DONT,
485                 (byte) 15, };
486 
487         boolean negotiation2Ok = false;
488         final byte[] buffread2 = new byte[9];
489         final byte[] send2 = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.DO, (byte) TelnetOption.TERMINAL_TYPE, (byte) TelnetCommand.IAC,
490                 (byte) TelnetCommand.DONT, (byte) TelnetOption.ECHO, (byte) TelnetCommand.IAC, (byte) TelnetCommand.DO, (byte) TelnetOption.SUPPRESS_GO_AHEAD,
491                 (byte) TelnetCommand.IAC, (byte) TelnetCommand.WONT, (byte) TelnetOption.SUPPRESS_GO_AHEAD };
492         final byte[] expected2 = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.WILL, (byte) TelnetOption.TERMINAL_TYPE, (byte) TelnetCommand.IAC,
493                 (byte) TelnetCommand.WONT, (byte) TelnetOption.ECHO, (byte) TelnetCommand.IAC, (byte) TelnetCommand.DONT,
494                 (byte) TelnetOption.SUPPRESS_GO_AHEAD };
495 
496         final byte[] buffread2b = new byte[11];
497         final byte[] send2b = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.SB, (byte) TelnetOption.TERMINAL_TYPE, (byte) 1, (byte) TelnetCommand.IAC,
498                 (byte) TelnetCommand.SE, };
499         final byte[] expected2b = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.SB, (byte) TelnetOption.TERMINAL_TYPE, (byte) 0, (byte) 'V', (byte) 'T',
500                 (byte) '1', (byte) '0', (byte) '0', (byte) TelnetCommand.IAC, (byte) TelnetCommand.SE, };
501 
502         boolean negotiation3Ok = false;
503         final byte[] buffread3 = new byte[6];
504         final byte[] send3 = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.DO, (byte) TelnetOption.TERMINAL_TYPE, (byte) TelnetCommand.IAC,
505                 (byte) TelnetCommand.DO, (byte) TelnetOption.SUPPRESS_GO_AHEAD };
506         final byte[] expected3 = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.WILL, (byte) TelnetOption.TERMINAL_TYPE, (byte) TelnetCommand.IAC,
507                 (byte) TelnetCommand.WONT, (byte) TelnetOption.SUPPRESS_GO_AHEAD };
508         final byte[] buffread3b = new byte[10];
509         final byte[] send3b = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.SB, (byte) TelnetOption.TERMINAL_TYPE, (byte) 1, (byte) TelnetCommand.IAC,
510                 (byte) TelnetCommand.SE, };
511         final byte[] expected3b = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.SB, (byte) TelnetOption.TERMINAL_TYPE, (byte) 0, (byte) 'A', (byte) 'N',
512                 (byte) 'S', (byte) 'I', (byte) TelnetCommand.IAC, (byte) TelnetCommand.SE, };
513 
514         final InputStream is1 = STANDARD.server.getInputStream();
515         final OutputStream os1 = STANDARD.server.getOutputStream();
516         is1.skip(is1.available());
517         os1.write(send1);
518         os1.flush();
519         Thread.sleep(1000);
520         if (is1.available() == 6) {
521             is1.read(buffread1);
522 
523             if (equalBytes(buffread1, expected1)) {
524                 negotiation1Ok = true;
525             }
526         }
527 
528         final InputStream is2 = OPTIONS.server.getInputStream();
529         final OutputStream os2 = OPTIONS.server.getOutputStream();
530         Thread.sleep(1000);
531         is2.skip(is2.available());
532         os2.write(send2);
533         os2.flush();
534         Thread.sleep(1000);
535         if (is2.available() == 9) {
536             is2.read(buffread2);
537 
538             if (equalBytes(buffread2, expected2)) {
539                 negotiation2Ok = true;
540             }
541 
542             if (negotiation2Ok) {
543                 negotiation2Ok = false;
544                 os2.write(send2b);
545                 os2.flush();
546                 Thread.sleep(1000);
547                 if (is2.available() == 11) {
548                     is2.read(buffread2b);
549 
550                     if (equalBytes(buffread2b, expected2b)) {
551                         negotiation2Ok = true;
552                     }
553                 }
554             }
555         }
556 
557         final InputStream is3 = ANSI.server.getInputStream();
558         final OutputStream os3 = ANSI.server.getOutputStream();
559         Thread.sleep(1000);
560         is3.skip(is3.available());
561         os3.write(send3);
562         os3.flush();
563         Thread.sleep(1000);
564         if (is3.available() == 6) {
565             is3.read(buffread3);
566 
567             if (equalBytes(buffread3, expected3)) {
568                 negotiation3Ok = true;
569             }
570 
571             if (negotiation3Ok) {
572                 negotiation3Ok = false;
573                 os3.write(send3b);
574                 os3.flush();
575                 Thread.sleep(1000);
576                 if (is3.available() == 10) {
577                     is3.read(buffread3b);
578                     if (equalBytes(buffread3b, expected3b)) {
579                         negotiation3Ok = true;
580                     }
581                 }
582             }
583         }
584 
585         assertTrue(negotiation1Ok);
586         assertTrue(negotiation2Ok);
587         assertTrue(negotiation3Ok);
588         assertFalse(STANDARD.client.getLocalOptionState(15));
589         assertFalse(STANDARD.client.getRemoteOptionState(15));
590         assertFalse(STANDARD.client.getLocalOptionState(TelnetOption.TERMINAL_TYPE));
591         assertFalse(OPTIONS.client.getLocalOptionState(TelnetOption.ECHO));
592         assertFalse(OPTIONS.client.getRemoteOptionState(TelnetOption.ECHO));
593         assertTrue(OPTIONS.client.getLocalOptionState(TelnetOption.SUPPRESS_GO_AHEAD));
594         assertFalse(OPTIONS.client.getRemoteOptionState(TelnetOption.SUPPRESS_GO_AHEAD));
595         assertTrue(OPTIONS.client.getLocalOptionState(TelnetOption.TERMINAL_TYPE));
596         assertTrue(ANSI.client.getLocalOptionState(TelnetOption.TERMINAL_TYPE));
597         assertFalse(OPTIONS.client.getLocalOptionState(TelnetOption.ECHO));
598     }
599 
600     /*
601      * protocol compliance test for option renegotiation
602      */
603     @Test
604     void testOptionRenegotiation() throws Exception {
605         boolean negotiation1Ok = false;
606 
607         final byte[] buffread = new byte[6];
608         final byte[] send = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.DO, (byte) TelnetOption.ECHO, (byte) TelnetCommand.IAC, (byte) TelnetCommand.DONT,
609                 (byte) TelnetOption.SUPPRESS_GO_AHEAD, (byte) TelnetCommand.IAC, (byte) TelnetCommand.WONT, (byte) TelnetOption.SUPPRESS_GO_AHEAD };
610         final byte[] expected = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.WONT, (byte) TelnetOption.SUPPRESS_GO_AHEAD, (byte) TelnetCommand.IAC,
611                 (byte) TelnetCommand.DONT, (byte) TelnetOption.SUPPRESS_GO_AHEAD };
612 
613         final byte[] buffread2 = new byte[3];
614         final byte[] send2 = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.DONT, (byte) TelnetOption.ECHO, };
615         final byte[] expected2 = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.WONT, (byte) TelnetOption.ECHO, };
616 
617         final InputStream is = OPTIONS.server.getInputStream();
618         final OutputStream os = OPTIONS.server.getOutputStream();
619         Thread.sleep(1000);
620         is.skip(is.available());
621         os.write(send);
622         os.flush();
623         Thread.sleep(1000);
624         if (is.available() == 6) {
625             is.read(buffread);
626 
627             if (equalBytes(buffread, expected)) {
628                 negotiation1Ok = true;
629             }
630 
631             if (negotiation1Ok) {
632                 negotiation1Ok = false;
633                 os.write(send2);
634                 os.flush();
635                 Thread.sleep(1000);
636                 if (is.available() == 3) {
637                     is.read(buffread2);
638                     if (equalBytes(buffread2, expected2)) {
639                         negotiation1Ok = true;
640                     }
641                 }
642             }
643         }
644 
645         assertTrue(negotiation1Ok);
646         assertFalse(OPTIONS.client.getLocalOptionState(TelnetOption.ECHO));
647     }
648 
649     /*
650      * test of setReaderThread
651      */
652     @Test
653     void testSetReaderThread() throws Exception {
654         boolean negotiation1Ok = false;
655         boolean negotiation2Ok = false;
656         boolean readOk = false;
657         final byte[] buffread1 = new byte[6];
658         final byte[] send1 = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.DO, (byte) 15, (byte) TelnetCommand.IAC, (byte) TelnetCommand.WILL, (byte) 15, };
659         final byte[] expected1 = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.WONT, (byte) 15, (byte) TelnetCommand.IAC, (byte) TelnetCommand.DONT,
660                 (byte) 15, };
661 
662         final InputStream is1 = NOREAD.server.getInputStream();
663         final OutputStream os1 = NOREAD.server.getOutputStream();
664         is1.skip(is1.available());
665         os1.write(send1);
666         os1.flush();
667         os1.write("A".getBytes());
668         os1.flush();
669         Thread.sleep(1000);
670         final InputStream instr = NOREAD.client.getInputStream();
671         final byte[] buff = new byte[4];
672 
673         final int retRead = instr.read(buff);
674         if (retRead == 1 && buff[0] == 'A') {
675             readOk = true;
676         }
677 
678         // if (is1.available() == 6)
679         // {
680         int read = 0;
681         int pos = 0;
682 
683         byte[] tmp = new byte[16];
684         while (pos < 5) {
685             read = is1.read(tmp);
686             System.arraycopy(tmp, 0, buffread1, pos, read);
687             pos += read;
688         }
689 
690         if (equalBytes(buffread1, expected1)) {
691             negotiation1Ok = true;
692             // }
693         }
694 
695         final InputStream is2 = STANDARD.server.getInputStream();
696         final OutputStream os2 = STANDARD.server.getOutputStream();
697         Thread.sleep(1000);
698         is2.skip(is2.available());
699         os2.write(send1);
700         os2.flush();
701         Thread.sleep(1000);
702 
703         tmp = new byte[16];
704         while (pos < 5) {
705             read = is2.read(tmp);
706             System.arraycopy(tmp, 0, buffread1, pos, read);
707             pos += read;
708         }
709         // if (is2.available() == 6)
710         // {
711         is2.read(buffread1);
712 
713         if (equalBytes(buffread1, expected1)) {
714             negotiation2Ok = true;
715             // }
716         }
717 
718         assertFalse(NOREAD.client.getReaderThread());
719         assertTrue(STANDARD.client.getReaderThread());
720         assertTrue(readOk, "Expected readOk to be true, got " + readOk);
721         assertTrue(negotiation1Ok, "Expected negotiation1Ok to be true, got " + negotiation1Ok);
722         assertTrue(negotiation2Ok, "Expected negotiation2Ok to be true, got " + negotiation2Ok);
723     }
724 
725     /*
726      * test of Spy functionality
727      */
728     @Test
729     void testSpy() throws Exception {
730         boolean test1spyOk = false;
731         boolean test2spyOk = false;
732         boolean stopspyOk = false;
733         final byte[] expected1 = { (byte) 't', (byte) 'e', (byte) 's', (byte) 't', (byte) '1' };
734         final byte[] expected2 = { (byte) 't', (byte) 'e', (byte) 's', (byte) 't', (byte) '2' };
735 
736         try (PipedOutputStream po = new PipedOutputStream(); final PipedInputStream pi = new PipedInputStream(po)) {
737 
738             final OutputStream os = STANDARD.server.getOutputStream();
739             final OutputStream ostc = STANDARD.client.getOutputStream();
740 
741             STANDARD.client.registerSpyStream(po);
742 
743             os.write("test1".getBytes());
744             os.flush();
745 
746             Thread.sleep(1000);
747             final byte[] buffer = new byte[5];
748 
749             if (pi.available() == 5) {
750                 pi.read(buffer);
751                 if (equalBytes(buffer, expected1)) {
752                     test1spyOk = true;
753                 }
754             }
755 
756             ostc.write("test2".getBytes());
757             ostc.flush();
758 
759             Thread.sleep(1000);
760 
761             if (pi.available() == 5) {
762                 pi.read(buffer);
763                 if (equalBytes(buffer, expected2)) {
764                     test2spyOk = true;
765                 }
766             }
767 
768             STANDARD.client.stopSpyStream();
769             os.write("test1".getBytes());
770             os.flush();
771             ostc.write("test2".getBytes());
772             ostc.flush();
773             Thread.sleep(1000);
774             if (pi.available() == 0) {
775                 stopspyOk = true;
776             }
777 
778             assertTrue(test1spyOk);
779             assertTrue(test2spyOk);
780             assertTrue(stopspyOk);
781         }
782     }
783 
784 }