package processing.app; import cc.arduino.packages.BoardPort; import cc.arduino.packages.ssh.NoInteractionUserInfo; import cc.arduino.packages.ssh.SSHClientSetupChainRing; import cc.arduino.packages.ssh.SSHConfigFileSetup; import cc.arduino.packages.ssh.SSHPwdSetup; import com.jcraft.jsch.*; import processing.app.debug.MessageConsumer; import processing.app.debug.MessageSiphon; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import static processing.app.I18n.tr; @SuppressWarnings("serial") public class NetworkMonitor extends AbstractTextMonitor implements MessageConsumer { private static final int MAX_CONNECTION_ATTEMPTS = 5; private MessageSiphon inputConsumer; private Session session; private Channel channel; private int connectionAttempts; public NetworkMonitor(BoardPort port) { super(port); onSendCommand(new ActionListener() { public void actionPerformed(ActionEvent event) { try { OutputStream out = channel.getOutputStream(); out.write(textField.getText().getBytes()); out.write('\n'); out.flush(); } catch (IOException e) { e.printStackTrace(); } textField.setText(""); } }); } @Override public boolean requiresAuthorization() { return true; } @Override public String getAuthorizationKey() { return "runtime.pwd." + getBoardPort().getAddress(); } @Override public void open() throws Exception { super.open(); this.connectionAttempts = 0; JSch jSch = new JSch(); SSHClientSetupChainRing sshClientSetupChain = new SSHConfigFileSetup(new SSHPwdSetup()); session = sshClientSetupChain.setup(getBoardPort(), jSch); session.setConfig("PreferredAuthentications", "publickey,keyboard-interactive,password"); session.setUserInfo(new NoInteractionUserInfo(PreferencesData.get(getAuthorizationKey()))); session.connect(30000); tryConnect(); } private void tryConnect() throws JSchException, IOException { connectionAttempts++; if (connectionAttempts > 1) { try { Thread.sleep(2000); } catch (InterruptedException e) { // ignored } } if (!session.isConnected()) { return; } channel = session.openChannel("exec"); ((ChannelExec) channel).setCommand("telnet localhost 6571"); InputStream inputStream = channel.getInputStream(); InputStream errStream = ((ChannelExec) channel).getErrStream(); channel.connect(); inputConsumer = new MessageSiphon(inputStream, this); new MessageSiphon(errStream, this); if (connectionAttempts > 1) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { // ignore } if (channel.isConnected()) { NetworkMonitor.this.message(tr("connected!") + '\n'); } } }); } } @Override public synchronized void message(String s) { if (s.contains("can't connect")) { while (!channel.isClosed()) { try { Thread.sleep(100); } catch (InterruptedException e) { // ignore } } if (connectionAttempts < MAX_CONNECTION_ATTEMPTS) { s = "\n" + tr("Unable to connect: retrying") + " (" + connectionAttempts + ")... "; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { try { NetworkMonitor.this.tryConnect(); } catch (JSchException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }); } else { s = "\n" + tr("Unable to connect: is the sketch using the bridge?"); } } super.message(s); } @Override public void close() throws Exception { super.close(); if (channel != null) { inputConsumer.stop(); channel.disconnect(); textArea.setText(""); } if (session != null) { session.disconnect(); } } }