1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.net.telnet;
19
20 import java.io.BufferedInputStream;
21 import java.io.BufferedOutputStream;
22 import java.io.IOException;
23 import java.io.OutputStream;
24 import java.time.Duration;
25 import java.util.Arrays;
26
27 import org.apache.commons.net.SocketClient;
28
29 class Telnet extends SocketClient {
30 static final boolean debug = false;
31
32 static final boolean debugoptions = false;
33
34 static final byte[] COMMAND_DO = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.DO };
35
36 static final byte[] COMMAND_DONT = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.DONT };
37
38 static final byte[] COMMAND_WILL = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.WILL };
39
40 static final byte[] COMMAND_WONT = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.WONT };
41
42 static final byte[] COMMAND_SB = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.SB };
43
44 static final byte[] COMMAND_SE = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.SE };
45
46 static final int WILL_MASK = 0x01;
47 static final int DO_MASK = 0x02;
48 static final int REQUESTED_WILL_MASK = 0x04;
49 static final int REQUESTED_DO_MASK = 0x08;
50
51
52 static final int DEFAULT_PORT = 23;
53
54
55
56
57
58 protected static final int TERMINAL_TYPE = 24;
59
60
61
62 protected static final int TERMINAL_TYPE_SEND = 1;
63
64
65
66 protected static final int TERMINAL_TYPE_IS = 0;
67
68
69
70
71 static final byte[] COMMAND_IS = { (byte) TERMINAL_TYPE, (byte) TERMINAL_TYPE_IS };
72
73
74
75
76
77 static final byte[] COMMAND_AYT = { (byte) TelnetCommand.IAC, (byte) TelnetCommand.AYT };
78
79 static final char NUL = '\0';
80
81 private final int[] doResponse;
82
83 private final int[] willResponse;
84
85 private final int[] options;
86
87
88
89
90
91
92 private String terminalType;
93
94
95
96
97
98
99 private final TelnetOptionHandler[] optionHandlers;
100
101
102
103
104 private final Object aytMonitor = new Object();
105
106
107
108
109 private volatile boolean aytFlag = true;
110
111
112
113
114
115 private volatile OutputStream spyStream;
116
117
118
119
120 private TelnetNotificationHandler notifhand;
121
122
123
124
125 Telnet() {
126 setDefaultPort(DEFAULT_PORT);
127 doResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1];
128 willResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1];
129 options = new int[TelnetOption.MAX_OPTION_VALUE + 1];
130 optionHandlers = new TelnetOptionHandler[TelnetOption.MAX_OPTION_VALUE + 1];
131 }
132
133
134
135
136
137
138
139 Telnet(final String termtype) {
140 setDefaultPort(DEFAULT_PORT);
141 doResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1];
142 willResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1];
143 options = new int[TelnetOption.MAX_OPTION_VALUE + 1];
144 terminalType = termtype;
145 optionHandlers = new TelnetOptionHandler[TelnetOption.MAX_OPTION_VALUE + 1];
146 }
147
148
149
150
151
152
153
154 @Override
155 protected void _connectAction_() throws IOException {
156
157 for (int ii = 0; ii < TelnetOption.MAX_OPTION_VALUE + 1; ii++) {
158 doResponse[ii] = 0;
159 willResponse[ii] = 0;
160 options[ii] = 0;
161 if (optionHandlers[ii] != null) {
162 optionHandlers[ii].setDo(false);
163 optionHandlers[ii].setWill(false);
164 }
165 }
166
167
168 super._connectAction_();
169 _input_ = new BufferedInputStream(_input_);
170 _output_ = new BufferedOutputStream(_output_);
171
172
173 for (int ii = 0; ii < TelnetOption.MAX_OPTION_VALUE + 1; ii++) {
174 if (optionHandlers[ii] != null) {
175 if (optionHandlers[ii].getInitLocal()) {
176 requestWill(optionHandlers[ii].getOptionCode());
177 }
178
179 if (optionHandlers[ii].getInitRemote()) {
180 requestDo(optionHandlers[ii].getOptionCode());
181 }
182 }
183 }
184
185 }
186
187
188
189
190
191
192
193 void _registerSpyStream(final OutputStream spystream) {
194 spyStream = spystream;
195 }
196
197
198
199
200
201
202
203
204
205
206
207 final boolean _sendAYT(final Duration timeout) throws IOException, IllegalArgumentException, InterruptedException {
208 boolean retValue = false;
209 synchronized (aytMonitor) {
210 synchronized (this) {
211 aytFlag = false;
212 _output_.write(COMMAND_AYT);
213 _output_.flush();
214 }
215 aytMonitor.wait(timeout.toMillis());
216 if (!aytFlag) {
217 aytFlag = true;
218 } else {
219 retValue = true;
220 }
221 }
222
223 return retValue;
224 }
225
226
227
228
229
230
231
232
233
234 final synchronized void _sendCommand(final byte cmd) throws IOException {
235 _output_.write(TelnetCommand.IAC);
236 _output_.write(cmd);
237 _output_.flush();
238 }
239
240
241
242
243
244
245
246
247 final synchronized void _sendSubnegotiation(final int[] subn) throws IOException {
248 if (debug) {
249 System.err.println("SEND SUBNEGOTIATION: ");
250 if (subn != null) {
251 System.err.println(Arrays.toString(subn));
252 }
253 }
254 if (subn != null) {
255 _output_.write(COMMAND_SB);
256
257 for (final int element : subn) {
258 final byte b = (byte) element;
259 if (b == (byte) TelnetCommand.IAC) {
260 _output_.write(b);
261 }
262 _output_.write(b);
263 }
264 _output_.write(COMMAND_SE);
265
266
267 _output_.flush();
268
269 }
270 }
271
272
273
274
275
276 void _stopSpyStream() {
277 spyStream = null;
278 }
279
280
281
282
283
284
285
286
287 void addOptionHandler(final TelnetOptionHandler opthand) throws InvalidTelnetOptionException, IOException {
288 final int optcode = opthand.getOptionCode();
289 if (!TelnetOption.isValidOption(optcode)) {
290 throw new InvalidTelnetOptionException("Invalid Option Code", optcode);
291 }
292 if (optionHandlers[optcode] != null) {
293 throw new InvalidTelnetOptionException("Already registered option", optcode);
294 }
295 optionHandlers[optcode] = opthand;
296 if (isConnected()) {
297 if (opthand.getInitLocal()) {
298 requestWill(optcode);
299 }
300
301 if (opthand.getInitRemote()) {
302 requestDo(optcode);
303 }
304 }
305 }
306
307
308
309
310
311
312
313
314 void deleteOptionHandler(final int optcode) throws InvalidTelnetOptionException, IOException {
315 if (!TelnetOption.isValidOption(optcode)) {
316 throw new InvalidTelnetOptionException("Invalid Option Code", optcode);
317 }
318 if (optionHandlers[optcode] == null) {
319 throw new InvalidTelnetOptionException("Unregistered option", optcode);
320 }
321 final TelnetOptionHandler opthand = optionHandlers[optcode];
322 optionHandlers[optcode] = null;
323
324 if (opthand.getWill()) {
325 requestWont(optcode);
326 }
327
328 if (opthand.getDo()) {
329 requestDont(optcode);
330 }
331 }
332
333
334
335
336
337
338 final synchronized void processAYTResponse() {
339 if (!aytFlag) {
340 synchronized (aytMonitor) {
341 aytFlag = true;
342 aytMonitor.notifyAll();
343 }
344 }
345 }
346
347
348
349
350
351
352
353 void processCommand(final int command) {
354 if (debugoptions) {
355 System.err.println("RECEIVED COMMAND: " + command);
356 }
357
358 if (notifhand != null) {
359 notifhand.receivedNegotiation(TelnetNotificationHandler.RECEIVED_COMMAND, command);
360 }
361 }
362
363
364
365
366
367
368
369 void processDo(final int option) throws IOException {
370 if (debugoptions) {
371 System.err.println("RECEIVED DO: " + TelnetOption.getOption(option));
372 }
373
374 if (notifhand != null) {
375 notifhand.receivedNegotiation(TelnetNotificationHandler.RECEIVED_DO, option);
376 }
377
378 boolean acceptNewState = false;
379
380
381 if (optionHandlers[option] != null) {
382 acceptNewState = optionHandlers[option].getAcceptLocal();
383 } else if (option == TERMINAL_TYPE && terminalType != null && !terminalType.isEmpty()) {
384 acceptNewState = true;
385 }
386
387
388
389 if (willResponse[option] > 0) {
390 --willResponse[option];
391 if (willResponse[option] > 0 && stateIsWill(option)) {
392 --willResponse[option];
393 }
394 }
395
396 if (willResponse[option] == 0) {
397 if (requestedWont(option)) {
398
399 switch (option) {
400
401 default:
402 break;
403
404 }
405
406 if (acceptNewState) {
407 setWantWill(option);
408 sendWill(option);
409 } else {
410 ++willResponse[option];
411 sendWont(option);
412 }
413 } else {
414
415
416 switch (option) {
417
418 default:
419 break;
420
421 }
422
423 }
424 }
425
426 setWill(option);
427 }
428
429
430
431
432
433
434
435 void processDont(final int option) throws IOException {
436 if (debugoptions) {
437 System.err.println("RECEIVED DONT: " + TelnetOption.getOption(option));
438 }
439 if (notifhand != null) {
440 notifhand.receivedNegotiation(TelnetNotificationHandler.RECEIVED_DONT, option);
441 }
442 if (willResponse[option] > 0) {
443 --willResponse[option];
444 if (willResponse[option] > 0 && stateIsWont(option)) {
445 --willResponse[option];
446 }
447 }
448
449 if (willResponse[option] == 0 && requestedWill(option)) {
450
451 switch (option) {
452
453 default:
454 break;
455
456 }
457
458
459 if (stateIsWill(option) || requestedWill(option)) {
460 sendWont(option);
461 }
462
463 setWantWont(option);
464
465 }
466
467 setWont(option);
468 }
469
470
471
472
473
474
475
476
477
478 void processSuboption(final int[] suboption, final int suboptionLength) throws IOException {
479 if (debug) {
480 System.err.println("PROCESS SUBOPTION.");
481 }
482
483
484 if (suboptionLength > 0) {
485 if (optionHandlers[suboption[0]] != null) {
486 final int[] responseSuboption = optionHandlers[suboption[0]].answerSubnegotiation(suboption, suboptionLength);
487 _sendSubnegotiation(responseSuboption);
488 } else if (suboptionLength > 1) {
489 if (debug) {
490 for (int ii = 0; ii < suboptionLength; ii++) {
491 System.err.println("SUB[" + ii + "]: " + suboption[ii]);
492 }
493 }
494 if (suboption[0] == TERMINAL_TYPE && suboption[1] == TERMINAL_TYPE_SEND) {
495 sendTerminalType();
496 }
497 }
498 }
499
500 }
501
502
503
504
505
506
507
508 void processWill(final int option) throws IOException {
509 if (debugoptions) {
510 System.err.println("RECEIVED WILL: " + TelnetOption.getOption(option));
511 }
512
513 if (notifhand != null) {
514 notifhand.receivedNegotiation(TelnetNotificationHandler.RECEIVED_WILL, option);
515 }
516
517 boolean acceptNewState = false;
518
519
520 if (optionHandlers[option] != null) {
521 acceptNewState = optionHandlers[option].getAcceptRemote();
522 }
523
524
525 if (doResponse[option] > 0) {
526 --doResponse[option];
527 if (doResponse[option] > 0 && stateIsDo(option)) {
528 --doResponse[option];
529 }
530 }
531
532 if (doResponse[option] == 0 && requestedDont(option)) {
533
534 switch (option) {
535
536 default:
537 break;
538
539 }
540
541 if (acceptNewState) {
542 setWantDo(option);
543 sendDo(option);
544 } else {
545 ++doResponse[option];
546 sendDont(option);
547 }
548 }
549
550 setDo(option);
551 }
552
553
554
555
556
557
558
559 void processWont(final int option) throws IOException {
560 if (debugoptions) {
561 System.err.println("RECEIVED WONT: " + TelnetOption.getOption(option));
562 }
563
564 if (notifhand != null) {
565 notifhand.receivedNegotiation(TelnetNotificationHandler.RECEIVED_WONT, option);
566 }
567
568 if (doResponse[option] > 0) {
569 --doResponse[option];
570 if (doResponse[option] > 0 && stateIsDont(option)) {
571 --doResponse[option];
572 }
573 }
574
575 if (doResponse[option] == 0 && requestedDo(option)) {
576
577 switch (option) {
578
579 default:
580 break;
581
582 }
583
584
585 if (stateIsDo(option) || requestedDo(option)) {
586 sendDont(option);
587 }
588
589 setWantDont(option);
590
591 }
592
593 setDont(option);
594 }
595
596
597
598
599
600
601 public void registerNotifHandler(final TelnetNotificationHandler notifhand) {
602 this.notifhand = notifhand;
603 }
604
605
606
607
608
609
610
611 final synchronized void requestDo(final int option) throws IOException {
612 if (doResponse[option] == 0 && stateIsDo(option) || requestedDo(option)) {
613 return;
614 }
615 setWantDo(option);
616 ++doResponse[option];
617 sendDo(option);
618 }
619
620
621
622
623
624
625
626 final synchronized void requestDont(final int option) throws IOException {
627 if (doResponse[option] == 0 && stateIsDont(option) || requestedDont(option)) {
628 return;
629 }
630 setWantDont(option);
631 ++doResponse[option];
632 sendDont(option);
633 }
634
635
636
637
638
639
640
641 boolean requestedDo(final int option) {
642 return (options[option] & REQUESTED_DO_MASK) != 0;
643 }
644
645
646
647
648
649
650
651 boolean requestedDont(final int option) {
652 return !requestedDo(option);
653 }
654
655
656
657
658
659
660
661 boolean requestedWill(final int option) {
662 return (options[option] & REQUESTED_WILL_MASK) != 0;
663 }
664
665
666
667
668
669
670
671 boolean requestedWont(final int option) {
672 return !requestedWill(option);
673 }
674
675
676
677
678
679
680
681 final synchronized void requestWill(final int option) throws IOException {
682 if (willResponse[option] == 0 && stateIsWill(option) || requestedWill(option)) {
683 return;
684 }
685 setWantWill(option);
686 ++doResponse[option];
687 sendWill(option);
688 }
689
690
691
692
693
694
695
696
697
698 final synchronized void requestWont(final int option) throws IOException {
699 if (willResponse[option] == 0 && stateIsWont(option) || requestedWont(option)) {
700 return;
701 }
702 setWantWont(option);
703 ++doResponse[option];
704 sendWont(option);
705 }
706
707
708
709
710
711
712
713 final synchronized void sendByte(final int b) throws IOException {
714 _output_.write(b);
715
716
717 spyWrite(b);
718
719
720 }
721
722
723
724
725
726
727
728 final synchronized void sendDo(final int option) throws IOException {
729 if (debug || debugoptions) {
730 System.err.println("DO: " + TelnetOption.getOption(option));
731 }
732 _output_.write(COMMAND_DO);
733 _output_.write(option);
734
735
736 _output_.flush();
737
738 }
739
740
741
742
743
744
745
746 final synchronized void sendDont(final int option) throws IOException {
747 if (debug || debugoptions) {
748 System.err.println("DONT: " + TelnetOption.getOption(option));
749 }
750 _output_.write(COMMAND_DONT);
751 _output_.write(option);
752
753
754 _output_.flush();
755
756 }
757
758
759
760
761
762
763 final synchronized void sendTerminalType() throws IOException {
764 if (debug) {
765 System.err.println("SEND TERMINAL-TYPE: " + terminalType);
766 }
767 if (terminalType != null) {
768 _output_.write(COMMAND_SB);
769 _output_.write(COMMAND_IS);
770 _output_.write(terminalType.getBytes(getCharset()));
771 _output_.write(COMMAND_SE);
772 _output_.flush();
773 }
774 }
775
776
777
778
779
780
781
782 final synchronized void sendWill(final int option) throws IOException {
783 if (debug || debugoptions) {
784 System.err.println("WILL: " + TelnetOption.getOption(option));
785 }
786 _output_.write(COMMAND_WILL);
787 _output_.write(option);
788
789
790 _output_.flush();
791
792 }
793
794
795
796
797
798
799
800 final synchronized void sendWont(final int option) throws IOException {
801 if (debug || debugoptions) {
802 System.err.println("WONT: " + TelnetOption.getOption(option));
803 }
804 _output_.write(COMMAND_WONT);
805 _output_.write(option);
806
807
808 _output_.flush();
809
810 }
811
812
813
814
815
816
817
818 void setDo(final int option) throws IOException {
819 options[option] |= DO_MASK;
820
821
822 if (requestedDo(option) && optionHandlers[option] != null) {
823 optionHandlers[option].setDo(true);
824
825 final int[] subneg = optionHandlers[option].startSubnegotiationRemote();
826
827 if (subneg != null) {
828 _sendSubnegotiation(subneg);
829 }
830 }
831
832 }
833
834
835
836
837
838
839 void setDont(final int option) {
840 options[option] &= ~DO_MASK;
841
842
843 if (optionHandlers[option] != null) {
844 optionHandlers[option].setDo(false);
845 }
846
847 }
848
849
850
851
852
853
854 void setWantDo(final int option) {
855 options[option] |= REQUESTED_DO_MASK;
856 }
857
858
859
860
861
862
863 void setWantDont(final int option) {
864 options[option] &= ~REQUESTED_DO_MASK;
865 }
866
867
868
869
870
871
872 void setWantWill(final int option) {
873 options[option] |= REQUESTED_WILL_MASK;
874 }
875
876
877
878
879
880
881 void setWantWont(final int option) {
882 options[option] &= ~REQUESTED_WILL_MASK;
883 }
884
885
886
887
888
889
890
891 void setWill(final int option) throws IOException {
892 options[option] |= WILL_MASK;
893
894
895 if (requestedWill(option) && optionHandlers[option] != null) {
896 optionHandlers[option].setWill(true);
897
898 final int[] subneg = optionHandlers[option].startSubnegotiationLocal();
899
900 if (subneg != null) {
901 _sendSubnegotiation(subneg);
902 }
903 }
904
905 }
906
907
908
909
910
911
912
913
914 void setWont(final int option) {
915 options[option] &= ~WILL_MASK;
916
917
918 if (optionHandlers[option] != null) {
919 optionHandlers[option].setWill(false);
920 }
921
922 }
923
924
925
926
927
928
929 void spyRead(final int ch) {
930 final OutputStream spy = spyStream;
931 if (spy != null) {
932 try {
933
934 if (ch != '\r') {
935 if (ch == '\n') {
936 spy.write('\r');
937 }
938 spy.write(ch);
939 spy.flush();
940 }
941 } catch (final IOException e) {
942 spyStream = null;
943 }
944 }
945 }
946
947
948
949
950
951
952 void spyWrite(final int ch) {
953 if (!(stateIsDo(TelnetOption.ECHO) && requestedDo(TelnetOption.ECHO))) {
954 final OutputStream spy = spyStream;
955 if (spy != null) {
956 try {
957 spy.write(ch);
958 spy.flush();
959 } catch (final IOException e) {
960 spyStream = null;
961 }
962 }
963 }
964 }
965
966
967
968
969
970
971
972
973 boolean stateIsDo(final int option) {
974 return (options[option] & DO_MASK) != 0;
975 }
976
977
978
979
980
981
982
983 boolean stateIsDont(final int option) {
984 return !stateIsDo(option);
985 }
986
987
988
989
990
991
992
993 boolean stateIsWill(final int option) {
994 return (options[option] & WILL_MASK) != 0;
995 }
996
997
998
999
1000
1001
1002
1003 boolean stateIsWont(final int option) {
1004 return !stateIsWill(option);
1005 }
1006
1007
1008
1009
1010 public void unregisterNotifHandler() {
1011 notifhand = null;
1012 }
1013 }