parent
24e1aaa396
commit
c2e3fc9e03
@ -0,0 +1,18 @@ |
||||
package be.noctis.vnc.relay; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.HashSet; |
||||
import java.util.Set; |
||||
|
||||
public interface IProtocolCommand { |
||||
|
||||
public static final int SERVER_CONNECTION = 10; |
||||
public static final int CLIENT_CONNECTION = 20; |
||||
|
||||
public static final int RELAY_CONNECTION = 30; |
||||
|
||||
public Set<Integer> ALL_COMMANDS = new HashSet<Integer>(Arrays.asList(new Integer[] { new Integer(SERVER_CONNECTION), |
||||
new Integer(CLIENT_CONNECTION), |
||||
new Integer(RELAY_CONNECTION)})); |
||||
|
||||
} |
@ -0,0 +1,24 @@ |
||||
package be.noctis.vnc.relay; |
||||
|
||||
public class ProtocolBean { |
||||
|
||||
private int command = -1; |
||||
private String serverID = null; |
||||
|
||||
public int getCommand() { |
||||
return command; |
||||
} |
||||
|
||||
public void setCommand(int command) { |
||||
this.command = command; |
||||
} |
||||
|
||||
public String getServerID() { |
||||
return serverID; |
||||
} |
||||
|
||||
public void setServerID(String serverID) { |
||||
this.serverID = serverID; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,297 @@ |
||||
package be.noctis.vnc.relay; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.OutputStream; |
||||
import java.net.InetAddress; |
||||
import java.net.ServerSocket; |
||||
import java.net.Socket; |
||||
import java.util.HashMap; |
||||
import java.util.LinkedList; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
public class Relay { |
||||
|
||||
private ServerSocket listeningSocket; |
||||
|
||||
private List<ConnectClientThread> clientWaitServer = new LinkedList<ConnectClientThread>(); |
||||
|
||||
private Map<String, Socket> commandSockets = new HashMap<String, Socket>(); |
||||
|
||||
private class ConnectClientThread extends Thread { |
||||
|
||||
private int MAX_WAITING_CYCLE = 1000; |
||||
|
||||
private String serverID = null; |
||||
|
||||
private Socket clientSocket = null; |
||||
|
||||
private Socket serverSocket = null; |
||||
|
||||
public ConnectClientThread(String inServerID, Socket inClientSocket) { |
||||
serverID = inServerID; |
||||
clientSocket = inClientSocket; |
||||
} |
||||
|
||||
public void run() { |
||||
try { |
||||
int waitingCycle = 0; |
||||
while ((serverSocket == null) && waitingCycle < MAX_WAITING_CYCLE) { |
||||
synchronized (serverID) { |
||||
serverID.wait(10000); |
||||
} |
||||
waitingCycle++; |
||||
} |
||||
synchronized (clientWaitServer) { |
||||
clientWaitServer.remove(this); |
||||
} |
||||
if (serverSocket != null) { |
||||
System.out.println("New connection create with server : " + serverID); |
||||
RelayThread serverClient = new RelayThread(serverSocket, clientSocket); |
||||
RelayThread clientServer = new RelayThread(clientSocket, serverSocket); |
||||
clientServer.touch(); |
||||
serverClient.start(); |
||||
clientServer.start(); |
||||
} else { |
||||
System.out.println("Error when client create connection to server : " + serverID); |
||||
try { |
||||
clientSocket.close(); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} catch (InterruptedException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
public String getServerID() { |
||||
return serverID; |
||||
} |
||||
|
||||
public void setServerSocket(Socket serverSocket) { |
||||
this.serverSocket = serverSocket; |
||||
synchronized (serverID) { |
||||
serverID.notify(); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
private class RelayThread extends Thread { |
||||
|
||||
private Socket clientSocket = null; |
||||
|
||||
private Socket serverSocket = null; |
||||
|
||||
public RelayThread(Socket server, Socket client) { |
||||
serverSocket = server; |
||||
clientSocket = client; |
||||
} |
||||
|
||||
public void touch() { |
||||
try { |
||||
clientSocket.getOutputStream().write(0); |
||||
} catch (IOException e) { |
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace(); |
||||
} |
||||
System.out.println("touch"); |
||||
} |
||||
|
||||
@Override |
||||
public void run() { |
||||
System.out.println("start a relay"); |
||||
try { |
||||
InputStream in = serverSocket.getInputStream(); |
||||
OutputStream out = clientSocket.getOutputStream(); |
||||
|
||||
byte[] readBuffer = new byte[4096]; |
||||
|
||||
int b = in.read(); |
||||
while (b >= 0) { |
||||
out.write(b); |
||||
if (in.available() == 0) { |
||||
out.flush(); |
||||
} else { |
||||
int readedLength = in.read(readBuffer); |
||||
out.write(readBuffer, 0, readedLength); |
||||
out.flush(); |
||||
} |
||||
b = in.read(); |
||||
} |
||||
|
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
if (clientSocket != null) { |
||||
try { |
||||
clientSocket.close(); |
||||
} catch (IOException e1) { |
||||
e1.printStackTrace(); |
||||
} |
||||
} |
||||
if (serverSocket != null) { |
||||
try { |
||||
serverSocket.close(); |
||||
} catch (IOException e1) { |
||||
e1.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
System.out.println("stop a relay."); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* read a protocol command (first bytes send by client or server or command on command connection) protocol : [command][data length][data]* |
||||
* |
||||
* @param inStream |
||||
* @return |
||||
* @throws IOException |
||||
*/ |
||||
private ProtocolBean readProtocolCommand(InputStream inStream) throws IOException { |
||||
ProtocolBean outBean = new ProtocolBean(); |
||||
int command = inStream.read(); |
||||
if (!IProtocolCommand.ALL_COMMANDS.contains(new Integer(command))) { |
||||
throw new IOException("unknow command found as protocol : " + command); |
||||
} |
||||
outBean.setCommand(command); |
||||
int codeSize = inStream.read(); |
||||
byte[] b = new byte[codeSize]; |
||||
inStream.read(b); |
||||
outBean.setServerID(new String(b)); |
||||
return outBean; |
||||
} |
||||
|
||||
private void sendProtocolCommand(OutputStream out, ProtocolBean bean) throws IOException { |
||||
out.write((byte) bean.getCommand()); |
||||
byte[] data = bean.getServerID().getBytes(); |
||||
out.write(data.length); |
||||
out.write(data); |
||||
out.flush(); |
||||
} |
||||
|
||||
public void addClientSocket(String serverID, Socket inSocket) throws IOException { |
||||
ConnectClientThread cc = new ConnectClientThread(serverID, inSocket); |
||||
cc.start(); |
||||
synchronized (clientWaitServer) { |
||||
clientWaitServer.add(cc); |
||||
} |
||||
askConnection(serverID); |
||||
} |
||||
|
||||
public void askConnection(String serverID) throws IOException { |
||||
|
||||
Socket serverSocket = commandSockets.get(serverID); |
||||
if (serverSocket != null) { |
||||
synchronized (commandSockets) { |
||||
ProtocolBean bean = new ProtocolBean(); |
||||
bean.setCommand(IProtocolCommand.RELAY_CONNECTION); |
||||
// send server ID for check it when server receive this command.
|
||||
bean.setServerID(serverID); |
||||
System.out.println("ask new connection to server local relay : " + serverID); |
||||
sendProtocolCommand(serverSocket.getOutputStream(), bean); |
||||
} |
||||
} else { |
||||
System.out.println("server socket not found : " + serverID); |
||||
} |
||||
} |
||||
|
||||
public void addServerSocket(String serverID, Socket inSocket) { |
||||
commandSockets.put(serverID, inSocket); |
||||
} |
||||
|
||||
public void addRelaySocket(String serverID, Socket inSocket) { |
||||
ConnectClientThread needConnectionFound = null; |
||||
synchronized (clientWaitServer) { |
||||
for (ConnectClientThread cc : clientWaitServer) { |
||||
if (cc.getServerID().equals(serverID)) { |
||||
needConnectionFound = cc; |
||||
} |
||||
} |
||||
if (needConnectionFound != null) { |
||||
clientWaitServer.remove(needConnectionFound); |
||||
} |
||||
} |
||||
needConnectionFound.setServerSocket(inSocket); |
||||
} |
||||
|
||||
private class ClientThread extends Thread { |
||||
|
||||
private Socket newSocket = null; |
||||
|
||||
@Override |
||||
public void run() { |
||||
try { |
||||
|
||||
ProtocolBean bean = readProtocolCommand(newSocket.getInputStream()); |
||||
System.out.println("command receive : " + bean.getCommand() + " serverID : " + bean.getServerID()); |
||||
if (bean.getCommand() == IProtocolCommand.SERVER_CONNECTION) { |
||||
addServerSocket(bean.getServerID(), newSocket); |
||||
} else if (bean.getCommand() == IProtocolCommand.CLIENT_CONNECTION) { |
||||
addClientSocket(bean.getServerID(), newSocket); |
||||
} else if (bean.getCommand() == IProtocolCommand.RELAY_CONNECTION) { |
||||
addRelaySocket(bean.getServerID(), newSocket); |
||||
} |
||||
|
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
public void setNewSocket(Socket newSocket) { |
||||
this.newSocket = newSocket; |
||||
} |
||||
} |
||||
|
||||
public void startRelay(int port, InetAddress ip) { |
||||
try { |
||||
String ipStr = "all"; |
||||
if (ip != null) { |
||||
ipStr = ip.getHostAddress(); |
||||
} |
||||
System.out.println("create server on [port:" + port + "] [ip=" + ipStr + "]"); |
||||
if (ip != null) { |
||||
listeningSocket = new ServerSocket(port, 10, ip); |
||||
} else { |
||||
listeningSocket = new ServerSocket(port, 10); |
||||
} |
||||
for (;;) { |
||||
System.out.println("Wait client..."); |
||||
Socket newSocket = listeningSocket.accept(); |
||||
System.out.println("New client connected."); |
||||
ClientThread clientThread = new ClientThread(); |
||||
clientThread.setNewSocket(newSocket); |
||||
clientThread.start(); |
||||
} |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
public static void main(String[] args) { |
||||
Relay rel = new Relay(); |
||||
|
||||
int port = 443; |
||||
InetAddress ip = null; |
||||
if (args.length > 0) { |
||||
String portStr = args[0]; |
||||
try { |
||||
port = Integer.parseInt(portStr); |
||||
|
||||
// ip defined
|
||||
if (args.length > 1) { |
||||
String ipStr = args[1]; |
||||
ip = InetAddress.getByName(ipStr); |
||||
} |
||||
} catch (Throwable e) { |
||||
e.printStackTrace(); |
||||
System.out.println("ERROR : parameter format : [Port number] [ip]"); |
||||
System.exit(-1); |
||||
} |
||||
} |
||||
|
||||
rel.startRelay(port, ip); |
||||
} |
||||
} |
Loading…
Reference in new issue