diff options
-rw-r--r-- | BUGS | 5 | ||||
-rw-r--r-- | Changelog | 15 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rwxr-xr-x | src/Ivy.java | 17 | ||||
-rwxr-xr-x | src/IvyClient.java | 17 | ||||
-rwxr-xr-x | src/IvyWatcher.java | 53 | ||||
-rw-r--r-- | src/Makefile | 18 | ||||
-rw-r--r-- | src/Probe.java | 33 | ||||
-rw-r--r-- | src/SelfIvyClient.java | 6 | ||||
-rw-r--r-- | src/Waiter.java | 2 | ||||
-rw-r--r-- | src/WaiterClient.java | 2 |
11 files changed, 130 insertions, 40 deletions
@@ -100,6 +100,11 @@ réf: [BUGXY] ------------------------------------------------------------------------------------- Fixed: +1.2.7 + + réf: none, unbind déconnait (Mathieu Raynal) + réf: none, bug perl implementation (Jean Paul) + 1.2.4 réf: [BUG J007] incorrect handling of faulty remote Ivy agents @@ -1,4 +1,19 @@ -------------------------------------------------------------------- +1.2.7 + + bugfixes + - no more the infamous unBindMsg() reported by Matthieu + - *complex* algorithm to disallow multiple instances of the same agent + when launched with multiple broadcast addresses, some of them being + received twice by a remote agent X, X trying to connect twice ... + It should fix both Francis's WiFi bugreport, and Jean-Paul Stress' bug + + new features + - Probe allows .where .dieall-yes-i-am-sure .bound and .bound CLIENT + + code cleanup + - minor fixes for acecssing static final values +-------------------------------------------------------------------- 1.2.6 documentation @@ -1,5 +1,5 @@ # Be sure to set this before compiling ... - VER = 1.2.6 + VER = 1.2.7 DIST = lib/ivy-java-$(VER).jar DOCS = doc/html/api #JAR = fastjar # jar fails with kaffe on woody diff --git a/src/Ivy.java b/src/Ivy.java index 196c3b4..3236ba4 100755 --- a/src/Ivy.java +++ b/src/Ivy.java @@ -13,6 +13,8 @@ *</pre> * * CHANGELOG: + * 1.2.7: + * - minor fixes for accessing static final values * 1.2.6: * - added serial numbers for traceDebug * - changed the semantic of -b a,b:port,c:otherport if no port is @@ -93,11 +95,11 @@ public class Ivy implements Runnable { * the library version, useful for development purposes only, when java is * invoked with -DIVY_DEBUG */ - public static final String libVersion ="1.2.6"; + public static final String libVersion ="1.2.7"; private boolean debug; private ServerSocket app; - private Vector watchers; + private Vector watchers = new Vector(); private volatile Thread serverThread; // to ensure quick communication of the end private Hashtable clients = new Hashtable(); private Hashtable half = new Hashtable(); @@ -200,14 +202,11 @@ public class Ivy implements Runnable { throw new IvyException("can't open TCP service socket " + e ); } traceDebug("lib: "+libVersion+" protocol: "+PROTOCOLVERSION+" TCP service open on port "+applicationPort); - watchers = new Vector(); Domain[] d = parseDomains(domainbus); // readies the rendezvous : an IvyWatcher (thread) per domain bus - for (int index=0;index<d.length;index++){ - IvyWatcher watcher =new IvyWatcher(this,d[index].domainaddr,d[index].port); - watchers.addElement(watcher); - } + for (int index=0;index<d.length;index++) + watchers.addElement(new IvyWatcher(this,d[index].domainaddr,d[index].port)); serverThread = new Thread(this); serverThread.start(); // sends the broadcasts and listen to incoming connexions @@ -403,9 +402,7 @@ public class Ivy implements Runnable { * whenever an exception occured during unbinding * @param String the string for the regular expression */ - public boolean unBindMsg(String re) { - return selfIvyClient.unBindMsg(re); - } + public boolean unBindMsg(String re) { return selfIvyClient.unBindMsg(re); } /** * adds a bind listener to a bus diff --git a/src/IvyClient.java b/src/IvyClient.java index 753184a..a53e398 100755 --- a/src/IvyClient.java +++ b/src/IvyClient.java @@ -100,6 +100,7 @@ public class IvyClient implements Runnable { private volatile Thread clientThread;// volatile to ensure the quick communication private Integer clientKey; private boolean discCallbackPerformed = false; + private String remoteHostname="unresolved"; // protected variables String appName="none"; @@ -133,6 +134,7 @@ public class IvyClient implements Runnable { // the registering will take place at the reception of the regexps... } } + remoteHostname = socket.getInetAddress().getHostName(); clientThread = new Thread(this); // clientThread handles the incoming traffic clientThread.start(); } @@ -170,6 +172,12 @@ public class IvyClient implements Runnable { public String getApplicationName() { return appName ; } /** + * returns the host name of the remote agent. + * @since 1.2.7 + */ + public String getHostName() { return remoteHostname ; } + + /** * allow an Ivy package class to access the list of regexps at a * given time. * perhaps we should implement a new IvyApplicationListener method to @@ -339,6 +347,7 @@ public class IvyClient implements Runnable { } } traceDebug("normally Disconnected from "+ appName); + bus.removeClient(this); // invokes the disconnect applicationListeners if (!discCallbackPerformed) bus.clientDisconnects(this); discCallbackPerformed=true; @@ -391,15 +400,15 @@ public class IvyClient implements Runnable { private String dumpHex(String s) { byte[] b = s.getBytes(); - String out = ""; + String outDump = ""; String zu = "\t"; for (int i=0;i<b.length;i++) { char c = s.charAt(i); - out+=((int)c) + " "; + outDump+=((int)c) + " "; zu+= ((c>15) ? c : 'X')+" "; } - out += zu; - return out; + outDump += zu; + return outDump; } private String dumpMsg(String s) { diff --git a/src/IvyWatcher.java b/src/IvyWatcher.java index 3ac5ef9..5009c03 100755 --- a/src/IvyWatcher.java +++ b/src/IvyWatcher.java @@ -14,6 +14,10 @@ * thing. * * CHANGELOG: + * 1.2.7: + * - better handling of multiple connexions from the same remote agent when + * there are different broadcast addresses ( introduced the alreadyBroadcasted + * function ) * 1.2.6: * - IOException now goes silent when we asked the bus to stop() * - use a new buffer for each Datagram received, to prevent an old bug @@ -60,13 +64,14 @@ import java.net.*; import java.io.*; import java.util.StringTokenizer; import org.apache.regexp.*; +import java.util.Hashtable; import java.util.Vector; import java.util.Enumeration; class IvyWatcher implements Runnable { private static boolean debug = (System.getProperty("IVY_DEBUG")!=null); private boolean isMulticastAddress = false; - private Ivy bus; /* master bus controler */ + private Ivy bus; /* master bus controler */ private DatagramSocket broadcast; /* supervision socket */ private InetAddress localhost,loopback; private String domainaddr; @@ -112,6 +117,7 @@ class IvyWatcher implements Runnable { traceDebug("beginning of a watcher Thread"); InetAddress remotehost=null; try { + int remotePort=0; while( listenThread==thisThread ) { try { byte buf[] = new byte[256]; @@ -130,26 +136,33 @@ class IvyWatcher implements Runnable { continue; } int version = Integer.parseInt(re.getParen(1)); - if ( version < bus.PROTOCOLMINIMUM ) { + if ( version < Ivy.PROTOCOLMINIMUM ) { System.err.println("Ignoring bad format broadcast from "+ remotehostname+":"+packet.getPort() - +" protocol version "+remotehost+" we need "+bus.PROTOCOLMINIMUM+" minimum"); + +" protocol version "+remotehost+" we need "+Ivy.PROTOCOLMINIMUM+" minimum"); continue; } - int port = Integer.parseInt(re.getParen(2)); - if (bus.applicationPort==port) { + remotePort = Integer.parseInt(re.getParen(2)); + if (bus.applicationPort==remotePort) { traceDebug("ignoring a broadcast from "+ remotehostname+":"+packet.getPort() - +" on my port number ("+port+"), it's probably me"); + +" on my port number ("+remotePort+"), it's probably me"); // TODO check better - // if bus.applicationPort=port + // if bus.applicationPort=remotePort // parse the list of Watchers and check for each // iw.broadcast.getInetAddress().equals(packet().getAddress() // if one is true, "continue" ( ignore the broadcast ) continue; } traceDebug("broadcast accepted from " +remotehostname - +":"+packet.getPort()+", port:"+port+", protocol version:"+version); - new IvyClient(bus,new Socket(remotehost,port),port); + +":"+packet.getPort()+", port:"+remotePort+", protocol version:"+version); + // 1.2.7 ? TODO two connexions from the same host on different broadcast + // addresses (e.g. sam simu) + if (!alreadyBroadcasted(remotehost.toString(),remotePort)) { + traceDebug("no known agent originating from " + remotehost + ":" + remotePort); + new IvyClient(bus,new Socket(remotehost,remotePort),remotePort); + } else { + traceDebug("there is already a request originating from " + remotehost + ":" + remotePort); + } } catch (RESyntaxException ree) { ree.printStackTrace(); System.exit(-1); @@ -159,7 +172,8 @@ class IvyWatcher implements Runnable { } catch ( UnknownHostException e ) { System.err.println("Unkonwn host "+remotehost +","+e.getMessage()); } catch ( IOException e) { - System.err.println("can't connect to "+remotehost+" port "+ port+e.getMessage()); + System.err.println("can't connect to "+remotehost+" port "+ remotePort+e.getMessage()); + e.printStackTrace(); } } catch (InterruptedIOException jii ){ if (thisThread!=listenThread) { break ;} @@ -188,6 +202,7 @@ class IvyWatcher implements Runnable { } private class PacketSender implements Runnable { + // TODO do I need multiple packetsenders ? DatagramPacket packet; String data; public PacketSender(String data) { @@ -216,13 +231,28 @@ class IvyWatcher implements Runnable { } synchronized void start() throws IvyException { - String hello = bus.PROTOCOLVERSION + " " + bus.applicationPort + "\n"; + String hello = Ivy.PROTOCOLVERSION + " " + bus.applicationPort + "\n"; if (broadcast==null) throw new IvyException("IvyWatcher PacketSender null broadcast address"); new PacketSender(hello); // notifies our arrival on each domain: protocol version + port listenThread.start(); } /* + * since 1.2.7 pre .... + * checks if there is already a broadcast received from the same address + * on the same port + */ + static private Hashtable alreadySocks=new Hashtable(); + static private synchronized boolean alreadyBroadcasted(String s,int port) { + // System.out.println("DEBUUUUUUUG " + s+ ":" + port); + if (s==null) return false; + Integer i = (Integer)alreadySocks.get(s); + if (((i!=null)&&(i.compareTo(new Integer(port)))==0)) return true; + alreadySocks.put(s,new Integer(port)); + return false; + } + + /* private boolean isInDomain( InetAddress host ){ return true; // TODO check if this function is useful. for now, it always returns true @@ -282,5 +312,4 @@ class IvyWatcher implements Runnable { if (debug) System.out.println("-->IvyWatcher["+myserial+","+bus.getSerial()+"]<-- "+s); } - } // class IvyWatcher diff --git a/src/Makefile b/src/Makefile index 592df31..9815906 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,14 +1,14 @@ -#GNUPATH=/usr/share/java/gnu-getopt.jar:/usr/share/java/regexp.jar # debian SID -GNUPATH=/usr/lib/jdk1.1/lib/classes.zip:/usr/share/java/gnu.getopt.jar:/usr/share/java/regexp.jar # debian woody +GNUPATH=/usr/share/java/gnu-getopt.jar:/usr/share/java/regexp.jar # debian SID +#GNUPATH=/usr/lib/jdk1.1/lib/classes.zip:/usr/share/java/gnu.getopt.jar:/usr/share/java/regexp.jar # debian woody #GNUPATH=${HOME}/java/jars/gnu-getopt.jar:${HOME}/java/jars/regexp.jar #GNUPATH=../bundle ####################################### # generic setup ####################################### - JAVAC = javac -JAVACOPTS = -d . -deprecation -CLASSPATH = -classpath .:$(GNUPATH) +# JAVAC = javac +#JAVACOPTS = -d . -deprecation +#CLASSPATH = -classpath .:$(GNUPATH) ####################################### # gcj setup @@ -20,10 +20,10 @@ CLASSPATH = -classpath .:$(GNUPATH) ####################################### # jikes setup on my box ####################################### -# RTPATH = /usr/lib/j2se/1.4/jre/lib/rt.jar -#JAVACOPTS = -d . -deprecation -# JAVAC = jikes -#CLASSPATH = -classpath .:$(RTPATH):$(GNUPATH) + RTPATH = /usr/local/jdk1.5.0/jre/lib/rt.jar +JAVACOPTS = -d . -deprecation + JAVAC = jikes +CLASSPATH = -classpath .:$(RTPATH):$(GNUPATH) ####################################### # blackdown jdk118 setup diff --git a/src/Probe.java b/src/Probe.java index e086560..be56d35 100644 --- a/src/Probe.java +++ b/src/Probe.java @@ -7,6 +7,10 @@ * (c) CENA * * Changelog: + * 1.2.7 + * - added a .where function + * - added a .bound function + * - added a .dieall-yes-i-am-sure function * 1.2.6 * - no more java ping * 1.2.5 @@ -49,7 +53,7 @@ import org.apache.regexp.*; public class Probe implements IvyApplicationListener, IvyMessageListener, IvyBindListener, Runnable { - public static final String helpCommands = "Available commands:\n.die CLIENTNAME sends a die message\n.direct CLIENTNAME ID MESSAGE sends the direct message to the client, with a message id set to the numerical ID\n.bye quits the application\n.quit idem\n.list lists the available clients\n.bind REGEXP binds to a regexp at runtime\n.unbind REGEXP unbinds to a regexp at runtime"; + public static final String helpCommands = "Available commands:\n.die CLIENT\t\t\t* sends a die message\n.dieall-yes-i-am-sure\t\t* sends a die to all clients\n.direct CLIENT ID MSG\t\t* sends the direct message to the client\n.bye\t\t\t\t* quits the probe\n.quit\t\t\t\t* quites the probe\n.list\t\t\t\t* lists the clients on the bus\n.bind REGEXP\t\t\t* subscribes to a regexp\n.unbind REGEXP\t\t\t* unsubscribes to a regexp\n.bound CLIENT\t\t\t* lists the subscriptions of a client\n.bound\t\t\t\t* lists the probe's subscriptions\n.where CLIENT\t\t\t* displays the host where a client runs"; public static final String helpmsg = "usage: java fr.dgac.ivy.Probe [options] [regexp]\n\t-b BUS\tspecifies the Ivy bus domain\n\t-n ivyname (default JPROBE)\n\t-q\tquiet, no tty output\n\t-d\tdebug\n\t-t\ttime stamp each message\n\t-s\tsends to self\n\t-h\thelp\n\n\t regexp is a Perl5 compatible regular expression"; @@ -127,6 +131,7 @@ public class Probe implements IvyApplicationListener, IvyMessageListener, IvyBin traceDebug("Thread started"); Thread thisThread=Thread.currentThread(); String s; + println("probe ready, type .help and return to get help"); // "infinite" loop on keyboard input while (looperThread==thisThread) { try { @@ -167,6 +172,9 @@ public class Probe implements IvyApplicationListener, IvyMessageListener, IvyBin println("-> not sent, the message contains incorrect characters"); } return; + } else if (s.lastIndexOf(".dieall-yes-i-am-sure")>=0){ + Vector v=bus.getIvyClients(); + for (int i=0;i<v.size();i++) ((IvyClient)v.elementAt(i)).sendDie("java probe wants you to leave the bus"); } else if (s.lastIndexOf(".die ")>=0){ String target=s.substring(5); Vector v=bus.getIvyClientsByName(target); @@ -179,6 +187,22 @@ public class Probe implements IvyApplicationListener, IvyMessageListener, IvyBin } else { println("you can't unsubscribe to " + regexp + ", your're not subscribed to it"); } + } else if (s.lastIndexOf(".bound ")>=0){ + String target=s.substring(7); + Vector v=bus.getIvyClientsByName(target); + if (v.size()==0) println("no Ivy client with the name \""+target+"\""); + for (int i=0;i<v.size();i++) { + IvyClient ic=(IvyClient)v.elementAt(i); + println(target+" has subscribed to:"); + for (Enumeration e = ic.getRegexps();e.hasMoreElements();) { + println("\t"+(String)e.nextElement()); + } + } + } else if (s.lastIndexOf(".bound")>=0){ + println("you have subscribed to:"); + for (Enumeration e = bus.getSelfIvyClient().getRegexps();e.hasMoreElements();) { + println("\t"+(String)e.nextElement()); + } } else if (s.lastIndexOf(".bind ")>=0){ String regexp=s.substring(6); try { @@ -196,6 +220,13 @@ public class Probe implements IvyApplicationListener, IvyMessageListener, IvyBin for (int i=0;i<v.size();i++) { println("-> "+((IvyClient)v.elementAt(i)).getApplicationName()); } + } else if ( s.lastIndexOf(".where ")>=0) { + String target=s.substring(7); + Vector v=bus.getIvyClientsByName(target); + if (v.size()==0) println("no Ivy client with the name \""+target+"\""); + for (int i=0;i<v.size();i++) { + println(target+" runs on "+((IvyClient)v.elementAt(i)).getHostName()); + } } else if ( s.lastIndexOf(".help")>=0) { println(helpCommands); } else if ( s.charAt(0)=='.') { diff --git a/src/SelfIvyClient.java b/src/SelfIvyClient.java index a96e0d2..acd2d66 100644 --- a/src/SelfIvyClient.java +++ b/src/SelfIvyClient.java @@ -6,6 +6,8 @@ * @since 1.2.4 * * CHANGELOG: + * 1.2.7: + * - fixes a bug on unbindMsg(String) ( closes Matthieu's burreport ) * 1.2.6: * - jakarta regexp are not threadsafe, adding extra synch blocks * 1.2.5: @@ -63,10 +65,12 @@ class SelfIvyClient extends IvyClient { throw new IvyException("client wants to remove an unexistant regexp "+id); } + // unbinds to the first regexp synchronized protected boolean unBindMsg(String re) { + if (!regexpsText.contains(re)) return false; for (Enumeration e=regexpsText.keys();e.hasMoreElements();) { Integer k = (Integer)e.nextElement(); - if ( ((String)regexps.get(k)).compareTo(re) == 0) { + if ( ((String)regexpsText.get(k)).compareTo(re) == 0) { try { bus.unBindMsg(k.intValue()); } catch (IvyException ie) { diff --git a/src/Waiter.java b/src/Waiter.java index c4eb29b..8db6980 100644 --- a/src/Waiter.java +++ b/src/Waiter.java @@ -33,7 +33,7 @@ class Waiter implements Runnable, IvyMessageListener { // System.out.println("DEV Waiter start"); while (encore) { try { - t.sleep(INCREMENT); + Thread.sleep(INCREMENT); if (!forever) { timeout-=INCREMENT; if (timeout<=0) encore=false; diff --git a/src/WaiterClient.java b/src/WaiterClient.java index 931a048..0c75777 100644 --- a/src/WaiterClient.java +++ b/src/WaiterClient.java @@ -35,7 +35,7 @@ class WaiterClient extends IvyApplicationAdapter implements Runnable { // System.out.println("DEV WaiterClient start"); while (encore) { try { - t.sleep(INCREMENT); + Thread.sleep(INCREMENT); if (!forever) { timeout-=INCREMENT; if (timeout<=0) encore=false; |