| /******************************************************************************* |
| * Copyright (c) 2015 IBM Corporation, and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial contribution |
| *******************************************************************************/ |
| package org.eclipse.remote.telnet.core; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.io.PipedInputStream; |
| import java.io.PipedOutputStream; |
| import java.net.ConnectException; |
| import java.net.InetSocketAddress; |
| import java.net.Socket; |
| import java.net.SocketTimeoutException; |
| import java.net.UnknownHostException; |
| |
| import org.eclipse.remote.core.IRemoteConnection; |
| import org.eclipse.remote.core.IRemoteConnectionHostService; |
| import org.eclipse.remote.core.IRemoteProcess; |
| import org.eclipse.remote.core.IRemoteProcessBuilder; |
| import org.eclipse.remote.core.exception.RemoteConnectionException; |
| import org.eclipse.remote.telnet.internal.core.Logger; |
| import org.eclipse.remote.telnet.internal.core.messages.Messages; |
| |
| public class TelnetCommandShell implements IRemoteProcess { |
| private final TelnetConnection telnetConnection; |
| private TelnetProtocol protocol; |
| |
| public TelnetCommandShell(IRemoteConnection remoteConnection, TelnetConnection telnetConnection) { |
| this.telnetConnection = telnetConnection; |
| assert(remoteConnection.getService(IRemoteConnectionHostService.class) != null); |
| } |
| |
| @Override |
| public void destroy() { |
| if (protocol != null) { |
| protocol.interrupt(); |
| } |
| } |
| |
| @Override |
| public int exitValue() { |
| return 0; |
| } |
| |
| @Override |
| public InputStream getErrorStream() { |
| return null; |
| } |
| |
| @Override |
| public InputStream getInputStream() { |
| if (protocol != null) { |
| PipedOutputStream pipedOutput = new PipedOutputStream(); |
| protocol.setClientOutputStream(pipedOutput); |
| try { |
| return new PipedInputStream(pipedOutput); |
| } catch (IOException e) { |
| return null; |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public OutputStream getOutputStream() { |
| if (protocol != null) { |
| return protocol.getOutputStream(); |
| } |
| return null; |
| } |
| |
| @Override |
| public int waitFor() throws InterruptedException { |
| if (protocol != null && protocol.isConnected()) { |
| wait(); |
| } |
| return 0; |
| } |
| |
| @Override |
| public boolean isCompleted() { |
| return protocol == null || !protocol.isAlive(); |
| } |
| |
| @Override |
| public IRemoteConnection getRemoteConnection() { |
| return telnetConnection.getRemoteConnection(); |
| } |
| |
| @Override |
| public <T extends Service> T getService(Class<T> service) { |
| return null; |
| } |
| |
| @Override |
| public <T extends Service> boolean hasService(Class<T> service) { |
| return false; |
| } |
| |
| @Override |
| public IRemoteProcessBuilder getProcessBuilder() { |
| return null; |
| } |
| |
| public void connect() throws RemoteConnectionException { |
| IRemoteConnectionHostService hostSvc = telnetConnection.getRemoteConnection() |
| .getService(IRemoteConnectionHostService.class); |
| |
| // Retry the connect after a little pause in case the |
| // remote telnet server isn't ready. ConnectExceptions might |
| // happen if the telnet server process did not initialized itself. |
| // This is seen especially if the telnet server is a process |
| // providing it's input and output via a built in telnet server. |
| int remaining = 10; |
| |
| while (remaining >= 0) { |
| // Pause before we re-try if the remaining tries are less than the initial value |
| if (remaining < 10) { |
| try { |
| Thread.sleep(500); |
| } catch (InterruptedException e) { |
| /* ignored on purpose */ } |
| } |
| |
| try { |
| int nTimeout = hostSvc.getTimeout() * 1000; |
| String strHost = hostSvc.getHostname(); |
| int nPort = hostSvc.getPort(); |
| InetSocketAddress address = new InetSocketAddress(strHost, nPort); |
| Socket socket = new Socket(); |
| |
| socket.connect(address, nTimeout); |
| |
| // If we get to this point, the connect succeeded and we will |
| // force the remaining counter to be 0. |
| remaining = 0; |
| |
| // This next call causes reads on the socket to see TCP urgent data |
| // inline with the rest of the non-urgent data. Without this call, TCP |
| // urgent data is silently dropped by Java. This is required for |
| // TELNET support, because when the TELNET server sends "IAC DM", the |
| // IAC byte is TCP urgent data. If urgent data is silently dropped, we |
| // only see the DM, which looks like an ISO Latin-1 '�' character. |
| |
| socket.setOOBInline(true); |
| socket.setKeepAlive(true); |
| |
| protocol = new TelnetProtocol(socket, this); |
| protocol.start(); |
| } catch (UnknownHostException ex) { |
| // No re-try in case of UnknownHostException, there is no indication that |
| // the DNS will fix itself |
| throw new RemoteConnectionException(Messages.TelnetCommandShell_0 + ex.getMessage()); |
| } catch (SocketTimeoutException socketTimeoutException) { |
| // Time out occurred. No re-try in this case either. Time out can |
| // be increased by the user. Multiplying the timeout with the remaining |
| // counter is not desired. |
| throw new RemoteConnectionException(socketTimeoutException.getMessage()); |
| } catch (ConnectException connectException) { |
| // In case of a ConnectException, do a re-try. The server could have been |
| // simply not ready yet and the worker would give up to early. If the terminal |
| // control is already closed (disconnected), don't print "Connection refused" errors |
| if (remaining == 0) { |
| throw new RemoteConnectionException(connectException.getMessage()); |
| } |
| } catch (Exception exception) { |
| // Any other exception on connect. No re-try in this case either |
| // Log the exception |
| Logger.logException(exception); |
| // And signal failed |
| throw new RemoteConnectionException(exception.getMessage()); |
| } finally { |
| remaining--; |
| } |
| } |
| } |
| |
| protected void terminated() { |
| telnetConnection.terminated(this); |
| } |
| } |