/**
* ProxyMaster: Ivy relay, first attempt
*
* @author Yannick Jestin
* @author http://www.tls.cena.fr/products/ivy/
*
* (c) ENAC
*
* changelog:
* 1.2.14
* - throws RuntimeException instead of System.exit(), allows code reuse
* - switch from gnu regexp (deprecated) to the built in java regexp
* - add generic types to declarations
* 1.2.13
* - adds support for RESyntaxException
* 1.2.12
*/
package fr.dgac.ivy.tools ; // TODO go into sub tools, and build a shell/.BAT script
import fr.dgac.ivy.* ;
import java.io.*;
import java.net.*;
import java.util.* ;
import gnu.getopt.Getopt;
import java.util.regex.*;
public class ProxyMaster {
private ServerSocket serviceSocket;
private static boolean debug=false;
private boolean doRun=true; // stops running when set to false
private Vector proxyClients = new Vector();
private Hashtable ghostFathers = new Hashtable(); // key: ghostId value: SubReader
private static int serial=0;
public static final int DEFAULT_SERVICE_PORT = 3456 ;
public static final String DEFAULTNAME = "ProxyMaster";
public static final String helpmsg = "usage: java fr.dgac.ivy.ProxyMaster [options]\n\t-p\tport number, default "+DEFAULT_SERVICE_PORT+"\n\t-q\tquiet, no tty output\n\t-d\tdebug\n\t-h\thelp\nListens on the TCP port for ProxyClients to join.\n";
static Pattern helloRE, getId,fwdPuppet,fwdGhost;
private static String name = DEFAULTNAME;
static {
try {
helloRE=Pattern.compile("^Hello bus=(.*)");
getId=Pattern.compile("^GetID id=(.*)");
fwdPuppet=Pattern.compile("^ForwardPuppet id=(.*) buffer=(.*)");
fwdGhost=Pattern.compile("^ForwardGhost id=(.*) buffer=(.*)");
} catch ( PatternSyntaxException res ) {
res.printStackTrace();
System.out.println("Regular Expression bug in Ivy source code ... bailing out");
throw new RuntimeException();
}
}
public static void main(String[] args) {
Ivy bus;
Getopt opt = new Getopt("ProxyMaster",args,"dqp:h");
int c;
int servicePort = DEFAULT_SERVICE_PORT;
boolean quiet = false;
while ((c = opt.getopt()) != -1) switch (c) {
case 'q':
quiet=true;
break;
case 'd':
Properties sysProp = System.getProperties();
sysProp.put("IVY_DEBUG","yes");
break;
case 'p':
String s="";
try {
servicePort = Integer.parseInt(s=opt.getOptarg());
} catch (NumberFormatException nfe) {
System.out.println("Invalid port number: " + s );
throw new RuntimeException();
}
break;
case 'h':
default:
System.out.println(helpmsg);
return;
}
try {
if (!quiet) System.out.println("listening on "+servicePort);
new ProxyMaster(servicePort);
} catch (IOException ioe) {
System.out.println("error, can't set up the proxy master");
ioe.printStackTrace();
return;
}
}
public ProxyMaster(int servicePort) throws IOException {
serviceSocket = new ServerSocket(servicePort) ;
while ( true ) {
try {
new SubReader(serviceSocket.accept());
} catch( IOException e ) {
traceDebug("TCP socket reader caught an exception " + e.getMessage());
}
}
}
class SubReader extends Thread {
BufferedReader in;
PrintWriter out;
String hostname=null; // I will know from the socket
String busDomain=null; // I will know it from the Hello message
SubReader(Socket socket) throws IOException {
proxyClients.addElement(this);
hostname = socket.getInetAddress().getHostName();
in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
out=new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
start();
}
public void send(String s) { // sends a message to the SubReader peer ( a ProxyClient )
out.println(s);
out.flush();
}
public void run() {
traceDebug("Subreader Thread started");
String msg = null;
try {
while (doRun) {
msg=in.readLine();
if (msg==null) break;
parseMsg(msg);
}
} catch (IOException ioe) {
traceDebug("Subreader exception ...");
ioe.printStackTrace();
throw new RuntimeException();
}
traceDebug("Subreader Thread stopped");
System.out.println("ProxyClient on "+hostname+", bus "+busDomain+" disconnected");
proxyClients.removeElement(this);
}
void parseMsg(String msg) {
// System.out.println("PM parsing "+msg);
Matcher m;
if ((m=helloRE.matcher(msg)).matches()) {
busDomain = m.group(1);
System.out.println("PC connected from "+hostname+", on the bus "+busDomain);
} else if ((m=getId.matcher(msg)).matches()) {
// a new Ghost has appeared and requests an Id
System.out.println("PM registering a new Ghost");
String newGhostId = Integer.valueOf(serial++).toString();
// I give it its ID
send("ID id="+m.group(1)+" value="+newGhostId);
ghostFathers.put(newGhostId,this); // remember the SubReader holding this Ghost
// I ask all other Clients to prepare a puppet
for (SubReader sr : proxyClients) {
if (sr!=SubReader.this) {
// System.out.println("propagate CreatePuppet to "+sr.busDomain);
sr.send("CreatePuppet id="+newGhostId);
} else {
// System.out.println("won't propagate CreatePuppet to "+sr.busDomain);
}
}
} else if ((m=fwdGhost.matcher(msg)).matches()) {
System.out.println("PM forwarding ["+msg+"] to its Ghost");
SubReader sr = ghostFathers.get(m.group(1));
sr.send(msg);
} else if ((m=fwdPuppet.matcher(msg)).matches()) {
System.out.println("PM forwarding ["+msg+"] to all other PCs");
for (Enumeratione=proxyClients.elements();e.hasMoreElements();) {
SubReader sr = e.nextElement();
if (sr!=SubReader.this) sr.send(msg);
}
} else {
System.out.println("error unknown message "+msg);
}
}
} // class SubReader
private static void traceDebug(String s){
if (debug) System.out.println("-->ProxyMaster "+name+"<-- "+s);
}
}