package aQute.remote.agent;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* A redirector that will open a connection to a socket, assuming there is a
* shell running there.
*/
public class SocketRedirector implements Redirector {
//
// The key used by the Apache Felix shell to define the host the server
// socket is registered on
//
private static final String OSGI_SHELL_TELNET_IP = "osgi.shell.telnet.ip";
//
// Telnet sends some options in the beginning that need to be
// skipped. The IAC is the first byte that then is followed
// by some commands.
//
private static final int IAC = 255;
private Socket socket;
private PrintStream in;
private Thread out;
private boolean quit;
/**
* Constructor
*
* @param agentServer the agent we're working for
* @param port the shell port
*/
public SocketRedirector(final AgentServer agentServer, final int port) throws Exception {
//
// We need a thread to read any output from the shell processor
// which is then forwarded to the supervisor
//
this.out = new Thread() {
@Override
public void run() {
try {
//
// Connect to the server. We keep on trying this.
//
while (!isInterrupted() && !quit) {
socket = findSocket(agentServer, port);
if (socket != null)
break;
Thread.sleep(1000);
}
//
// Create a printstream on the socket output (the system's
// input).
//
SocketRedirector.this.in = new PrintStream(socket.getOutputStream());
//
// Start reading the input
//
InputStream out = socket.getInputStream();
byte[] buffer = new byte[1000];
while (!isInterrupted() && !quit)
try {
int size = out.read(buffer);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < size; i++) {
int b = 0xFF & buffer[i];
// Since we have a telnet protocol, there
// are some special characters we should
// ignore. We assume that all parts of the
// command are in the same buffer, which is
// highly likely since they are usually
// tramsmitted in a single go
if (b == IAC) {
// Next is the command type
b = buffer[++i];
// DO, DONT, WILL, WONT have an extra byte
if (b == 251 || b == 252 || b == 253 || b == 254)
++i;
} else {
sb.append((char) b);
}
}
if (sb.length() > 0)
agentServer.getSupervisor().stdout(sb.toString());
} catch (Exception e) {
break;
}
} catch (Exception e1) {
// ignore, we just exit
} finally {
try {
if (socket != null && !quit)
socket.close();
} catch (IOException e) {
// ignore
}
}
}
};
this.out.setDaemon(true);
this.out.start();
}
Socket findSocket(AgentServer agent, int port) throws UnknownHostException {
try {
String ip = agent.getContext().getProperty(OSGI_SHELL_TELNET_IP);
if (ip != null) {
InetAddress gogoHost = InetAddress.getByName(ip);
return new Socket(gogoHost, port);
}
} catch (Exception e) {
// ignore
}
try {
//
// Some Unix's use 127.0.1.1 for some unknown reason
// but the Gogo shell delivers at 127.0.0.1
//
InetAddress oldStyle = InetAddress.getByName(null);
return new Socket(oldStyle, port);
} catch (Exception e) {
// ignore
}
//
// Ah well, maybe they did change their mind, so let's
// look at localhost as well.
//
try {
InetAddress localhost = InetAddress.getLocalHost();
return new Socket(localhost, port);
} catch (Exception e) {
// ignore
}
return null;
}
@Override
public void close() throws IOException {
quit = true;
out.interrupt();
socket.close();
try {
out.join(500);
} catch (InterruptedException e) {
// ignore, best effort
}
}
@Override
public int getPort() {
return socket.getPort();
}
@Override
public void stdin(String s) throws Exception {
if (this.in != null) {
this.in.print(s);
this.in.flush();
}
}
@Override
public PrintStream getOut() throws Exception {
if (this.in != null)
return this.in;
return System.out;
}
}