1 package processing.app; 2 3 import cc.arduino.packages.BoardPort; 4 import cc.arduino.packages.ssh.NoInteractionUserInfo; 5 import cc.arduino.packages.ssh.SSHClientSetupChainRing; 6 import cc.arduino.packages.ssh.SSHConfigFileSetup; 7 import cc.arduino.packages.ssh.SSHPwdSetup; 8 9 import com.jcraft.jsch.*; 10 11 import processing.app.debug.MessageConsumer; 12 import processing.app.debug.MessageSiphon; 13 14 import javax.swing.*; 15 16 import java.awt.event.ActionEvent; 17 import java.awt.event.ActionListener; 18 import java.io.IOException; 19 import java.io.InputStream; 20 import java.io.OutputStream; 21 22 import static processing.app.I18n.tr; 23 24 @SuppressWarnings("serial") 25 public class NetworkMonitor extends AbstractTextMonitor implements MessageConsumer { 26 27 private static final int MAX_CONNECTION_ATTEMPTS = 5; 28 29 private MessageSiphon inputConsumer; 30 private Session session; 31 private Channel channel; 32 private int connectionAttempts; 33 NetworkMonitor(BoardPort port)34 public NetworkMonitor(BoardPort port) { 35 super(port); 36 37 onSendCommand(new ActionListener() { 38 public void actionPerformed(ActionEvent event) { 39 try { 40 OutputStream out = channel.getOutputStream(); 41 out.write(textField.getText().getBytes()); 42 out.write('\n'); 43 out.flush(); 44 } catch (IOException e) { 45 e.printStackTrace(); 46 } 47 textField.setText(""); 48 } 49 }); 50 } 51 52 @Override requiresAuthorization()53 public boolean requiresAuthorization() { 54 return true; 55 } 56 57 @Override getAuthorizationKey()58 public String getAuthorizationKey() { 59 return "runtime.pwd." + getBoardPort().getAddress(); 60 } 61 62 @Override open()63 public void open() throws Exception { 64 super.open(); 65 this.connectionAttempts = 0; 66 67 JSch jSch = new JSch(); 68 SSHClientSetupChainRing sshClientSetupChain = new SSHConfigFileSetup(new SSHPwdSetup()); 69 session = sshClientSetupChain.setup(getBoardPort(), jSch); 70 71 session.setConfig("PreferredAuthentications", "publickey,keyboard-interactive,password"); 72 session.setUserInfo(new NoInteractionUserInfo(PreferencesData.get(getAuthorizationKey()))); 73 session.connect(30000); 74 75 tryConnect(); 76 } 77 tryConnect()78 private void tryConnect() throws JSchException, IOException { 79 connectionAttempts++; 80 81 if (connectionAttempts > 1) { 82 try { 83 Thread.sleep(2000); 84 } catch (InterruptedException e) { 85 // ignored 86 } 87 } 88 89 if (!session.isConnected()) { 90 return; 91 } 92 channel = session.openChannel("exec"); 93 ((ChannelExec) channel).setCommand("telnet localhost 6571"); 94 95 InputStream inputStream = channel.getInputStream(); 96 InputStream errStream = ((ChannelExec) channel).getErrStream(); 97 98 channel.connect(); 99 100 inputConsumer = new MessageSiphon(inputStream, this); 101 new MessageSiphon(errStream, this); 102 103 if (connectionAttempts > 1) { 104 SwingUtilities.invokeLater(new Runnable() { 105 106 @Override 107 public void run() { 108 try { 109 Thread.sleep(1000); 110 } catch (InterruptedException e) { 111 // ignore 112 } 113 if (channel.isConnected()) { 114 NetworkMonitor.this.message(tr("connected!") + '\n'); 115 } 116 } 117 118 }); 119 } 120 } 121 122 @Override message(String s)123 public synchronized void message(String s) { 124 if (s.contains("can't connect")) { 125 while (!channel.isClosed()) { 126 try { 127 Thread.sleep(100); 128 } catch (InterruptedException e) { 129 // ignore 130 } 131 } 132 if (connectionAttempts < MAX_CONNECTION_ATTEMPTS) { 133 s = "\n" + tr("Unable to connect: retrying") + " (" + connectionAttempts + ")... "; 134 135 SwingUtilities.invokeLater(new Runnable() { 136 @Override 137 public void run() { 138 try { 139 NetworkMonitor.this.tryConnect(); 140 } catch (JSchException e) { 141 e.printStackTrace(); 142 } catch (IOException e) { 143 e.printStackTrace(); 144 } 145 } 146 }); 147 } else { 148 s = "\n" + tr("Unable to connect: is the sketch using the bridge?"); 149 } 150 } 151 super.message(s); 152 } 153 154 @Override close()155 public void close() throws Exception { 156 super.close(); 157 158 if (channel != null) { 159 inputConsumer.stop(); 160 channel.disconnect(); 161 textArea.setText(""); 162 } 163 164 if (session != null) { 165 session.disconnect(); 166 } 167 } 168 169 } 170