aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUGS5
-rw-r--r--Changelog15
-rw-r--r--Makefile2
-rwxr-xr-xsrc/Ivy.java17
-rwxr-xr-xsrc/IvyClient.java17
-rwxr-xr-xsrc/IvyWatcher.java53
-rw-r--r--src/Makefile18
-rw-r--r--src/Probe.java33
-rw-r--r--src/SelfIvyClient.java6
-rw-r--r--src/Waiter.java2
-rw-r--r--src/WaiterClient.java2
11 files changed, 130 insertions, 40 deletions
diff --git a/BUGS b/BUGS
index fee8430..ad63254 100644
--- a/BUGS
+++ b/BUGS
@@ -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
diff --git a/Changelog b/Changelog
index 8a920e7..02db532 100644
--- a/Changelog
+++ b/Changelog
@@ -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
diff --git a/Makefile b/Makefile
index 539bacc..a85d8ed 100644
--- a/Makefile
+++ b/Makefile
@@ -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;