comparison src/ch/ethz/ssh2/Connection.java @ 308:42b15aaa7ac7 ganymed

merge
author Carl Byington <carl@five-ten-sg.com>
date Wed, 30 Jul 2014 14:21:50 -0700
parents 071eccdff8ea
children cdb3c9215a9b
comparison
equal deleted inserted replaced
306:90e47d99ea54 308:42b15aaa7ac7
56 * <p/> 56 * <p/>
57 * <b>NOTE: As per the RFC, the "softwareversion" string MUST consist of printable 57 * <b>NOTE: As per the RFC, the "softwareversion" string MUST consist of printable
58 * US-ASCII characters, with the exception of whitespace characters and the minus sign (-).</b> 58 * US-ASCII characters, with the exception of whitespace characters and the minus sign (-).</b>
59 */ 59 */
60 private String softwareversion 60 private String softwareversion
61 = String.format("Ganymed_%s", Version.getSpecification()); 61 = String.format("Ganymed_%s", Version.getSpecification());
62 62
63 /* Will be used to generate all random data needed for the current connection. 63 /* Will be used to generate all random data needed for the current connection.
64 * Note: SecureRandom.nextBytes() is thread safe. 64 * Note: SecureRandom.nextBytes() is thread safe.
65 */ 65 */
66 66
67 private SecureRandom generator; 67 private SecureRandom generator;
68 68
69 /** 69 /**
70 * Unless you know what you are doing, you will never need this. 70 * Unless you know what you are doing, you will never need this.
71 * 71 *
72 * @return The list of supported cipher algorithms by this implementation. 72 * @return The list of supported cipher algorithms by this implementation.
73 */ 73 */
74
74 public static synchronized String[] getAvailableCiphers() { 75 public static synchronized String[] getAvailableCiphers() {
75 return BlockCipherFactory.getDefaultCipherList(); 76 return BlockCipherFactory.getDefaultCipherList();
76 } 77 }
77 78
78 /** 79 /**
79 * Unless you know what you are doing, you will never need this. 80 * Unless you know what you are doing, you will never need this.
80 * 81 *
81 * @return The list of supported MAC algorthims by this implementation. 82 * @return The list of supported MAC algorthims by this implementation.
82 */ 83 */
84
83 public static synchronized String[] getAvailableMACs() { 85 public static synchronized String[] getAvailableMACs() {
84 return MAC.getMacList(); 86 return MAC.getMacList();
85 } 87 }
86 88
87 /** 89 /**
88 * Unless you know what you are doing, you will never need this. 90 * Unless you know what you are doing, you will never need this.
89 * 91 *
90 * @return The list of supported server host key algorthims by this implementation. 92 * @return The list of supported server host key algorthims by this implementation.
91 */ 93 */
94
92 public static synchronized String[] getAvailableServerHostKeyAlgorithms() { 95 public static synchronized String[] getAvailableServerHostKeyAlgorithms() {
93 return KexManager.getDefaultServerHostkeyAlgorithmList(); 96 return KexManager.getDefaultServerHostkeyAlgorithmList();
94 } 97 }
95 98
96 private AuthenticationManager am; 99 private AuthenticationManager am;
97 100
98 private boolean authenticated; 101 private boolean authenticated;
99 private ChannelManager cm; 102 private ChannelManager cm;
100 103
101 private CryptoWishList cryptoWishList 104 private CryptoWishList cryptoWishList
102 = new CryptoWishList(); 105 = new CryptoWishList();
103 106
104 private DHGexParameters dhgexpara 107 private DHGexParameters dhgexpara
105 = new DHGexParameters(); 108 = new DHGexParameters();
106 109
107 private final String hostname; 110 private final String hostname;
108 111
109 private final int port; 112 private final int port;
110 113
113 private boolean tcpNoDelay = false; 116 private boolean tcpNoDelay = false;
114 117
115 private HTTPProxyData proxy; 118 private HTTPProxyData proxy;
116 119
117 private List<ConnectionMonitor> connectionMonitors 120 private List<ConnectionMonitor> connectionMonitors
118 = new ArrayList<ConnectionMonitor>(); 121 = new ArrayList<ConnectionMonitor>();
119 122
120 /** 123 /**
121 * Prepares a fresh <code>Connection</code> object which can then be used 124 * Prepares a fresh <code>Connection</code> object which can then be used
122 * to establish a connection to the specified SSH-2 server. 125 * to establish a connection to the specified SSH-2 server.
123 * <p/> 126 * <p/>
194 * @deprecated You should use one of the {@link #authenticateWithPublicKey(String, File, String) authenticateWithPublicKey()} 197 * @deprecated You should use one of the {@link #authenticateWithPublicKey(String, File, String) authenticateWithPublicKey()}
195 * methods, this method is just a wrapper for it and will 198 * methods, this method is just a wrapper for it and will
196 * disappear in future builds. 199 * disappear in future builds.
197 */ 200 */
198 @Deprecated 201 @Deprecated
199 public synchronized boolean authenticateWithDSA(String user, String pem, String password) throws IOException { 202
200 if(tm == null) { 203 public synchronized boolean authenticateWithDSA(String user, String pem, String password) throws IOException {
204 if (tm == null) {
201 throw new IllegalStateException("Connection is not established!"); 205 throw new IllegalStateException("Connection is not established!");
202 } 206 }
203 207
204 if(authenticated) { 208 if (authenticated) {
205 throw new IllegalStateException("Connection is already authenticated!"); 209 throw new IllegalStateException("Connection is already authenticated!");
206 } 210 }
207 211
208 if(am == null) { 212 if (am == null) {
209 am = new AuthenticationManager(tm); 213 am = new AuthenticationManager(tm);
210 } 214 }
211 215
212 if(cm == null) { 216 if (cm == null) {
213 cm = new ChannelManager(tm); 217 cm = new ChannelManager(tm);
214 } 218 }
215 219
216 if(user == null) { 220 if (user == null) {
217 throw new IllegalArgumentException("user argument is null"); 221 throw new IllegalArgumentException("user argument is null");
218 } 222 }
219 223
220 if(pem == null) { 224 if (pem == null) {
221 throw new IllegalArgumentException("pem argument is null"); 225 throw new IllegalArgumentException("pem argument is null");
222 } 226 }
223 227
224 authenticated = am.authenticatePublicKey(user, pem.toCharArray(), password, getOrCreateSecureRND()); 228 authenticated = am.authenticatePublicKey(user, pem.toCharArray(), password, getOrCreateSecureRND());
225
226 return authenticated; 229 return authenticated;
227 } 230 }
228 231
229 /** 232 /**
230 * A wrapper that calls {@link #authenticateWithKeyboardInteractive(String, String[], InteractiveCallback) 233 * A wrapper that calls {@link #authenticateWithKeyboardInteractive(String, String[], InteractiveCallback)
234 * @param cb An <code>InteractiveCallback</code> which will be used to 237 * @param cb An <code>InteractiveCallback</code> which will be used to
235 * determine the responses to the questions asked by the server. 238 * determine the responses to the questions asked by the server.
236 * @return whether the connection is now authenticated. 239 * @return whether the connection is now authenticated.
237 * @throws IOException 240 * @throws IOException
238 */ 241 */
242
239 public synchronized boolean authenticateWithKeyboardInteractive(String user, InteractiveCallback cb) 243 public synchronized boolean authenticateWithKeyboardInteractive(String user, InteractiveCallback cb)
240 throws IOException { 244 throws IOException {
241 return authenticateWithKeyboardInteractive(user, null, cb); 245 return authenticateWithKeyboardInteractive(user, null, cb);
242 } 246 }
243 247
244 /** 248 /**
245 * After a successful connect, one has to authenticate oneself. This method 249 * After a successful connect, one has to authenticate oneself. This method
269 * @param cb An <code>InteractiveCallback</code> which will be used to 273 * @param cb An <code>InteractiveCallback</code> which will be used to
270 * determine the responses to the questions asked by the server. 274 * determine the responses to the questions asked by the server.
271 * @return whether the connection is now authenticated. 275 * @return whether the connection is now authenticated.
272 * @throws IOException 276 * @throws IOException
273 */ 277 */
278
274 public synchronized boolean authenticateWithKeyboardInteractive(String user, String[] submethods, 279 public synchronized boolean authenticateWithKeyboardInteractive(String user, String[] submethods,
275 InteractiveCallback cb) throws IOException { 280 InteractiveCallback cb) throws IOException {
276 if(cb == null) { 281 if (cb == null) {
277 throw new IllegalArgumentException("Callback may not ne NULL!"); 282 throw new IllegalArgumentException("Callback may not ne NULL!");
278 } 283 }
279 284
280 if(tm == null) { 285 if (tm == null) {
281 throw new IllegalStateException("Connection is not established!"); 286 throw new IllegalStateException("Connection is not established!");
282 } 287 }
283 288
284 if(authenticated) { 289 if (authenticated) {
285 throw new IllegalStateException("Connection is already authenticated!"); 290 throw new IllegalStateException("Connection is already authenticated!");
286 } 291 }
287 292
288 if(am == null) { 293 if (am == null) {
289 am = new AuthenticationManager(tm); 294 am = new AuthenticationManager(tm);
290 } 295 }
291 296
292 if(cm == null) { 297 if (cm == null) {
293 cm = new ChannelManager(tm); 298 cm = new ChannelManager(tm);
294 } 299 }
295 300
296 if(user == null) { 301 if (user == null) {
297 throw new IllegalArgumentException("user argument is null"); 302 throw new IllegalArgumentException("user argument is null");
298 } 303 }
299 304
300 authenticated = am.authenticateInteractive(user, submethods, cb); 305 authenticated = am.authenticateInteractive(user, submethods, cb);
301
302 return authenticated; 306 return authenticated;
303 } 307 }
304 308
305 public synchronized boolean authenticateWithAgent(String user, AgentProxy proxy) throws IOException { 309 public synchronized boolean authenticateWithAgent(String user, AgentProxy proxy) throws IOException {
306 if(tm == null) { 310 if (tm == null) {
307 throw new IllegalStateException("Connection is not established!"); 311 throw new IllegalStateException("Connection is not established!");
308 } 312 }
309 313
310 if(authenticated) { 314 if (authenticated) {
311 throw new IllegalStateException("Connection is already authenticated!"); 315 throw new IllegalStateException("Connection is already authenticated!");
312 } 316 }
313 317
314 if(am == null) { 318 if (am == null) {
315 am = new AuthenticationManager(tm); 319 am = new AuthenticationManager(tm);
316 } 320 }
317 321
318 if(cm == null) { 322 if (cm == null) {
319 cm = new ChannelManager(tm); 323 cm = new ChannelManager(tm);
320 } 324 }
321 325
322 if(user == null) { 326 if (user == null) {
323 throw new IllegalArgumentException("user argument is null"); 327 throw new IllegalArgumentException("user argument is null");
324 } 328 }
325 329
326 authenticated = am.authenticatePublicKey(user, proxy); 330 authenticated = am.authenticatePublicKey(user, proxy);
327
328 return authenticated; 331 return authenticated;
329 } 332 }
330 333
331 /** 334 /**
332 * After a successful connect, one has to authenticate oneself. This method 335 * After a successful connect, one has to authenticate oneself. This method
350 * @param user 353 * @param user
351 * @param password 354 * @param password
352 * @return if the connection is now authenticated. 355 * @return if the connection is now authenticated.
353 * @throws IOException 356 * @throws IOException
354 */ 357 */
358
355 public synchronized boolean authenticateWithPassword(String user, String password) throws IOException { 359 public synchronized boolean authenticateWithPassword(String user, String password) throws IOException {
356 if(tm == null) { 360 if (tm == null) {
357 throw new IllegalStateException("Connection is not established!"); 361 throw new IllegalStateException("Connection is not established!");
358 } 362 }
359 363
360 if(authenticated) { 364 if (authenticated) {
361 throw new IllegalStateException("Connection is already authenticated!"); 365 throw new IllegalStateException("Connection is already authenticated!");
362 } 366 }
363 367
364 if(am == null) { 368 if (am == null) {
365 am = new AuthenticationManager(tm); 369 am = new AuthenticationManager(tm);
366 } 370 }
367 371
368 if(cm == null) { 372 if (cm == null) {
369 cm = new ChannelManager(tm); 373 cm = new ChannelManager(tm);
370 } 374 }
371 375
372 if(user == null) { 376 if (user == null) {
373 throw new IllegalArgumentException("user argument is null"); 377 throw new IllegalArgumentException("user argument is null");
374 } 378 }
375 379
376 if(password == null) { 380 if (password == null) {
377 throw new IllegalArgumentException("password argument is null"); 381 throw new IllegalArgumentException("password argument is null");
378 } 382 }
379 383
380 authenticated = am.authenticatePassword(user, password); 384 authenticated = am.authenticatePassword(user, password);
381
382 return authenticated; 385 return authenticated;
383 } 386 }
384 387
385 /** 388 /**
386 * After a successful connect, one has to authenticate oneself. 389 * After a successful connect, one has to authenticate oneself.
406 * 409 *
407 * @param user 410 * @param user
408 * @return if the connection is now authenticated. 411 * @return if the connection is now authenticated.
409 * @throws IOException 412 * @throws IOException
410 */ 413 */
414
411 public synchronized boolean authenticateWithNone(String user) throws IOException { 415 public synchronized boolean authenticateWithNone(String user) throws IOException {
412 if(tm == null) { 416 if (tm == null) {
413 throw new IllegalStateException("Connection is not established!"); 417 throw new IllegalStateException("Connection is not established!");
414 } 418 }
415 419
416 if(authenticated) { 420 if (authenticated) {
417 throw new IllegalStateException("Connection is already authenticated!"); 421 throw new IllegalStateException("Connection is already authenticated!");
418 } 422 }
419 423
420 if(am == null) { 424 if (am == null) {
421 am = new AuthenticationManager(tm); 425 am = new AuthenticationManager(tm);
422 } 426 }
423 427
424 if(cm == null) { 428 if (cm == null) {
425 cm = new ChannelManager(tm); 429 cm = new ChannelManager(tm);
426 } 430 }
427 431
428 if(user == null) { 432 if (user == null) {
429 throw new IllegalArgumentException("user argument is null"); 433 throw new IllegalArgumentException("user argument is null");
430 } 434 }
431 435
432 /* Trigger the sending of the PacketUserauthRequestNone packet */ 436 /* Trigger the sending of the PacketUserauthRequestNone packet */
433 /* (if not already done) */ 437 /* (if not already done) */
434
435 authenticated = am.authenticateNone(user); 438 authenticated = am.authenticateNone(user);
436
437 return authenticated; 439 return authenticated;
438 } 440 }
439 441
440 /** 442 /**
441 * After a successful connect, one has to authenticate oneself. 443 * After a successful connect, one has to authenticate oneself.
473 * you must specify a password. Otherwise, this argument will be ignored 475 * you must specify a password. Otherwise, this argument will be ignored
474 * and can be set to <code>null</code>. 476 * and can be set to <code>null</code>.
475 * @return whether the connection is now authenticated. 477 * @return whether the connection is now authenticated.
476 * @throws IOException 478 * @throws IOException
477 */ 479 */
480
478 public synchronized boolean authenticateWithPublicKey(String user, char[] pemPrivateKey, String password) 481 public synchronized boolean authenticateWithPublicKey(String user, char[] pemPrivateKey, String password)
479 throws IOException { 482 throws IOException {
480 if(tm == null) { 483 if (tm == null) {
481 throw new IllegalStateException("Connection is not established!"); 484 throw new IllegalStateException("Connection is not established!");
482 } 485 }
483 486
484 if(authenticated) { 487 if (authenticated) {
485 throw new IllegalStateException("Connection is already authenticated!"); 488 throw new IllegalStateException("Connection is already authenticated!");
486 } 489 }
487 490
488 if(am == null) { 491 if (am == null) {
489 am = new AuthenticationManager(tm); 492 am = new AuthenticationManager(tm);
490 } 493 }
491 494
492 if(cm == null) { 495 if (cm == null) {
493 cm = new ChannelManager(tm); 496 cm = new ChannelManager(tm);
494 } 497 }
495 498
496 if(user == null) { 499 if (user == null) {
497 throw new IllegalArgumentException("user argument is null"); 500 throw new IllegalArgumentException("user argument is null");
498 } 501 }
499 502
500 if(pemPrivateKey == null) { 503 if (pemPrivateKey == null) {
501 throw new IllegalArgumentException("pemPrivateKey argument is null"); 504 throw new IllegalArgumentException("pemPrivateKey argument is null");
502 } 505 }
503 506
504 authenticated = am.authenticatePublicKey(user, pemPrivateKey, password, getOrCreateSecureRND()); 507 authenticated = am.authenticatePublicKey(user, pemPrivateKey, password, getOrCreateSecureRND());
505
506 return authenticated; 508 return authenticated;
507 } 509 }
508 510
509 /** 511 /**
510 * After a successful connect, one has to authenticate oneself. The 512 * After a successful connect, one has to authenticate oneself. The
576 * @param password If the PEM file is encrypted then you must specify the password. 578 * @param password If the PEM file is encrypted then you must specify the password.
577 * Otherwise, this argument will be ignored and can be set to <code>null</code>. 579 * Otherwise, this argument will be ignored and can be set to <code>null</code>.
578 * @return whether the connection is now authenticated. 580 * @return whether the connection is now authenticated.
579 * @throws IOException 581 * @throws IOException
580 */ 582 */
583
581 public synchronized boolean authenticateWithPublicKey(String user, File pemFile, String password) 584 public synchronized boolean authenticateWithPublicKey(String user, File pemFile, String password)
582 throws IOException { 585 throws IOException {
583 if(pemFile == null) { 586 if (pemFile == null) {
584 throw new IllegalArgumentException("pemFile argument is null"); 587 throw new IllegalArgumentException("pemFile argument is null");
585 } 588 }
586 589
587 char[] buff = new char[256]; 590 char[] buff = new char[256];
588
589 CharArrayWriter cw = new CharArrayWriter(); 591 CharArrayWriter cw = new CharArrayWriter();
590
591 FileReader fr = new FileReader(pemFile); 592 FileReader fr = new FileReader(pemFile);
592 593
593 while(true) { 594 while (true) {
594 int len = fr.read(buff); 595 int len = fr.read(buff);
595 if(len < 0) { 596
597 if (len < 0) {
596 break; 598 break;
597 } 599 }
600
598 cw.write(buff, 0, len); 601 cw.write(buff, 0, len);
599 } 602 }
600 603
601 fr.close(); 604 fr.close();
602
603 return authenticateWithPublicKey(user, cw.toCharArray(), password); 605 return authenticateWithPublicKey(user, cw.toCharArray(), password);
604 } 606 }
605 607
606 /** 608 /**
607 * Add a {@link ConnectionMonitor} to this connection. Can be invoked at any time, 609 * Add a {@link ConnectionMonitor} to this connection. Can be invoked at any time,
614 * this method does nothing. 616 * this method does nothing.
615 * 617 *
616 * @param cmon An object implementing the {@link ConnectionMonitor} interface. 618 * @param cmon An object implementing the {@link ConnectionMonitor} interface.
617 * @see ConnectionMonitor 619 * @see ConnectionMonitor
618 */ 620 */
621
619 public synchronized void addConnectionMonitor(ConnectionMonitor cmon) { 622 public synchronized void addConnectionMonitor(ConnectionMonitor cmon) {
620 if(!connectionMonitors.contains(cmon)) { 623 if (!connectionMonitors.contains(cmon)) {
621 connectionMonitors.add(cmon); 624 connectionMonitors.add(cmon);
622 if(tm != null) { 625
626 if (tm != null) {
623 tm.setConnectionMonitors(connectionMonitors); 627 tm.setConnectionMonitors(connectionMonitors);
624 } 628 }
625 } 629 }
626 } 630 }
627 631
629 * Remove a {@link ConnectionMonitor} from this connection. 633 * Remove a {@link ConnectionMonitor} from this connection.
630 * 634 *
631 * @param cmon 635 * @param cmon
632 * @return whether the monitor could be removed 636 * @return whether the monitor could be removed
633 */ 637 */
638
634 public synchronized boolean removeConnectionMonitor(ConnectionMonitor cmon) { 639 public synchronized boolean removeConnectionMonitor(ConnectionMonitor cmon) {
635 boolean existed = connectionMonitors.remove(cmon); 640 boolean existed = connectionMonitors.remove(cmon);
636 if(tm != null) { 641
642 if (tm != null) {
637 tm.setConnectionMonitors(connectionMonitors); 643 tm.setConnectionMonitors(connectionMonitors);
638 } 644 }
645
639 return existed; 646 return existed;
640 } 647 }
641 648
642 /** 649 /**
643 * Controls whether compression is used on the link or not. 650 * Controls whether compression is used on the link or not.
659 * Close the connection to the SSH-2 server. All assigned sessions will be 666 * Close the connection to the SSH-2 server. All assigned sessions will be
660 * closed, too. Can be called at any time. Don't forget to call this once 667 * closed, too. Can be called at any time. Don't forget to call this once
661 * you don't need a connection anymore - otherwise the receiver thread may 668 * you don't need a connection anymore - otherwise the receiver thread may
662 * run forever. 669 * run forever.
663 */ 670 */
671
664 public synchronized void close() { 672 public synchronized void close() {
665 if(cm != null) { 673 if (cm != null) {
666 cm.closeAllChannels(); 674 cm.closeAllChannels();
667 } 675 }
668 if(tm != null) { 676
677 if (tm != null) {
669 tm.close(); 678 tm.close();
670 tm = null; 679 tm = null;
671 } 680 }
681
672 am = null; 682 am = null;
673 cm = null; 683 cm = null;
674 authenticated = false; 684 authenticated = false;
675 } 685 }
676 686
677 public synchronized void close(IOException t) { 687 public synchronized void close(IOException t) {
678 if(cm != null) { 688 if (cm != null) {
679 cm.closeAllChannels(); 689 cm.closeAllChannels();
680 } 690 }
681 if(tm != null) { 691
692 if (tm != null) {
682 tm.close(t); 693 tm.close(t);
683 tm = null; 694 tm = null;
684 } 695 }
696
685 am = null; 697 am = null;
686 cm = null; 698 cm = null;
687 authenticated = false; 699 authenticated = false;
688 } 700 }
689 701
691 * Same as {@link #connect(ServerHostKeyVerifier, int, int) connect(null, 0, 0)}. 703 * Same as {@link #connect(ServerHostKeyVerifier, int, int) connect(null, 0, 0)}.
692 * 704 *
693 * @return see comments for the {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} method. 705 * @return see comments for the {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} method.
694 * @throws IOException 706 * @throws IOException
695 */ 707 */
708
696 public synchronized ConnectionInfo connect() throws IOException { 709 public synchronized ConnectionInfo connect() throws IOException {
697 return connect(null, 0, 0); 710 return connect(null, 0, 0);
698 } 711 }
699 712
700 /** 713 /**
701 * Same as {@link #connect(ServerHostKeyVerifier, int, int) connect(verifier, 0, 0)}. 714 * Same as {@link #connect(ServerHostKeyVerifier, int, int) connect(verifier, 0, 0)}.
702 * 715 *
703 * @return see comments for the {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} method. 716 * @return see comments for the {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} method.
704 * @throws IOException 717 * @throws IOException
705 */ 718 */
719
706 public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier) throws IOException { 720 public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier) throws IOException {
707 return connect(verifier, 0, 0); 721 return connect(verifier, 0, 0);
708 } 722 }
709 723
710 /** 724 /**
766 * If a HTTP proxy is being used and the proxy refuses the connection, 780 * If a HTTP proxy is being used and the proxy refuses the connection,
767 * then a {@link HTTPProxyException} may be thrown, which 781 * then a {@link HTTPProxyException} may be thrown, which
768 * contains the details returned by the proxy. If the proxy is buggy and does 782 * contains the details returned by the proxy. If the proxy is buggy and does
769 * not return a proper HTTP response, then a normal IOException is thrown instead. 783 * not return a proper HTTP response, then a normal IOException is thrown instead.
770 */ 784 */
785
771 public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier, int connectTimeout, int kexTimeout) 786 public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier, int connectTimeout, int kexTimeout)
772 throws IOException { 787 throws IOException {
773 final class TimeoutState { 788 final class TimeoutState {
774 boolean isCancelled = false; 789 boolean isCancelled = false;
775 boolean timeoutSocketClosed = false; 790 boolean timeoutSocketClosed = false;
776 } 791 }
777 792
778 if(tm != null) { 793 if (tm != null) {
779 throw new IllegalStateException(String.format("Connection to %s is already in connected state", hostname)); 794 throw new IllegalStateException(String.format("Connection to %s is already in connected state", hostname));
780 } 795 }
781 796
782 if(connectTimeout < 0) { 797 if (connectTimeout < 0) {
783 throw new IllegalArgumentException("connectTimeout must be non-negative!"); 798 throw new IllegalArgumentException("connectTimeout must be non-negative!");
784 } 799 }
785 800
786 if(kexTimeout < 0) { 801 if (kexTimeout < 0) {
787 throw new IllegalArgumentException("kexTimeout must be non-negative!"); 802 throw new IllegalArgumentException("kexTimeout must be non-negative!");
788 } 803 }
789 804
790 final TimeoutState state = new TimeoutState(); 805 final TimeoutState state = new TimeoutState();
791 806
792 if(null == proxy) { 807 if (null == proxy) {
793 tm = new ClientTransportManager(new Socket()); 808 tm = new ClientTransportManager(new Socket());
794 } 809 }
795 else { 810 else {
796 tm = new HTTPProxyClientTransportManager(new Socket(), proxy); 811 tm = new HTTPProxyClientTransportManager(new Socket(), proxy);
797 } 812 }
813
798 tm.setSoTimeout(connectTimeout); 814 tm.setSoTimeout(connectTimeout);
799 tm.setTcpNoDelay(tcpNoDelay); 815 tm.setTcpNoDelay(tcpNoDelay);
800 tm.setConnectionMonitors(connectionMonitors); 816 tm.setConnectionMonitors(connectionMonitors);
801 817
802 try { 818 try {
803 TimeoutToken token = null; 819 TimeoutToken token = null;
804 820
805 if(kexTimeout > 0) { 821 if (kexTimeout > 0) {
806 final Runnable timeoutHandler = new Runnable() { 822 final Runnable timeoutHandler = new Runnable() {
807 public void run() { 823 public void run() {
808 synchronized(state) { 824 synchronized (state) {
809 if(state.isCancelled) { 825 if (state.isCancelled) {
810 return; 826 return;
811 } 827 }
828
812 state.timeoutSocketClosed = true; 829 state.timeoutSocketClosed = true;
813 tm.close(new SocketTimeoutException("The connect timeout expired")); 830 tm.close(new SocketTimeoutException("The connect timeout expired"));
814 } 831 }
815 } 832 }
816 }; 833 };
817
818 long timeoutHorizont = System.currentTimeMillis() + kexTimeout; 834 long timeoutHorizont = System.currentTimeMillis() + kexTimeout;
819
820 token = TimeoutService.addTimeoutHandler(timeoutHorizont, timeoutHandler); 835 token = TimeoutService.addTimeoutHandler(timeoutHorizont, timeoutHandler);
821 } 836 }
822 837
823 tm.connect(hostname, port, softwareversion, cryptoWishList, verifier, dhgexpara, connectTimeout, 838 tm.connect(hostname, port, softwareversion, cryptoWishList, verifier, dhgexpara, connectTimeout,
824 getOrCreateSecureRND()); 839 getOrCreateSecureRND());
825 840 /* Wait until first KEX has finished */
826 /* Wait until first KEX has finished */
827
828 ConnectionInfo ci = tm.getConnectionInfo(1); 841 ConnectionInfo ci = tm.getConnectionInfo(1);
829 842
830 /* Now try to cancel the timeout, if needed */ 843 /* Now try to cancel the timeout, if needed */
831 844
832 if(token != null) { 845 if (token != null) {
833 TimeoutService.cancelTimeoutHandler(token); 846 TimeoutService.cancelTimeoutHandler(token);
834 847
835 /* Were we too late? */ 848 /* Were we too late? */
836 849
837 synchronized(state) { 850 synchronized (state) {
838 if(state.timeoutSocketClosed) { 851 if (state.timeoutSocketClosed) {
839 throw new IOException("This exception will be replaced by the one below =)"); 852 throw new IOException("This exception will be replaced by the one below =)");
840 } 853 }
854
841 /* Just in case the "cancelTimeoutHandler" invocation came just a little bit 855 /* Just in case the "cancelTimeoutHandler" invocation came just a little bit
842 * too late but the handler did not enter the semaphore yet - we can 856 * too late but the handler did not enter the semaphore yet - we can
843 * still stop it. 857 * still stop it.
844 */ 858 */
845 state.isCancelled = true; 859 state.isCancelled = true;
846 } 860 }
847 } 861 }
848 862
849 return ci; 863 return ci;
850 } 864 }
851 catch(SocketTimeoutException e) { 865 catch (SocketTimeoutException e) {
852 throw e; 866 throw e;
853 } 867 }
854 catch(HTTPProxyException e) { 868 catch (HTTPProxyException e) {
855 throw e; 869 throw e;
856 } 870 }
857 catch(IOException e) { 871 catch (IOException e) {
858 // This will also invoke any registered connection monitors 872 // This will also invoke any registered connection monitors
859 close(e); 873 close(e);
860 874
861 synchronized(state) { 875 synchronized (state) {
862 /* Show a clean exception, not something like "the socket is closed!?!" */ 876 /* Show a clean exception, not something like "the socket is closed!?!" */
863 if(state.timeoutSocketClosed) { 877 if (state.timeoutSocketClosed) {
864 throw new SocketTimeoutException(String.format("The kexTimeout (%d ms) expired.", kexTimeout)); 878 throw new SocketTimeoutException(String.format("The kexTimeout (%d ms) expired.", kexTimeout));
865 } 879 }
866 } 880 }
881
867 throw e; 882 throw e;
868 } 883 }
869 } 884 }
870 885
871 /** 886 /**
881 * @param host_to_connect target address (IP or hostname) 896 * @param host_to_connect target address (IP or hostname)
882 * @param port_to_connect target port 897 * @param port_to_connect target port
883 * @return A {@link LocalPortForwarder} object. 898 * @return A {@link LocalPortForwarder} object.
884 * @throws IOException 899 * @throws IOException
885 */ 900 */
901
886 public synchronized LocalPortForwarder createLocalPortForwarder(int local_port, String host_to_connect, 902 public synchronized LocalPortForwarder createLocalPortForwarder(int local_port, String host_to_connect,
887 int port_to_connect) throws IOException { 903 int port_to_connect) throws IOException {
888 this.checkConnection(); 904 this.checkConnection();
889
890 return new LocalPortForwarder(cm, local_port, host_to_connect, port_to_connect); 905 return new LocalPortForwarder(cm, local_port, host_to_connect, port_to_connect);
891 } 906 }
892 907
893 /** 908 /**
894 * Creates a new {@link LocalPortForwarder}. 909 * Creates a new {@link LocalPortForwarder}.
903 * @param host_to_connect target address (IP or hostname) 918 * @param host_to_connect target address (IP or hostname)
904 * @param port_to_connect target port 919 * @param port_to_connect target port
905 * @return A {@link LocalPortForwarder} object. 920 * @return A {@link LocalPortForwarder} object.
906 * @throws IOException 921 * @throws IOException
907 */ 922 */
923
908 public synchronized LocalPortForwarder createLocalPortForwarder(InetSocketAddress addr, String host_to_connect, 924 public synchronized LocalPortForwarder createLocalPortForwarder(InetSocketAddress addr, String host_to_connect,
909 int port_to_connect) throws IOException { 925 int port_to_connect) throws IOException {
910 this.checkConnection(); 926 this.checkConnection();
911
912 return new LocalPortForwarder(cm, addr, host_to_connect, port_to_connect); 927 return new LocalPortForwarder(cm, addr, host_to_connect, port_to_connect);
913 } 928 }
914 929
915 /** 930 /**
916 * Creates a new {@link LocalStreamForwarder}. 931 * Creates a new {@link LocalStreamForwarder}.
921 * @param host_to_connect 936 * @param host_to_connect
922 * @param port_to_connect 937 * @param port_to_connect
923 * @return A {@link LocalStreamForwarder} object. 938 * @return A {@link LocalStreamForwarder} object.
924 * @throws IOException 939 * @throws IOException
925 */ 940 */
941
926 public synchronized LocalStreamForwarder createLocalStreamForwarder(String host_to_connect, int port_to_connect) 942 public synchronized LocalStreamForwarder createLocalStreamForwarder(String host_to_connect, int port_to_connect)
927 throws IOException { 943 throws IOException {
928 this.checkConnection(); 944 this.checkConnection();
929
930 return new LocalStreamForwarder(cm, host_to_connect, port_to_connect); 945 return new LocalStreamForwarder(cm, host_to_connect, port_to_connect);
931 } 946 }
932 947
933 /** 948 /**
934 * Creates a new {@link DynamicPortForwarder}. A 949 * Creates a new {@link DynamicPortForwarder}. A
992 * Note: This factory method will probably disappear in the future. 1007 * Note: This factory method will probably disappear in the future.
993 * 1008 *
994 * @return A {@link SCPClient} object. 1009 * @return A {@link SCPClient} object.
995 * @throws IOException 1010 * @throws IOException
996 */ 1011 */
1012
997 public synchronized SCPClient createSCPClient() throws IOException { 1013 public synchronized SCPClient createSCPClient() throws IOException {
998 this.checkConnection(); 1014 this.checkConnection();
999
1000 return new SCPClient(this); 1015 return new SCPClient(this);
1001 } 1016 }
1002 1017
1003 /** 1018 /**
1004 * Force an asynchronous key re-exchange (the call does not block). The 1019 * Force an asynchronous key re-exchange (the call does not block). The
1010 * Note: This implementation will never start a key exchange (other than the initial one) 1025 * Note: This implementation will never start a key exchange (other than the initial one)
1011 * unless you or the SSH-2 server ask for it. 1026 * unless you or the SSH-2 server ask for it.
1012 * 1027 *
1013 * @throws IOException In case of any failure behind the scenes. 1028 * @throws IOException In case of any failure behind the scenes.
1014 */ 1029 */
1030
1015 public synchronized void forceKeyExchange() throws IOException { 1031 public synchronized void forceKeyExchange() throws IOException {
1016 this.checkConnection(); 1032 this.checkConnection();
1017
1018 tm.forceKeyExchange(cryptoWishList, dhgexpara, null, null, null); 1033 tm.forceKeyExchange(cryptoWishList, dhgexpara, null, null, null);
1019 } 1034 }
1020 1035
1021 /** 1036 /**
1022 * Returns the hostname that was passed to the constructor. 1037 * Returns the hostname that was passed to the constructor.
1023 * 1038 *
1024 * @return the hostname 1039 * @return the hostname
1025 */ 1040 */
1041
1026 public synchronized String getHostname() { 1042 public synchronized String getHostname() {
1027 return hostname; 1043 return hostname;
1028 } 1044 }
1029 1045
1030 /** 1046 /**
1031 * Returns the port that was passed to the constructor. 1047 * Returns the port that was passed to the constructor.
1032 * 1048 *
1033 * @return the TCP port 1049 * @return the TCP port
1034 */ 1050 */
1051
1035 public synchronized int getPort() { 1052 public synchronized int getPort() {
1036 return port; 1053 return port;
1037 } 1054 }
1038 1055
1039 /** 1056 /**
1042 * established (successfully connected). 1059 * established (successfully connected).
1043 * 1060 *
1044 * @return A {@link ConnectionInfo} object. 1061 * @return A {@link ConnectionInfo} object.
1045 * @throws IOException In case of any failure behind the scenes. 1062 * @throws IOException In case of any failure behind the scenes.
1046 */ 1063 */
1064
1047 public synchronized ConnectionInfo getConnectionInfo() throws IOException { 1065 public synchronized ConnectionInfo getConnectionInfo() throws IOException {
1048 this.checkConnection(); 1066 this.checkConnection();
1049
1050 return tm.getConnectionInfo(1); 1067 return tm.getConnectionInfo(1);
1051 } 1068 }
1052 1069
1053 /** 1070 /**
1054 * After a successful connect, one has to authenticate oneself. This method 1071 * After a successful connect, one has to authenticate oneself. This method
1070 * 1087 *
1071 * @param user A <code>String</code> holding the username. 1088 * @param user A <code>String</code> holding the username.
1072 * @return a (possibly emtpy) array holding authentication method names. 1089 * @return a (possibly emtpy) array holding authentication method names.
1073 * @throws IOException 1090 * @throws IOException
1074 */ 1091 */
1092
1075 public synchronized String[] getRemainingAuthMethods(String user) throws IOException { 1093 public synchronized String[] getRemainingAuthMethods(String user) throws IOException {
1076 if(user == null) { 1094 if (user == null) {
1077 throw new IllegalArgumentException("user argument may not be NULL!"); 1095 throw new IllegalArgumentException("user argument may not be NULL!");
1078 } 1096 }
1079 1097
1080 if(tm == null) { 1098 if (tm == null) {
1081 throw new IllegalStateException("Connection is not established!"); 1099 throw new IllegalStateException("Connection is not established!");
1082 } 1100 }
1083 1101
1084 if(authenticated) { 1102 if (authenticated) {
1085 throw new IllegalStateException("Connection is already authenticated!"); 1103 throw new IllegalStateException("Connection is already authenticated!");
1086 } 1104 }
1087 1105
1088 if(am == null) { 1106 if (am == null) {
1089 am = new AuthenticationManager(tm); 1107 am = new AuthenticationManager(tm);
1090 } 1108 }
1091 1109
1092 if(cm == null) { 1110 if (cm == null) {
1093 cm = new ChannelManager(tm); 1111 cm = new ChannelManager(tm);
1094 } 1112 }
1095 1113
1096 final Set<String> remainingMethods = am.getRemainingMethods(user); 1114 final Set<String> remainingMethods = am.getRemainingMethods(user);
1097 return remainingMethods.toArray(new String[remainingMethods.size()]); 1115 return remainingMethods.toArray(new String[remainingMethods.size()]);
1102 * time. 1120 * time.
1103 * 1121 *
1104 * @return <code>true</code> if no further authentication steps are 1122 * @return <code>true</code> if no further authentication steps are
1105 * needed. 1123 * needed.
1106 */ 1124 */
1125
1107 public synchronized boolean isAuthenticationComplete() { 1126 public synchronized boolean isAuthenticationComplete() {
1108 return authenticated; 1127 return authenticated;
1109 } 1128 }
1110 1129
1111 /** 1130 /**
1118 * If you are interested in the details, then have a look at RFC4252. 1137 * If you are interested in the details, then have a look at RFC4252.
1119 * 1138 *
1120 * @return if the there was a failed authentication step and the last one 1139 * @return if the there was a failed authentication step and the last one
1121 * was marked as a "partial success". 1140 * was marked as a "partial success".
1122 */ 1141 */
1142
1123 public synchronized boolean isAuthenticationPartialSuccess() { 1143 public synchronized boolean isAuthenticationPartialSuccess() {
1124 if(am == null) { 1144 if (am == null) {
1125 return false; 1145 return false;
1126 } 1146 }
1147
1127 return am.getPartialSuccess(); 1148 return am.getPartialSuccess();
1128 } 1149 }
1129 1150
1130 /** 1151 /**
1131 * Checks if a specified authentication method is available. This method is 1152 * Checks if a specified authentication method is available. This method is
1136 * @param method An authentication method name (e.g., "publickey", "password", 1157 * @param method An authentication method name (e.g., "publickey", "password",
1137 * "keyboard-interactive") as specified by the SSH-2 standard. 1158 * "keyboard-interactive") as specified by the SSH-2 standard.
1138 * @return if the specified authentication method is currently available. 1159 * @return if the specified authentication method is currently available.
1139 * @throws IOException 1160 * @throws IOException
1140 */ 1161 */
1162
1141 public synchronized boolean isAuthMethodAvailable(String user, String method) throws IOException { 1163 public synchronized boolean isAuthMethodAvailable(String user, String method) throws IOException {
1142 String methods[] = getRemainingAuthMethods(user); 1164 String methods[] = getRemainingAuthMethods(user);
1143 for(final String m : methods) { 1165
1144 if(m.compareTo(method) == 0) { 1166 for (final String m : methods) {
1167 if (m.compareTo(method) == 0) {
1145 return true; 1168 return true;
1146 } 1169 }
1147 } 1170 }
1171
1148 return false; 1172 return false;
1149 } 1173 }
1150 1174
1151 private SecureRandom getOrCreateSecureRND() { 1175 private SecureRandom getOrCreateSecureRND() {
1152 if(generator == null) { 1176 if (generator == null) {
1153 generator = new SecureRandom(); 1177 generator = new SecureRandom();
1154 } 1178 }
1179
1155 return generator; 1180 return generator;
1156 } 1181 }
1157 1182
1158 /** 1183 /**
1159 * Open a new {@link Session} on this connection. Works only after one has passed 1184 * Open a new {@link Session} on this connection. Works only after one has passed
1161 * concurrent sessions. 1186 * concurrent sessions.
1162 * 1187 *
1163 * @return A {@link Session} object. 1188 * @return A {@link Session} object.
1164 * @throws IOException 1189 * @throws IOException
1165 */ 1190 */
1191
1166 public synchronized Session openSession() throws IOException { 1192 public synchronized Session openSession() throws IOException {
1167 this.checkConnection(); 1193 this.checkConnection();
1168
1169 return new Session(cm, getOrCreateSecureRND()); 1194 return new Session(cm, getOrCreateSecureRND());
1170 } 1195 }
1171 1196
1172 /** 1197 /**
1173 * Send an SSH_MSG_IGNORE packet. This method will generate a random data attribute 1198 * Send an SSH_MSG_IGNORE packet. This method will generate a random data attribute
1175 * <p/> 1200 * <p/>
1176 * This method must only be called once the connection is established. 1201 * This method must only be called once the connection is established.
1177 * 1202 *
1178 * @throws IOException 1203 * @throws IOException
1179 */ 1204 */
1205
1180 public synchronized void sendIgnorePacket() throws IOException { 1206 public synchronized void sendIgnorePacket() throws IOException {
1181 SecureRandom rnd = getOrCreateSecureRND(); 1207 SecureRandom rnd = getOrCreateSecureRND();
1182
1183 byte[] data = new byte[rnd.nextInt(16)]; 1208 byte[] data = new byte[rnd.nextInt(16)];
1184 rnd.nextBytes(data); 1209 rnd.nextBytes(data);
1185
1186 sendIgnorePacket(data); 1210 sendIgnorePacket(data);
1187 } 1211 }
1188 1212
1189 /** 1213 /**
1190 * Send an SSH_MSG_IGNORE packet with the given data attribute. 1214 * Send an SSH_MSG_IGNORE packet with the given data attribute.
1191 * <p/> 1215 * <p/>
1192 * This method must only be called once the connection is established. 1216 * This method must only be called once the connection is established.
1193 * 1217 *
1194 * @throws IOException 1218 * @throws IOException
1195 */ 1219 */
1220
1196 public synchronized void sendIgnorePacket(byte[] data) throws IOException { 1221 public synchronized void sendIgnorePacket(byte[] data) throws IOException {
1197 this.checkConnection(); 1222 this.checkConnection();
1198
1199 PacketIgnore pi = new PacketIgnore(data); 1223 PacketIgnore pi = new PacketIgnore(data);
1200
1201 tm.sendMessage(pi.getPayload()); 1224 tm.sendMessage(pi.getPayload());
1202 } 1225 }
1203 1226
1204 /** 1227 /**
1205 * Controls whether compression is used on the link or not. 1228 * Controls whether compression is used on the link or not.
1206 */ 1229 */
1230
1207 public synchronized void setCompression(String[] algorithms) { 1231 public synchronized void setCompression(String[] algorithms) {
1208 CompressionFactory.checkCompressorList(algorithms); 1232 CompressionFactory.checkCompressorList(algorithms);
1209 cryptoWishList.c2s_comp_algos = algorithms; 1233 cryptoWishList.c2s_comp_algos = algorithms;
1210 } 1234 }
1211 1235
1213 cryptoWishList.c2s_comp_algos = CompressionFactory.getDefaultCompressorList(); 1237 cryptoWishList.c2s_comp_algos = CompressionFactory.getDefaultCompressorList();
1214 cryptoWishList.s2c_comp_algos = CompressionFactory.getDefaultCompressorList(); 1238 cryptoWishList.s2c_comp_algos = CompressionFactory.getDefaultCompressorList();
1215 } 1239 }
1216 1240
1217 public synchronized void disableCompression() { 1241 public synchronized void disableCompression() {
1218 cryptoWishList.c2s_comp_algos = new String[]{"none"}; 1242 cryptoWishList.c2s_comp_algos = new String[] {"none"};
1219 cryptoWishList.s2c_comp_algos = new String[]{"none"}; 1243 cryptoWishList.s2c_comp_algos = new String[] {"none"};
1220 } 1244 }
1221 1245
1222 /** 1246 /**
1223 * Unless you know what you are doing, you will never need this. 1247 * Unless you know what you are doing, you will never need this.
1224 */ 1248 */
1249
1225 public synchronized void setClient2ServerCiphers(final String[] ciphers) { 1250 public synchronized void setClient2ServerCiphers(final String[] ciphers) {
1226 if((ciphers == null) || (ciphers.length == 0)) { 1251 if ((ciphers == null) || (ciphers.length == 0)) {
1227 throw new IllegalArgumentException(); 1252 throw new IllegalArgumentException();
1228 } 1253 }
1254
1229 BlockCipherFactory.checkCipherList(ciphers); 1255 BlockCipherFactory.checkCipherList(ciphers);
1230 cryptoWishList.c2s_enc_algos = ciphers; 1256 cryptoWishList.c2s_enc_algos = ciphers;
1231 } 1257 }
1232 1258
1233 /** 1259 /**
1234 * Unless you know what you are doing, you will never need this. 1260 * Unless you know what you are doing, you will never need this.
1235 */ 1261 */
1262
1236 public synchronized void setClient2ServerMACs(final String[] macs) { 1263 public synchronized void setClient2ServerMACs(final String[] macs) {
1237 MAC.checkMacList(macs); 1264 MAC.checkMacList(macs);
1238 cryptoWishList.c2s_mac_algos = macs; 1265 cryptoWishList.c2s_mac_algos = macs;
1239 } 1266 }
1240 1267
1243 * know what you are doing, you will never need this. Default values are 1270 * know what you are doing, you will never need this. Default values are
1244 * defined in the {@link DHGexParameters} class. 1271 * defined in the {@link DHGexParameters} class.
1245 * 1272 *
1246 * @param dgp {@link DHGexParameters}, non null. 1273 * @param dgp {@link DHGexParameters}, non null.
1247 */ 1274 */
1275
1248 public synchronized void setDHGexParameters(DHGexParameters dgp) { 1276 public synchronized void setDHGexParameters(DHGexParameters dgp) {
1249 if(dgp == null) { 1277 if (dgp == null) {
1250 throw new IllegalArgumentException(); 1278 throw new IllegalArgumentException();
1251 } 1279 }
1252 1280
1253 dhgexpara = dgp; 1281 dhgexpara = dgp;
1254 } 1282 }
1255 1283
1256 /** 1284 /**
1257 * Unless you know what you are doing, you will never need this. 1285 * Unless you know what you are doing, you will never need this.
1258 */ 1286 */
1287
1259 public synchronized void setServer2ClientCiphers(final String[] ciphers) { 1288 public synchronized void setServer2ClientCiphers(final String[] ciphers) {
1260 BlockCipherFactory.checkCipherList(ciphers); 1289 BlockCipherFactory.checkCipherList(ciphers);
1261 cryptoWishList.s2c_enc_algos = ciphers; 1290 cryptoWishList.s2c_enc_algos = ciphers;
1262 } 1291 }
1263 1292
1264 /** 1293 /**
1265 * Unless you know what you are doing, you will never need this. 1294 * Unless you know what you are doing, you will never need this.
1266 */ 1295 */
1296
1267 public synchronized void setServer2ClientMACs(final String[] macs) { 1297 public synchronized void setServer2ClientMACs(final String[] macs) {
1268 MAC.checkMacList(macs); 1298 MAC.checkMacList(macs);
1269 cryptoWishList.s2c_mac_algos = macs; 1299 cryptoWishList.s2c_mac_algos = macs;
1270 } 1300 }
1271 1301
1279 * SSH-2 defines <code>ssh-dss</code> and <code>ssh-rsa</code>. 1309 * SSH-2 defines <code>ssh-dss</code> and <code>ssh-rsa</code>.
1280 * The entries of the array must be ordered after preference, i.e., 1310 * The entries of the array must be ordered after preference, i.e.,
1281 * the entry at index 0 is the most preferred one. You must specify 1311 * the entry at index 0 is the most preferred one. You must specify
1282 * at least one entry. 1312 * at least one entry.
1283 */ 1313 */
1314
1284 public synchronized void setServerHostKeyAlgorithms(final String[] algos) { 1315 public synchronized void setServerHostKeyAlgorithms(final String[] algos) {
1285 KexManager.checkServerHostkeyAlgorithmsList(algos); 1316 KexManager.checkServerHostkeyAlgorithmsList(algos);
1286 cryptoWishList.serverHostKeyAlgorithms = algos; 1317 cryptoWishList.serverHostKeyAlgorithms = algos;
1287 } 1318 }
1288 1319
1294 * The default value that will be used is <code>false</code>. 1325 * The default value that will be used is <code>false</code>.
1295 * 1326 *
1296 * @param enable the argument passed to the <code>Socket.setTCPNoDelay()</code> method. 1327 * @param enable the argument passed to the <code>Socket.setTCPNoDelay()</code> method.
1297 * @throws IOException 1328 * @throws IOException
1298 */ 1329 */
1330
1299 public synchronized void setTCPNoDelay(boolean enable) throws IOException { 1331 public synchronized void setTCPNoDelay(boolean enable) throws IOException {
1300 tcpNoDelay = enable; 1332 tcpNoDelay = enable;
1301 if(tm != null) { 1333
1334 if (tm != null) {
1302 tm.setTcpNoDelay(enable); 1335 tm.setTcpNoDelay(enable);
1303 } 1336 }
1304 } 1337 }
1305 1338
1306 /** 1339 /**
1361 * @param bindPort port number to bind on the server (must be &gt; 0) 1394 * @param bindPort port number to bind on the server (must be &gt; 0)
1362 * @param targetAddress the target address (IP or hostname) 1395 * @param targetAddress the target address (IP or hostname)
1363 * @param targetPort the target port 1396 * @param targetPort the target port
1364 * @throws IOException 1397 * @throws IOException
1365 */ 1398 */
1399
1366 public synchronized void requestRemotePortForwarding(String bindAddress, int bindPort, String targetAddress, 1400 public synchronized void requestRemotePortForwarding(String bindAddress, int bindPort, String targetAddress,
1367 int targetPort) throws IOException { 1401 int targetPort) throws IOException {
1368 this.checkConnection(); 1402 this.checkConnection();
1369 1403
1370 if((bindAddress == null) || (targetAddress == null) || (bindPort <= 0) || (targetPort <= 0)) { 1404 if ((bindAddress == null) || (targetAddress == null) || (bindPort <= 0) || (targetPort <= 0)) {
1371 throw new IllegalArgumentException(); 1405 throw new IllegalArgumentException();
1372 } 1406 }
1373 1407
1374 cm.requestGlobalForward(bindAddress, bindPort, targetAddress, targetPort); 1408 cm.requestGlobalForward(bindAddress, bindPort, targetAddress, targetPort);
1375 } 1409 }
1382 * 1416 *
1383 * @param bindPort the allocated port number on the server 1417 * @param bindPort the allocated port number on the server
1384 * @throws IOException if the remote side refuses the cancel request or another low 1418 * @throws IOException if the remote side refuses the cancel request or another low
1385 * level error occurs (e.g., the underlying connection is closed) 1419 * level error occurs (e.g., the underlying connection is closed)
1386 */ 1420 */
1421
1387 public synchronized void cancelRemotePortForwarding(int bindPort) throws IOException { 1422 public synchronized void cancelRemotePortForwarding(int bindPort) throws IOException {
1388 this.checkConnection(); 1423 this.checkConnection();
1389
1390 cm.requestCancelGlobalForward(bindPort); 1424 cm.requestCancelGlobalForward(bindPort);
1391 } 1425 }
1392 1426
1393 /** 1427 /**
1394 * Provide your own instance of SecureRandom. Can be used, e.g., if you 1428 * Provide your own instance of SecureRandom. Can be used, e.g., if you
1397 * The SecureRandom instance is used during key exchanges, public key authentication, 1431 * The SecureRandom instance is used during key exchanges, public key authentication,
1398 * x11 cookie generation and the like. 1432 * x11 cookie generation and the like.
1399 * 1433 *
1400 * @param rnd a SecureRandom instance 1434 * @param rnd a SecureRandom instance
1401 */ 1435 */
1436
1402 public synchronized void setSecureRandom(SecureRandom rnd) { 1437 public synchronized void setSecureRandom(SecureRandom rnd) {
1403 if(rnd == null) { 1438 if (rnd == null) {
1404 throw new IllegalArgumentException(); 1439 throw new IllegalArgumentException();
1405 } 1440 }
1441
1406 this.generator = rnd; 1442 this.generator = rnd;
1407 } 1443 }
1408 1444
1409 private void checkConnection() throws IllegalStateException { 1445 private void checkConnection() throws IllegalStateException {
1410 if(tm == null) { 1446 if (tm == null) {
1411 throw new IllegalStateException("You need to establish a connection first."); 1447 throw new IllegalStateException("You need to establish a connection first.");
1412 } 1448 }
1413 if(!authenticated) { 1449
1450 if (!authenticated) {
1414 throw new IllegalStateException("The connection is not authenticated."); 1451 throw new IllegalStateException("The connection is not authenticated.");
1415 } 1452 }
1416 } 1453 }
1417 } 1454 }