From: kbaati
This method *must* be called after every call of {@link #removeNeighbor} + * in {@link #processEvent}. + *
+ */ + private void processNeighborListSize(Node node, int pid) { + if (nNodes==20) { + Object ev; + long latency; + ev = new SimpleMsg(TRACKER, node); + Node tracker = ((BitTorrent)node.getProtocol(pid)).tracker; + if(tracker != null){ +// latency = ((Transport)node.getProtocol(tid)).getLatency(node, tracker); +// EDSimulator.add(latency,ev,tracker,pid); + ((Transport) node.getProtocol(tid)).send(node, tracker, ev, pid); + } + } + } + + /** + * The standard method that processes incoming events. + * @param node reference to the local node for which the event is going to be processed + * @param pid BitTorrent's protocol id + * @param event the event to process + */ + public void processEvent(Node node, int pid, Object event){ + + Object ev; + long latency; + switch(((SimpleEvent)event).getType()){ + + case KEEP_ALIVE: // 1 + { + Node sender = ((IntMsg)event).getSender(); + int isResponse = ((IntMsg)event).getInt(); + //System.out.println("process, keep_alive: sender is "+sender.getID()+", local is "+node.getID()); + Element e = search(sender.getID()); + if(e!= null){ //if I know the sender + cache[e.peer].isAlive(); + if(isResponse==0 && alive(sender)){ + Object msg = new IntMsg(KEEP_ALIVE,node,1,0); +// latency = ((Transport)node.getProtocol(tid)).getLatency(node, sender); +// EDSimulator.add(latency,msg,sender,pid); + ((Transport) node.getProtocol(tid)).send(node, sender, msg, pid); + cache[e.peer].justSent(); + } + } + else{ + System.err.println("despite it should never happen, it happened"); + ev = new BitfieldMsg(BITFIELD, true, false, node, status, nPieces); +// latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender); +// EDSimulator.add(latency,ev,sender,pid); + ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid); + nBitfieldSent++; + } + + };break; + + case CHOKE: // 2, CHOKE message. + { + Node sender = ((SimpleMsg)event).getSender(); + //System.out.println("process, choke: sender is "+sender.getID()+", local is "+node.getID()); + Element e = search(sender.getID()); + if(e!= null){ //if I know the sender + cache[e.peer].isAlive(); + unchokedBy[e.peer]= false; // I'm choked by it + } + else{ + System.err.println("despite it should never happen, it happened"); + ev = new BitfieldMsg(BITFIELD, true, false, node, status, nPieces); +// latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender); +// EDSimulator.add(latency,ev,sender,pid); + ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid); + nBitfieldSent++; + } + };break; + + case UNCHOKE: // 3, UNCHOKE message. + { + Node sender = ((SimpleMsg)event).getSender(); + //System.out.println("process, unchoke: sender is "+sender.getID()+", local is "+node.getID()); + Element e = search(sender.getID()); + if(e != null){ // If I know the sender + int senderIndex = e.peer; + cache[senderIndex].isAlive(); + /* I send to it some of the pending requests not yet satisfied. */ + int t = numberOfDuplicatedRequests; + for(int i=4;i>=0 && t>0;i--){ + if(pendingRequest[i]==-1) + break; + if(alive(cache[senderIndex].node) && swarm[senderIndex][decode(pendingRequest[i],0)]==1){ //If the sender has that piece + ev = new IntMsg(REQUEST, node,pendingRequest[i],0); +// latency = ((Transport)node.getProtocol(tid)).getLatency(node,sender); +// EDSimulator.add(latency,ev, sender,pid); + ((Transport) node.getProtocol(tid)).send(node, sender, ev, pid); + cache[senderIndex].justSent(); + } + if(!alive(cache[senderIndex].node)){ + System.out.println("unchoke1 rm neigh "+ cache[i].node.getID() ); + removeNeighbor(cache[senderIndex].node); + processNeighborListSize(node,pid); + return; + } + t--; + } + // I request missing blocks to fill the queue + int block = getBlock(); + int piece; + while(block != -2){ //while still available request to send + if(block < 0){ // No more block to request for the current piece + piece = getPiece(); + if(piece == -1){ // no more piece to request + break; + } + for(int j=0; jThe ACK value used to implement ack and nack messages.
+ *It has value true if the message is a reponse and the sender has inserted
+ * the receiver in its own cache of neighbors.
+ * If for some reason (for instance the cache had already 80 peer inside at the moment of the
+ * request) it was not possible to insert the peer, the value is false.
+ * It has value false also if the message is a request and is sent when occours
+ * an unespected message.
+ *
+ * The allowed bandwidth speed are 640 Kbps, 1 Mbps, 2 Mbps and 4 Mbps. + *
+ * @param p The BitTorrent protocol + */ + private void setBandwidth(BitTorrent p){ + int value = CommonState.r.nextInt(4); + switch(value){ + case 0: p.setBandwidth(640);break; //640Kbps + case 1: p.setBandwidth(1024);break;// 1Mbps + case 2: p.setBandwidth(2048);break;// 2Mbps + case 3: p.setBandwidth(4096);break; //4Mbps + } + } + + /** + * Sets the completed pieces for the given protocol p. + * @parm percentage The percentage of the downloaded pieces, according to {@link #getProbability()} + * @param p the BitTorrent protocol + */ + private void choosePieces(int percentage, BitTorrent p){ + double temp = ((double)p.nPieces/100.0)*percentage; // We use a double to avoid the loss of precision + // during the division operation + int completed = (int)temp; //integer number of piece to set as completed + //0 if the peer is a newer + p.setCompleted(completed); + if(percentage == 100) + p.setPeerStatus(1); + int tmp; + while(completed!=0){ + tmp = CommonState.r.nextInt(p.nPieces); + if(p.getStatus(tmp)!=16){ + p.setStatus(tmp, 16); + completed--; + } + } + } + + /** + * Gets a probability according with the parameter newer_distr + * defined in the configuration file. + * @return the probabilty value, where 0 means that the peer is new and no pieces has been downloaded, + * 100 means that the peer is a seeder; other values defines a random probability. + * @see #PAR_NEWER_DISTR + */ + private int getProbability(){ + int value = CommonState.r.nextInt(100); + if((value+1)<=seederDistr) + return 100; + value = CommonState.r.nextInt(100); + if((value+1)<=newerDistr){ + return 0; // A newer peer, with probability newer_distr + } + else{ + value = CommonState.r.nextInt(9); + return (value+1)*10; + } + } +} \ No newline at end of file diff --git a/contrib/psg/src/example/bittorrent/PeerSetMsg.java b/contrib/psg/src/example/bittorrent/PeerSetMsg.java new file mode 100644 index 0000000000..d0e92d56ff --- /dev/null +++ b/contrib/psg/src/example/bittorrent/PeerSetMsg.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2007-2008 Fabrizio Frioli, Michele Pedrolli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * -- + * + * Please send your questions/suggestions to: + * {fabrizio.frioli, michele.pedrolli} at studenti dot unitn dot it + * + */ +package example.bittorrent; + +import peersim.core.*; + +/** + * This class is a {@link SimpleMsg} and represents the peerset + * message used by the tracker to send to the peers a list of neighbors. + */ +public class PeerSetMsg extends SimpleMsg{ + + /** + * The set of "friends" peers sent by the tracker to each node. + */ + private Neighbor[] peerSet; + + /** + * Initializes a new peerset message. + * @param type is the type of the message (it should be 12) + * @param array is the array containing the references to the neighbor nodes + * @param sender the sender node + * @see SimpleEvent + */ + public PeerSetMsg(int type, Neighbor []array, Node sender){ + super.type = type; + peerSet = array; // references to the effective nodes + super.sender = sender; + } + + /** + * Gets the peer set. + * @return the peer set, namely the set of neighbor nodes. + */ + public Neighbor[] getPeerSet(){ + return this.peerSet; + } +} diff --git a/contrib/psg/src/example/bittorrent/SimpleEvent.java b/contrib/psg/src/example/bittorrent/SimpleEvent.java new file mode 100644 index 0000000000..1da537ac00 --- /dev/null +++ b/contrib/psg/src/example/bittorrent/SimpleEvent.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2007-2008 Fabrizio Frioli, Michele Pedrolli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * -- + * + * Please send your questions/suggestions to: + * {fabrizio.frioli, michele.pedrolli} at studenti dot unitn dot it + * + */ + +package example.bittorrent; + +/** + * This class defines a simple event. A simple event is characterized only + * by its type. + */ +public class SimpleEvent { + + /** + * The identifier of the type of the event. + *
+ * The available identifiers for event type are:
+ *
+ * Loading the configuration is currently done with the help of constructing
+ * an instance of {@link ParsedProperties} using the constructor
+ * {@link ParsedProperties#ParsedProperties(String[])}. The parameter
+ * args
is simply passed to this class. This class is then used
+ * to initialize the configuration.
+ *
+ * After loading the configuration, the experiments are run by invoking the + * appropriate engine, which is identified as follows: + *
+ * This list represents the order in which these alternatives are checked. + * That is, if more than one return true, then the first will be taken. Note + * that this class checks only for these clues and does not check if the + * configuration is consistent or valid. + * + * @param args + * passed on to + * {@link ParsedProperties#ParsedProperties(String[])} + * @throws InterruptedException + * @throws HostNotFoundException + * @see ParsedProperties + * @see Configuration + * @see CDSimulator + * @see EDSimulator + */ + public static void main(String[] args) throws InterruptedException, + HostNotFoundException { + long time = System.currentTimeMillis(); + long start; + System.err.println("Simulator: loading configuration"); + Configuration.setConfig(new ParsedProperties(args)); + PrintStream newout = (PrintStream) Configuration.getInstance( + PAR_REDIRECT, System.out); + if (newout != System.out) + System.setOut(newout); + + int exps = Configuration.getInt(PAR_EXPS, 1); + final int SIMID = getSimID(); + if (SIMID == UNKNOWN) { + System.err + .println("Simulator: unable to determine simulation engine type"); + return; + } + + try { + + for (int k = 0; k < exps; ++k) { + if (k > 0) { + long seed = CommonState.r.nextLong(); + CommonState.initializeRandom(seed); + } + System.err.print("Simulator: starting experiment " + k); + System.err.println(" invoking " + simName[SIMID]); + System.err.println("Random seed: " + + CommonState.r.getLastSeed()); + // XXX could be done through reflection, but + // this is easier to read. + + switch (SIMID) { + case CDSIM: + CDSimulator.nextExperiment(); + break; + case EDSIM: + log("ps"); + start = System.currentTimeMillis(); + EDSimulator.nextExperiment(); + System.err.print("Duration of Simulation in ps:" + + (System.currentTimeMillis() - start) + " ms\n"); + break; + case PSGSIM: + try { + log("psg"); + start = System.currentTimeMillis(); + PSGSimulator.main(); + System.err.print("Duration of Simulation in psg:" + + (System.currentTimeMillis() - start) + + " ms\n"); + } catch (NativeException e) { + System.err + .println("***********Native exception***************"); + e.printStackTrace(); + } + break; + } + } + + } catch (MissingParameterException e) { + System.err.println(e + ""); + System.exit(1); + } catch (IllegalParameterException e) { + System.err.println(e + ""); + System.exit(1); + } + + // undocumented testing capabilities + if (Configuration.contains("__t")) + System.out.println(System.currentTimeMillis() - time); + if (Configuration.contains("__x")) + Network.test(); + + } + + /** + * + * @param sim + */ + public static void log(String sim) { + String propName = "OutputName"; + + /** le nom de l'OS */ + final String OS_NAME = System.getProperty("os.name"); + File file = null; + String prot = Configuration.getString(propName, "null"); + if (prot.contentEquals("null")) { + System.err.println("OutputName parameter not defined"); + } else { + if ("Linux".equals(OS_NAME) || "Mac".equals(OS_NAME)) { + if (!new File("outputs" + prot).exists()) { + new File("outputs/" + prot).mkdirs(); + } + String path = "outputs/" + prot + "/"; + file = new File(path + sim + ".txt"); + } else { + if (!new File("outputs" + prot).exists()) + new File("outputs\\" + prot).mkdirs(); + String path = "outputs\\" + prot + "\\"; + file = new File(path + sim + ".txt"); + } + try { + PrintStream printStream = new PrintStream(file); + System.setOut(printStream); + // System.setErr(printStream); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + + } + +} diff --git a/contrib/psg/src/peersim/cdsim/CDProtocol.java b/contrib/psg/src/peersim/cdsim/CDProtocol.java new file mode 100644 index 0000000000..c0d2f0de66 --- /dev/null +++ b/contrib/psg/src/peersim/cdsim/CDProtocol.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2003-2005 The BISON Project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +package peersim.cdsim; + +import peersim.core.Protocol; +import peersim.core.Node; + +/** +* Defines cycle driven protocols, that is, protocols that have a periodic +* activity in regular time intervals. +*/ +public interface CDProtocol extends Protocol +{ + +/** + * A protocol which is defined by performing an algorithm in more or less + * regular periodic intervals. + * This method is called by the simulator engine once in each cycle with + * the appropriate parameters. + * + * @param node + * the node on which this component is run + * @param protocolID + * the id of this protocol in the protocol array + */ +public void nextCycle(Node node, int protocolID); + +} diff --git a/contrib/psg/src/peersim/cdsim/CDSimulator.java b/contrib/psg/src/peersim/cdsim/CDSimulator.java new file mode 100644 index 0000000000..f4875949ee --- /dev/null +++ b/contrib/psg/src/peersim/cdsim/CDSimulator.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2003-2005 The BISON Project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +package peersim.cdsim; + +import java.util.*; +import peersim.config.*; +import peersim.core.*; + +/** + * This is the cycle driven simulation engine. It is a fully static + * singleton class. For a cycle driven simulation the configuration can + * describe a set of {@link Protocol}s, and their ordering, a set of + * {@link Control}s and their ordering and a set of initializers and their + * ordering. See parameters {@value #PAR_INIT}, {@value #PAR_CTRL}. Out + * of the set of protocols, this engine only executes the ones that + * implement the {@link CDProtocol} interface. + *
+ * One experiment run by {@link #nextExperiment} works as follows. First + * the initializers are run in the specified order, then the following is + * iterated {@value #PAR_CYCLES} times: If {@value #PAR_NOMAIN} is + * specified, then simply the controls specified in the configuration are + * run in the specified order. If {@value #PAR_NOMAIN} is not specified, + * then the controls in the configuration are run in the specified order, + * followed by the execution of {@link FullNextCycle}. + *
+ * All components (controls and protocols) can have configuration + * parameters that control their scheduling (see {@link Scheduler}). This + * way they can skip cycles, start from a specified cycle, etc. As a + * special case, components can be scheduled to run after the last cycle. + * That is, each experiment is finished by running the controls that are + * scheduled after the last cycle. + *
+ * Finally, any control can interrupt an experiment at any time it is
+ * executed by returning true in method {@link Control#execute}. However,
+ * the controls scheduled to run after the last cycle are still executed
+ * completely, irrespective of their return value and even if the
+ * experiment was interrupted.
+ * @see Configuration
+ */
+public class CDSimulator
+{
+
+// ============== fields ===============================================
+// =====================================================================
+
+/**
+ * Parameter representing the maximum number of cycles to be performed
+ * @config
+ */
+public static final String PAR_CYCLES = "simulation.cycles";
+
+/**
+ * This option is only for experts. It switches off the main cycle that
+ * calls the cycle driven protocols. When you switch this off, you need to
+ * control the execution of the protocols by configuring controls that do
+ * the job (e.g., {@link FullNextCycle}, {@link NextCycle}). It's there for
+ * people who want maximal flexibility for their hacks.
+ * @config
+ */
+private static final String PAR_NOMAIN = "simulation.nodefaultcycle";
+
+/**
+ * This is the prefix for initializers. These have to be of type
+ * {@link Control}. They are run at the beginning of each experiment, in
+ * the order specified by the configuration.
+ * @see Configuration
+ * @config
+ */
+private static final String PAR_INIT = "init";
+
+/**
+ * This is the prefix for controls. These have to be of type
+ * {@link Control}. They are run before each cycle, in the order specified
+ * by the configuration.
+ * @see Configuration
+ * @config
+ */
+private static final String PAR_CTRL = "control";
+
+// --------------------------------------------------------------------
+
+/** The maximum number of cycles to be performed */
+private static int cycles;
+
+/** holds the modifiers of this simulation */
+private static Control[] controls = null;
+
+/** Holds the control schedulers of this simulation */
+private static Scheduler[] ctrlSchedules = null;
+
+// =============== initialization ======================================
+// =====================================================================
+
+/** to prevent construction */
+private CDSimulator()
+{
+}
+
+// =============== private methods =====================================
+// =====================================================================
+
+/**
+ * Load and run initializers.
+ */
+private static void runInitializers()
+{
+
+ Object[] inits = Configuration.getInstanceArray(PAR_INIT);
+ String names[] = Configuration.getNames(PAR_INIT);
+
+ for (int i = 0; i < inits.length; ++i) {
+ System.err.println("- Running initializer " + names[i] + ": "
+ + inits[i].getClass());
+ ((Control) inits[i]).execute();
+ }
+}
+
+// --------------------------------------------------------------------
+
+private static String[] loadControls()
+{
+
+ boolean nomaincycle = Configuration.contains(PAR_NOMAIN);
+ String[] names = Configuration.getNames(PAR_CTRL);
+ if (nomaincycle) {
+ controls = new Control[names.length];
+ ctrlSchedules = new Scheduler[names.length];
+ } else {
+ // provide for an extra control that handles the main cycle
+ controls = new Control[names.length + 1];
+ ctrlSchedules = new Scheduler[names.length + 1];
+ // calling with a prefix that cannot exist
+ controls[names.length] = new FullNextCycle(" ");
+ ctrlSchedules[names.length] = new Scheduler(" ");
+ }
+ for (int i = 0; i < names.length; ++i) {
+ controls[i] = (Control) Configuration.getInstance(names[i]);
+ ctrlSchedules[i] = new Scheduler(names[i]);
+ }
+ System.err.println("CDSimulator: loaded controls " + Arrays.asList(names));
+ return names;
+}
+
+// ---------------------------------------------------------------------
+
+/**
+ * This method is used to check whether the current configuration can be
+ * used for cycle-driven simulations. It checks for the existence of
+ * configuration parameter {@value #PAR_CYCLES}.
+ */
+public static final boolean isConfigurationCycleDriven()
+{
+ return Configuration.contains(PAR_CYCLES);
+}
+
+// ---------------------------------------------------------------------
+
+/**
+ * Runs an experiment, resetting everything except the random seed.
+ */
+public static final void nextExperiment()
+{
+
+ // Reading parameter
+ cycles = Configuration.getInt(PAR_CYCLES);
+ if (CommonState.getEndTime() < 0) // not initialized yet
+ CDState.setEndTime(cycles);
+
+ // initialization
+ CDState.setCycle(0);
+ CDState.setPhase(CDState.PHASE_UNKNOWN);
+ System.err.println("CDSimulator: resetting");
+ controls = null;
+ ctrlSchedules = null;
+ Network.reset();
+ System.err.println("CDSimulator: running initializers");
+ runInitializers();
+
+ // main cycle
+ loadControls();
+
+ System.err.println("CDSimulator: starting simulation");
+ for (int i = 0; i < cycles; ++i) {
+ CDState.setCycle(i);
+
+ boolean stop = false;
+ for (int j = 0; j < controls.length; ++j) {
+ if (ctrlSchedules[j].active(i))
+ stop = stop || controls[j].execute();
+ }
+ if (stop)
+ break;
+ //System.err.println("CDSimulator: cycle " + i + " DONE");
+ }
+
+ CDState.setPhase(CDState.POST_SIMULATION);
+
+ // analysis after the simulation
+ for (int j = 0; j < controls.length; ++j) {
+ if (ctrlSchedules[j].fin)
+ controls[j].execute();
+ }
+}
+
+}
diff --git a/contrib/psg/src/peersim/cdsim/CDState.java b/contrib/psg/src/peersim/cdsim/CDState.java
new file mode 100644
index 0000000000..ef52f78682
--- /dev/null
+++ b/contrib/psg/src/peersim/cdsim/CDState.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.cdsim;
+
+import peersim.core.CommonState;
+
+
+/**
+ * This is the common state of a cycle driven simulation that all objects see.
+ * It contains additional information, specific to the cycle driven model,
+ * in addition to the info in {@link peersim.core.CommonState}.
+ */
+public class CDState extends CommonState {
+
+
+// ======================= fields ==================================
+// =================================================================
+
+/**
+ * Current time within the current cycle.
+ * Note that {@link #cycle} gives the cycle id to which this value is relative.
+ */
+private static int ctime = -1;
+
+/**
+ * Current cycle in the simulation. It makes sense only in the case of a
+ * cycle based simulator, that is, cycle based simulators will maintain this
+ * value, others will not. It still makes sense to keep it separate from
+ * {@link #time} because it is an int, while time is a long.
+ */
+private static int cycle = -1;
+
+
+// ======================== initialization =========================
+// =================================================================
+
+
+static {}
+
+/** to avoid construction */
+private CDState() {}
+
+// ======================= methods =================================
+// =================================================================
+
+
+/**
+* Returns true if and only if there is a cycle driven simulation going on.
+*/
+public static boolean isCD() { return cycle >= 0; }
+
+//-----------------------------------------------------------------
+
+/**
+ * Returns the current cycle.
+ * Note that {@link #getTime()} returns the same value.
+ * @throws UnsupportedOperationException if no cycle-driven state is available
+ */
+public static int getCycle()
+{
+ if( cycle >= 0 ) return cycle;
+ else throw new UnsupportedOperationException(
+ "Cycle driven state accessed when "+
+ "no cycle state information is available.");
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Sets current cycle. Resets also cycle time to 0. It also calls
+ * {@link #setTime(long)} with the given parameter, to make sure
+ * {@link #getTime()} is indeed independent of the simulation model.
+ */
+public static void setCycle(int t)
+{
+ cycle = t;
+ ctime = 0;
+ setTime(t);
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Returns current cycle as an Integer object.
+ * @throws UnsupportedOperationException if no cycle-driven state is available
+ */
+public static Integer getCycleObj()
+{
+ if( cycle >= 0 ) return Integer.valueOf(cycle);
+ else throw new UnsupportedOperationException(
+ "Cycle driven state accessed when "+
+ "no cycle state information is available.");
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Returns the current time within the current cycle.
+ * Note that the time returned by {@link #getCycle} is the cycle id
+ * in this case. In other words, it returns the number of nodes that have
+ * already been visited in a given cycle.
+ * @throws UnsupportedOperationException if no cycle-driven state is available
+ */
+public static int getCycleT()
+{
+ if( ctime >= 0 ) return ctime;
+ else throw new UnsupportedOperationException(
+ "Cycle driven state accessed when "+
+ "no cycle state information is available.");
+}
+
+// -----------------------------------------------------------------
+
+public static void setCycleT(int t)
+{
+ ctime = t;
+}
+}
+
+
diff --git a/contrib/psg/src/peersim/cdsim/DaemonProtocol.java b/contrib/psg/src/peersim/cdsim/DaemonProtocol.java
new file mode 100644
index 0000000000..73f9a4eac4
--- /dev/null
+++ b/contrib/psg/src/peersim/cdsim/DaemonProtocol.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.cdsim;
+
+import java.util.Arrays;
+import peersim.config.Configuration;
+import peersim.core.Node;
+import peersim.core.Control;
+
+/**
+* A protocol that is not really a protocol, but a trick to carry out all
+* kinds of tasks during the simulation. Many users will probably not need it,
+* but it is a nice way to e.g. run controls at any time, not only between cycles.
+*/
+public class DaemonProtocol implements CDProtocol {
+
+
+// ========================= fields =================================
+// ==================================================================
+
+
+/**
+* This is the prefix for network dynamism managers.
+* @config
+*/
+private static final String PAR_CTRL = "control";
+
+/**
+* The controls will be run according to this frequency.
+* It is interpreted within a cycle, in terms of cycle time
+* ({@link CDState#getCycleT}). The first cycletime is 0.
+* Defaults to 1.
+* @config
+*/
+private static final String PAR_STEP = "cstep";
+
+// --------------------------------------------------------------------
+
+private static Control[] controls=null;
+
+private static int step;
+
+// ========================= initialization =========================
+// ==================================================================
+
+
+public DaemonProtocol(String s)
+{
+ step = Configuration.getInt(s+"."+PAR_STEP,1);
+
+ String[] names = Configuration.getNames(s+"."+PAR_CTRL);
+ controls = new Control[names.length];
+ for(int i=0; i
+* Loading the configuration is currently done with the help of
+* constructing an instance of {@link ParsedProperties} using the
+* constructor {@link ParsedProperties#ParsedProperties(String[])},
+* in the same way as the normal simulator.
+*
+* After loading the configuration, the collection of nodes forming a
+* Network is instantiated, together with all protocols forming a
+* node. Initialization controls are executed, and then the simulation
+* stops.
+*
+* For each error encountered, a message is printed ons standard error,
+* and the initialization keeps going without interruption. If multiple
+* errors are present, an error message for each of them is printed.
+* Apart from errors, default choices are also printed as warnings, to
+* allow developers to spot subtle configuration errors such as missing
+* parameters that defaults to standard values.
+*
+* @param args passed on to
+* {@link ParsedProperties#ParsedProperties(String[])}
+*/
+public static void main(String[] args)
+ throws Exception
+{
+ System.setErr(new NullPrintStream());
+ Properties prop = new ParsedProperties(args);
+ Configuration.setConfig( prop, true );
+ parseRanges(prop);
+
+ final int SIMID = getSimID();
+ if( SIMID == UNKNOWN )
+ {
+ System.err.println(
+ "Simulator: unable to identify configuration, exiting.");
+ return;
+ }
+
+ try {
+
+ // XXX could be done through reflection, but
+ // this is easier to read.
+ switch(SIMID)
+ {
+ case CDSIM:
+ // Set cycles to 0, so no simulation is ever performed.
+ prop.setProperty(CDSimulator.PAR_CYCLES, "0");
+ CDSimulator.nextExperiment();
+ break;
+ case EDSIM:
+ // Set endtime to 0, so no simulation is ever performed.
+ prop.setProperty(EDSimulator.PAR_ENDTIME, "0");
+ EDSimulator.nextExperiment();
+ break;
+ }
+
+ } catch (MissingParameterException e) {
+ System.out.println(e.getMessage());
+ System.exit(1);
+ } catch (IllegalParameterException e) {
+ System.out.println(e.getMessage());
+ System.exit(1);
+ }
+}
+
+/**
+ * Parses a collection of range specifications, identifies the set
+ * of parameters that will change during the simulation and
+ * instantiates them with the first value of their ranges.
+ */
+private static void parseRanges(Properties prop)
+{
+ // Get ranges
+ String[] ranges = Configuration.getNames(PAR_RANGE);
+
+ for (int i = 0; i < ranges.length; i++) {
+ String[] array = Configuration.getString(ranges[i]).split(";");
+ if (array.length != 2) {
+ throw new IllegalParameterException(ranges[i],
+ " should be formatted as
+ * Note that this is not a constant time operation in the number of
+ * protocols, although typically there are very few protocols defined.
+ *
+ * @param pid
+ * numeric protocol identifier.
+ * @return name of the protocol that has the given id. null if no protocols
+ * have the given id.
+ */
+public String lookupPid(int pid)
+{
+
+ if (!protocols.containsValue(pid))
+ return null;
+ for (Map.Entry
+ * It is not required that all entries are listed. If PAR_INCLUDE is used,
+ * then only those entries are returned that are listed. If PAR_ORDER is
+ * used, then all names are returned, but the array will start with those
+ * that are listed. The rest of the names follow in alphabetical order.
+ *
+ *
+ * @param names
+ * the set of property names to be searched
+ * @param type
+ * the string identifying the particular set of properties to be
+ * inspected
+ */
+private String[] order(String[] names, String type)
+{
+ String order = getString(Configuration.PAR_INCLUDE + "." + type, null);
+ boolean include = order != null;
+ if (!include)
+ order = getString(Configuration.PAR_ORDER + "." + type, null);
+
+ int i = 0;
+ if (order != null && !order.equals("")) {
+ // split around non-word characters
+ String[] sret = order.split("\\W+");
+ for (; i < sret.length; i++) {
+ int j = i;
+ for (; j < names.length; ++j)
+ if (names[j].equals(type + "." + sret[i]))
+ break;
+ if (j == names.length) {
+ throw new IllegalParameterException(
+ (include ? Configuration.PAR_INCLUDE : Configuration.PAR_ORDER)
+ + "." + type, type + "." + sret[i] + " is not defined.");
+ } else // swap the element to current position
+ {
+ String tmps = names[j];
+ names[j] = names[i];
+ names[i] = tmps;
+ }
+ }
+ }
+
+ Arrays.sort(names, i, names.length);
+ int retsize = (include ? i : names.length);
+ String[] ret = new String[retsize];
+ for (int j = 0; j < retsize; ++j)
+ ret[j] = names[j];
+ return ret;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Print debug information for configuration. The amount of information
+ * depends on the debug level DEBUG. 0 = nothing 1 = just the config name 2 =
+ * config name plus method calling
+ *
+ * @param name
+ */
+private void debug(String name, String result)
+{
+ if (debugLevel == DEBUG_NO)
+ return;
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("DEBUG ");
+ buffer.append(name);
+ buffer.append(" = ");
+ buffer.append(result);
+
+ // Additional info
+ if (debugLevel == DEBUG_CONTEXT) {
+
+ buffer.append("\n at ");
+ // Obtain the stack trace
+ StackTraceElement[] stack = null;
+ try {
+ throw new Exception();
+ } catch (Exception e) {
+ stack = e.getStackTrace();
+ }
+
+ // Search the element that invoked Configuration
+ // It's the first whose class is different from Configuration
+ int pos;
+ for (pos = 0; pos < stack.length; pos++) {
+ if (!stack[pos].getClassName().equals(Configuration.class.getName()))
+ break;
+ }
+
+ buffer.append(stack[pos].getClassName());
+ buffer.append(":");
+ buffer.append(stack[pos].getLineNumber());
+ buffer.append(", method ");
+ buffer.append(stack[pos - 1].getMethodName());
+ buffer.append("()");
+ }
+
+ System.err.println(buffer);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * @return an array of adjacent letter pairs contained in the input string
+ * http://www.catalysoft.com/articles/StrikeAMatch.html
+ */
+private String[] letterPairs(String str)
+{
+ int numPairs = str.length() - 1;
+ String[] pairs = new String[numPairs];
+ for (int i = 0; i < numPairs; i++) {
+ pairs[i] = str.substring(i, i + 2);
+ }
+ return pairs;
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * @return an ArrayList of 2-character Strings.
+ * http://www.catalysoft.com/articles/StrikeAMatch.html
+ */
+private ArrayList
+* A little inconvenience is that if
+* No exceptions are thrown, instead error messages are written to the
+* standard error. Users who want a finer control should use
+* the public methods of this class.
+*
+* @param pars The (probably command line) parameter list.
+* @param resource The name of the system resource that contains the
+* defaults. null if there isn't any.
+*
+*/
+public ConfigProperties( String[] pars, String resource ) {
+
+ try
+ {
+ if( resource != null )
+ {
+ loadSystemResource(resource);
+ System.err.println("ConfigProperties: System resource "
+ +resource+" loaded.");
+ }
+ }
+ catch( Exception e )
+ {
+ System.err.println("ConfigProperties: " + e );
+ }
+
+ if( pars == null || pars.length == 0 ) return;
+
+ for (int i=0; i < pars.length; i++)
+ {
+ try
+ {
+ load( pars[i] );
+ System.err.println(
+ "ConfigProperties: File "+pars[i]+" loaded.");
+ pars[i] = "";
+ }
+ catch( IOException e )
+ {
+ try
+ {
+ loadPropertyString( pars[i] );
+ System.err.println("ConfigProperties: Property '" +
+ pars[i] + "' set.");
+ }
+ catch( Exception e2 )
+ {
+ System.err.println("ConfigProperties: " + e2 );
+ }
+ }
+ catch( Exception e )
+ {
+ System.err.println("ConfigProperties: " + e );
+ }
+ }
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Constructs a ConfigProperty object by loading a file by calling
+* {@link #load}.
+* @param fileName The name of the configuration file.
+*/
+public ConfigProperties( String fileName ) throws IOException {
+
+ load( fileName );
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Calls super constructor.
+*/
+public ConfigProperties( Properties props ) {
+
+ super( props );
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Calls {@link #ConfigProperties(String[],String)} with resource set to null.
+*/
+public ConfigProperties( String[] pars ) {
+
+ this( pars, null );
+}
+
+
+// =========== Public methods ========================================
+// ===================================================================
+
+
+/**
+* Loads given file. Calls
+ * The design of this class also hides the actual implementation of the
+ * configuration which can be Properties, XML, whatever. Currently only
+ * Properties is supported.
+ *
+ * Apart from storing (name,value) pairs, this class also does some
+ * processing, and offers some utility functions. This extended
+ * functionality consists of the following: reading values with type
+ * checking, ordering of entries, pre-processing protocol names, parsing
+ * expressions, resolving underspecified classnames, and finally some basic
+ * debugging possibilities. We discuss these in the following.
+ *
+ * Note that the configuration is initialized using a Properties object.
+ * The class of this object might implement some additional pre-processing
+ * on the file or provide an extended syntax for defining property files.
+ * See {@link ParsedProperties} for more details. This is the class that is
+ * currently used by simulation engines.
+ *
+ * Assuming the configuration is in Properties format (which is currently
+ * the only format available) component types and names are defined as
+ * follows. Property names containing two non-empty words separated by one
+ * dot (".") character are treated specially (the words contain word
+ * characters: alphanumeric and underscore ("_")). The first word will be
+ * the type, and the second is the name of a component. For example,
+ *
+ *
+ * It is also possible to exclude elements from the list, while ordering
+ * them. The syntax is identical to that of the above, only the parameter
+ * name begins with
+ *
+ * Expressions like "sub-expression op sub-expression" are computed based
+ * on the type of the sub-expressions. If both sub-expressions are integer,
+ * the computation is done using integer arithmetics and the result is an
+ * integer. So, for example, 5/2 returns 2. If one of the sub-expression is
+ * floating point, the computation is based on floating-point arithmetics
+ * (double precision) and the result is a floating point value. So, for
+ * example, 5.0/2 returns 2.5.
+ *
+ *
+ * Expressions are parsed recursively. Note that no optimization is done,
+ * so expression F is evaluated three times here (due to the fact that
+ * appears twice in C and once in B). But since properties are read just
+ * once at initialization, this is not a performance problem.
+ *
+ *
+ * Finally, recursive definitions are not allowed (and without function
+ * definitions, they make no sense). Since it is difficult to discover
+ * complex recursive chains, a simple trick is used: if the depth of
+ * recursion is greater than a given threshold (configurable, currently
+ * {@value #DEFAULT_MAXDEPTH}, an error message is printed. This avoids to
+ * fill the stack, that results in an anonymous OutOfMemoryError. So, if
+ * you write
+ *
+ *
+ * If property {@value #PAR_DEBUG} is defined, each config property and the
+ * associated value are printed. Properties that are not present in the
+ * config file but have default values are postfixed with the string
+ * "(DEFAULT)".
+ *
+ * If property {@value #PAR_DEBUG} is defined and it is equal to
+ * {@value #DEBUG_EXTENDED}, information about the configuration method
+ * invoked, and where this method is invoked, is also printed. If it is
+ * equal to {@value #DEBUG_FULL}, all the properties are printed, even if
+ * they are not read.
+ *
+ * Each line printed by this debug feature is prefixed by the string
+ * "DEBUG".
+ *
+ *
+ * Note that this is not a constant time operation in the number of
+ * protocols, although typically there are very few protocols defined.
+ *
+ * @param pid
+ * numeric protocol identifier.
+ * @return name of the protocol that has the given id. null if no protocols
+ * have the given id.
+ */
+public static String lookupPid(int pid)
+{
+ return config.lookupPid(pid);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * {@link MissingParameterException}. When creating the Class object, a
+ * few attempts are done to resolve the classname. See
+ * {@link Configuration} for details.
+ * @param name
+ * Name of configuration property
+ */
+public static Class getClass(String name)
+{
+ return config.getClass(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ * Name of configuration property
+ * @param def
+ * default value
+ * @see #getClass(String)
+ */
+public static Class getClass(String name, Class def)
+{
+ return config.getClass(name, def);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property for a class name. It returns an
+ * instance of the class. The class must implement a constructor that takes
+ * a String as an argument. The value of this string will be name.
+ * The constructor of the class can see the configuration so it can make
+ * use of this name to read its own parameters from it.
+ * @param name
+ * Name of configuration property
+ * @throws MissingParameterException
+ * if the given property is not defined
+ * @throws IllegalParameterException
+ * if there is any problem creating the instance
+ */
+public static Object getInstance(String name)
+{
+ return config.getInstance(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property for a class name. It returns an
+ * instance of the class. The class must implement a constructor that takes
+ * a String as an argument. The value of this string will be name.
+ * The constructor of the class can see the configuration so it can make
+ * use of this name to read its own parameters from it.
+ * @param name
+ * Name of configuration property
+ * @param def
+ * The default object that is returned if there is no property
+ * defined with the given name
+ * @throws IllegalParameterException
+ * if the given name is defined but there is a problem creating
+ * the instance.
+ */
+public static Object getInstance(String name, Object def)
+{
+ return config.getInstance(name, def);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * It returns an array of class instances. The instances are constructed by
+ * calling {@link #getInstance(String)} on the names returned by
+ * {@link #getNames(String)}.
+ * @param name
+ * The component type (i.e. prefix of the list of configuration
+ * properties) which will be passed to {@link #getNames(String)}.
+ */
+public static Object[] getInstanceArray(String name)
+{
+ return config.getInstanceArray(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Returns an array of names prefixed by the specified name. The array is
+ * sorted as follows. If there is no config entry
+ *
+ Know limitations:
+ The parsing mechanism is very simple; no complex error messages
+ are provided. In case of missing closing brackets, the method
+ will stop reporting the number of missing brackets. Additional
+ closing brackets (i.e., missing opening brackets) produce an
+ error messages reporting the line where the closing bracket
+ is present. Misplaced brackets (included in lines that
+ contains other characters) are ignored, thus may indirectly produce
+ the previous error messages.
+*/
+public void load( String fileName ) throws IOException {
+
+ /* This set is used to store prefixes that have been associated
+ * to brackets blocks. If a prefix is inserted twice, this means
+ * that there are two blocks referring to the same prefix -
+ * which may be caused by a commented prefix in the config
+ * file, something like this:
+ *
+ * prefix1
+ * {
+ * property 1
+ * }
+ * #prefix2
+ * {
+ * property 2
+ * }
+ *
+ */
+ Set
+ * The set methods should not be used by applications,
+ * they are for system
+ * components. Use them only if you know exactly what you are doing, e.g.
+ * if you are so advanced that you can write your own simulation engine.
+ * Ideally, they should not be visible, but due to the lack of more
+ * flexibility in java access rights, we are forced to make them public.
+ */
+public class CommonState
+{
+
+//======================= constants ===============================
+//=================================================================
+
+/**
+* Constant that can be used as a value of simulation phase.
+* It means that the simulation has finished.
+* @see #getPhase
+*/
+public static final int POST_SIMULATION = 1;
+
+/**
+* Constant that can be used as a value of simulation phase.
+* It means that the simulation phase information has not been set (unknown).
+* @see #getPhase
+*/
+public static final int PHASE_UNKNOWN = 0;
+
+// ======================= fields ==================================
+// =================================================================
+
+/**
+ * Current time. Note that this value is simulator independent, all simulation
+ * models have a notion related to time. For example, in the cycle based model,
+ * the cycle id gives time, while in even driven simulations there is a more
+ * realistic notion of time.
+ */
+private static long time = 0;
+
+/**
+ * The maximal value {@link #time} can ever take.
+ */
+private static long endtime = -1;
+
+/**
+ * Number of used bits in the long representation of time, calculated
+ * based on the endtime.
+ */
+private static int toshift = -1;
+
+/**
+ * Information about where exactly the simulation is.
+ */
+private static int phase = PHASE_UNKNOWN;
+
+/**
+ * The current pid.
+ */
+private static int pid;
+
+/**
+ * The current node.
+ */
+private static Node node;
+
+/**
+* This source of randomness should be used by all components.
+* This field is public because it doesn't matter if it changes
+* during an experiment (although it shouldn't) until no other sources of
+* randomness are used within the system. Besides, we can save the cost
+* of calling a wrapper method, which is important because this is needed
+* very often.
+*/
+public static ExtendedRandom r = null;
+
+
+// ======================== initialization =========================
+// =================================================================
+
+/**
+* Configuration parameter used to define which random generator
+* class should be used. If not specified, the default implementation
+* {@link ExtendedRandom} is used. User-specified random generators
+* must extend class {@link ExtendedRandom}.
+* @config
+*/
+public static final String PAR_RANDOM = "random";
+
+/**
+* Configuration parameter used to initialize the random seed.
+* If it is not specified the current time is used.
+* @config
+*/
+public static final String PAR_SEED = "random.seed";
+
+
+/**
+* Initializes the field {@link r} according to the configuration.
+* Assumes that the configuration is already
+* loaded.
+*/
+static {
+
+ long seed =
+ Configuration.getLong(PAR_SEED,System.currentTimeMillis());
+ initializeRandom(seed);
+}
+
+
+/** Does nothing. To avoid construction but allow extension. */
+protected CommonState() {}
+
+// ======================= methods =================================
+// =================================================================
+
+
+/**
+ * Returns current time. In event-driven simulations, returns the current
+ * time (a long-value).
+ * In cycle-driven simulations, returns the current cycle (a long that
+ * can safely be cast into an integer).
+ */
+public static long getTime()
+{
+ /* if the engine simulator used is PSG (simId=2 */
+ if(Simulator.getSimID()==2)
+ return (long) PSGPlatform.getTime();
+ else
+ return time;
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Returns current time in integer format. The purpose is to enhance the
+ * performance of protocols (ints are smaller and faster) when absolute
+ * precision is not required. It assumes that endtime has been set via
+ * {@link #setEndTime} by the simulation engine. It uses the endtime for
+ * the optimal mapping to get the maximal precision.
+ * In particular, in the cycle
+ * based model, time is the same as cycle which can be safely cast into
+ * integer, so no precision is lost.
+ */
+public static int getIntTime()
+{
+ return (int)(time>>toshift);
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Sets the current time.
+ */
+public static void setTime(long t)
+{
+ time = t;
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Returns endtime.
+ * It is the maximal value {@link #getTime} ever returns. If it's negative, it
+ * means the endtime is not known.
+ */
+public static long getEndTime()
+{
+ return endtime;
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Sets the endtime.
+ */
+public static void setEndTime(long t)
+{
+ if( endtime >= 0 )
+ throw new RuntimeException("You can set endtime only once");
+ if( t < 0 )
+ throw new RuntimeException("No negative values are allowed");
+
+ endtime = t;
+ toshift = 32-Long.numberOfLeadingZeros(t);
+ if( toshift<0 ) toshift = 0;
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Returns the simulation phase. Currently the following phases are
+ * understood.
+ *
+* Also note that there is no possibility to remove elements from the
+* neighbor set. This is because removal is usually costly and it does not make
+* sense in the context of our applications,
+* where this interface is used for 1) initialization and 2)
+* providing an interface for other protocols for accessing the neighbor list.
+* Protocols that manage links remove, refresh, etc their link set internally
+* or through custom methods.
+* Therefore it would only put an unnecessary burden on implementors.
+*/
+public interface Linkable extends Cleanable {
+
+
+ /**
+ * Returns the size of the neighbor list.
+ */
+ public int degree();
+
+ /**
+ * Returns the neighbor with the given index. The contract is that
+ * listing the elements from index 0 to index degree()-1 should list
+ * each element exactly once if this object is not modified in the
+ * meantime. It throws an IndexOutOfBounds exception if i is negative
+ * or larger than or equal to {@link #degree}.
+ */
+ public Node getNeighbor(int i);
+
+ /**
+ * Add a neighbor to the current set of neighbors. If neighbor
+ * is not yet a neighbor but it cannot be added from other reasons,
+ * this method should not return normally, that is, it must throw
+ * a runtime exception.
+ * @return true if the neighbor has been inserted; false if the
+ * node is already a neighbor of this node
+ */
+ public boolean addNeighbor(Node neighbour);
+
+ /**
+ * Returns true if the given node is a member of the neighbor set.
+ */
+ public boolean contains(Node neighbor);
+
+ /**
+ * A possibility for optimization. An implementation should try to
+ * compress its internal representation. Normally this is called
+ * by initializers or other components when
+ * no increase in the expected size of the neighborhood can be
+ * expected.
+ */
+ public void pack();
+}
+
diff --git a/contrib/psg/src/peersim/core/MaliciousProtocol.java b/contrib/psg/src/peersim/core/MaliciousProtocol.java
new file mode 100644
index 0000000000..26ed74f126
--- /dev/null
+++ b/contrib/psg/src/peersim/core/MaliciousProtocol.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+/**
+ * Tag interface to identify protocols that are malicious.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.2 $
+ */
+public interface MaliciousProtocol
+extends Protocol
+{
+}
+
diff --git a/contrib/psg/src/peersim/core/ModifiableNode.java b/contrib/psg/src/peersim/core/ModifiableNode.java
new file mode 100644
index 0000000000..7ce80a3acd
--- /dev/null
+++ b/contrib/psg/src/peersim/core/ModifiableNode.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+
+/**
+ * This class extends GeneralNode by allowing to modify single
+ * protocol instances at nodes.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.3 $
+ */
+public class ModifiableNode extends GeneralNode
+{
+
+/**
+ * Invokes the super constructor.
+ */
+public ModifiableNode(String prefix)
+{
+ super(prefix);
+}
+
+/**
+ * Substitutes the specified protocol at this node.
+ *
+ * @param pid protocol identifier
+ * @param prot the protocol object
+ */
+public void setProtocol(int pid, Protocol prot)
+{
+ protocol[pid] = prot;
+}
+
+}
diff --git a/contrib/psg/src/peersim/core/Network.java b/contrib/psg/src/peersim/core/Network.java
new file mode 100644
index 0000000000..da9c54531e
--- /dev/null
+++ b/contrib/psg/src/peersim/core/Network.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+import peersim.Simulator;
+import peersim.config.Configuration;
+import psgsim.PSGDynamicNetwork;
+
+import java.util.Comparator;
+import java.util.Arrays;
+
+import org.simgrid.msg.HostNotFoundException;
+import org.simgrid.msg.MsgException;
+
+/**
+ * This class forms the basic framework of all simulations. This is a static
+ * singleton which is based on the assumption that we will simulate only one
+ * overlay network at a time. This allows us to reduce memory usage in many
+ * cases by allowing all the components to directly reach the fields of this
+ * class without having to store a reference.
+ *
+ * The network is a set of nodes implemented via an array list for the sake of
+ * efficiency. Each node has an array of protocols. The protocols within a node
+ * can interact directly as defined by their implementation, and can be imagined
+ * as processes running in a common local environment (i.e. the node). This
+ * class is called a "network" because, although it is only a set of nodes, in
+ * most simulations there is at least one {@link Linkable} protocol that defines
+ * connections between nodes. In fact, such a {@link Linkable} protocol layer
+ * can be accessed through a {@link peersim.graph.Graph} view using
+ * {@link OverlayGraph}.
+ */
+public class Network {
+
+ // ========================= fields =================================
+ // ==================================================================
+
+ /**
+ * This config property defines the node class to be used. If not set, then
+ * {@link GeneralNode} will be used.
+ *
+ * @config
+ */
+ private static final String PAR_NODE = "network.node";
+
+ /**
+ * This config property defines the initial capacity of the overlay network.
+ * If not set then the value of {@value #PAR_SIZE} will be used. The main
+ * purpose of this parameter is that it allows for optimization. In the case
+ * of scenarios when the network needs to grow, setting this to the maximal
+ * expected size of the network avoids reallocation of memory during the
+ * growth of the network.
+ *
+ * @see #getCapacity
+ * @config
+ */
+ private static final String PAR_MAXSIZE = "network.initialCapacity";
+
+ /**
+ * This config property defines the initial size of the overlay network.
+ * This property is required.
+ *
+ * @config
+ */
+ private static final String PAR_SIZE = "network.size";
+
+ /**
+ * The node array. This is not a private array which is not nice but
+ * efficiency has the highest priority here. The main purpose is to allow
+ * the package quick reading of the contents in a maximally flexible way.
+ * Nevertheless, methods of this class should be used instead of the array
+ * when modifying the contents. Because this array is not private, it is
+ * necessary to know that the actual node set is only the first
+ * {@link #size()} items of the array.
+ */
+ static Node[] node = null;
+
+ /**
+ * Actual size of the network.
+ */
+ private static int len;
+
+ /**
+ * The prototype node which is used to populate the simulation via cloning.
+ * After all the nodes have been cloned, {@link Control} components can be
+ * applied to perform any further initialization.
+ */
+ public static Node prototype = null;
+
+ // ====================== initialization ===========================
+ // =================================================================
+
+ /**
+ * Reads configuration parameters, constructs the prototype node, and
+ * populates the network by cloning the prototype.
+ */
+ public static void reset() {
+
+ if (prototype != null) {
+ // not first experiment
+ while (len > 0)
+ remove(); // this is to call onKill on all nodes
+ prototype = null;
+ node = null;
+ }
+
+ len = Configuration.getInt(PAR_SIZE);
+ int maxlen = Configuration.getInt(PAR_MAXSIZE, len);
+ if (maxlen < len)
+ throw new IllegalArgumentException(PAR_MAXSIZE + " is less than "
+ + PAR_SIZE);
+
+ node = new Node[maxlen];
+
+ // creating prototype node
+ Node tmp = null;
+ if (!Configuration.contains(PAR_NODE)) {
+ System.err.println("Network: no node defined, using GeneralNode");
+ tmp = new GeneralNode("");
+ } else {
+ tmp = (Node) Configuration.getInstance(PAR_NODE);
+ }
+ prototype = tmp;
+ prototype.setIndex(-1);
+
+ // cloning the nodes
+ if (len > 0) {
+ for (int i = 0; i < len; ++i) {
+ node[i] = (Node) prototype.clone();
+ node[i].setIndex(i);
+ }
+ }
+ }
+
+ /** Disable instance construction */
+ private Network() {
+ }
+
+ // =============== public methods ===================================
+ // ==================================================================
+
+ /** Number of nodes currently in the network */
+ public static int size() {
+ return len;
+ }
+
+ // ------------------------------------------------------------------
+
+ /**
+ * Sets the capacity of the internal array storing the nodes. The nodes will
+ * remain the same in the same order. If the new capacity is less than the
+ * old size of the node list, than the end of the list is cut. The nodes
+ * that get removed via this cutting are removed through {@link #remove()}.
+ */
+ public static void setCapacity(int newSize) {
+
+ if (node == null || newSize != node.length) {
+ for (int i = newSize; i < len; ++i)
+ remove();
+ Node[] newnodes = new Node[newSize];
+ final int l = Math.min(node.length, newSize);
+ System.arraycopy(node, 0, newnodes, 0, l);
+ node = newnodes;
+ if (len > newSize)
+ len = newSize;
+ }
+ }
+
+ // ------------------------------------------------------------------
+
+ /**
+ * Returns the maximal number of nodes that can be stored without
+ * reallocating the underlying array to increase capacity.
+ */
+ public static int getCapacity() {
+ return node.length;
+ }
+
+ // ------------------------------------------------------------------
+
+ /**
+ * The node will be appended to the end of the list. If necessary, the
+ * capacity of the internal array is increased.
+ */
+ public static void add(Node n) {
+ if (len == node.length)
+ setCapacity(3 * node.length / 2 + 1);
+ node[len] = n;
+ n.setIndex(len);
+ len++;
+ if (Simulator.getSimID() == 2)
+ try {
+ PSGDynamicNetwork.add(n);
+ } catch (HostNotFoundException e) {
+ System.err.println("Host not found in platform file");
+ }
+ System.err.println("node " + n.getID() + " with index " + n.getIndex()
+ + " was added at time " + CommonState.getTime());
+ }
+
+ // ------------------------------------------------------------------
+
+ /**
+ * Returns node with the given index. Note that the same node will normally
+ * have a different index in different times. This can be used as a random
+ * access iterator. This method does not perform range checks to increase
+ * efficiency. The maximal valid index is {@link #size()}.
+ */
+ public static Node get(int index) {
+ return node[index];
+ }
+
+ // ------------------------------------------------------------------
+
+ /**
+ * The node at the end of the list is removed. Returns the removed node. It
+ * also sets the fail state of the node to {@link Fallible#DEAD}.
+ */
+ public static Node remove() {
+ Node n = node[len - 1]; // if len was zero this throws and exception
+ node[len - 1] = null;
+ len--;
+ System.err.println("node " + n.getID() + " with index " + n.getIndex()
+ + " was removed at time " + CommonState.getTime());
+ n.setFailState(Fallible.DEAD);
+ if (Simulator.getSimID() == 2)
+ PSGDynamicNetwork.remove(n);
+ return n;
+ }
+
+ // ------------------------------------------------------------------
+
+ /**
+ * The node with the given index is removed. Returns the removed node. It
+ * also sets the fail state of the node to {@link Fallible#DEAD}.
+ *
+ * Look out: the index of the other nodes will not change (the right hand
+ * side of the list is not shifted to the left) except that of the last
+ * node. Only the last node is moved to the given position and will get
+ * index i.
+ */
+ public static Node remove(int i) {
+
+ if (i < 0 || i >= len)
+ throw new IndexOutOfBoundsException("" + i);
+ swap(i, len - 1);
+ return remove();
+ }
+
+ // ------------------------------------------------------------------
+
+ /**
+ * Swaps the two nodes at the given indexes.
+ */
+ public static void swap(int i, int j) {
+
+ Node n = node[i];
+ node[i] = node[j];
+ node[j] = n;
+ node[j].setIndex(j);
+ node[i].setIndex(i);
+ }
+
+ // ------------------------------------------------------------------
+
+ /**
+ * Shuffles the node array. The index of each node is updated accordingly.
+ */
+ public static void shuffle() {
+
+ for (int i = len; i > 1; i--)
+ swap(i - 1, CommonState.r.nextInt(i));
+
+ }
+
+ // ------------------------------------------------------------------
+
+ /**
+ * Sorts the node array. The index of each node is updated accordingly.
+ *
+ * @param c
+ * The comparator to be used for sorting the nodes. If null, the
+ * natural order of the nodes is used.
+ */
+ public static void sort(Comparator super Node> c) {
+
+ Arrays.sort(node, 0, len, c);
+ for (int i = 0; i < len; i++)
+ node[i].setIndex(i);
+ }
+
+ // ------------------------------------------------------------------
+
+ public static void test() {
+
+ System.err.println("number of nodes = " + len);
+ System.err.println("capacity (max number of nodes) = " + node.length);
+ for (int i = 0; i < len; ++i) {
+ System.err.println("node[" + i + "]");
+ System.err.println(node[i].toString());
+ }
+
+ if (prototype == null)
+ return;
+ for (int i = 0; i < prototype.protocolSize(); ++i) {
+ if (prototype.getProtocol(i) instanceof Linkable)
+ peersim.graph.GraphIO.writeUCINET_DL(new OverlayGraph(i),
+ System.err);
+ }
+ }
+
+}
diff --git a/contrib/psg/src/peersim/core/Node.java b/contrib/psg/src/peersim/core/Node.java
new file mode 100644
index 0000000000..a64e3a23b9
--- /dev/null
+++ b/contrib/psg/src/peersim/core/Node.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+/**
+ * Class that represents one node with a network address. An {@link Network} is
+ * made of a set of nodes. The functionality of this class is thin: it must be
+ * able to represent failure states and store a list of protocols. It is the
+ * protocols that do the interesting job.
+ */
+public interface Node extends Fallible, Cloneable
+{
+
+/**
+ * Prefix of the parameters that defines protocols.
+ * @config
+ */
+public static final String PAR_PROT = "protocol";
+
+/**
+ * Returns the Conceptually one can think of it as a successful operation which is
+* immediately overruled by the dynamics of the underlying overlay network.
+* Let's not forget that this class is an adaptor only.
+*
+*
+* The behaviour of this method is affected by parameter {@link #wireDirected}.
+* If it is false, then the opposite edge is set too.
+*/
+public boolean setEdge( int i, int j ) {
+// XXX slightly unintuitive behavior but makes sense when understood
+
+ if( !wireDirected )
+ ((Linkable)Network.node[j].getProtocol(protocolID)
+ ).addNeighbor(Network.node[i]);
+
+
+ return
+ ((Linkable)Network.node[i].getProtocol(protocolID)
+ ).addNeighbor(Network.node[j]);
+}
+
+// ---------------------------------------------------------------
+
+/** Not supported */
+public boolean clearEdge( int i, int j ) {
+
+ throw new UnsupportedOperationException();
+}
+
+// ---------------------------------------------------------------
+
+/**
+* Returns number of neighbors that are up. If node i is down, returns 0.
+*/
+public int degree(int i) {
+
+ if( !Network.node[i].isUp() ) return 0;
+ Linkable lble=(Linkable)Network.node[i].getProtocol(protocolID);
+ int numNeighbours = 0;
+ for(int j=0; j
+ * Although the method cannot have any parameters, it can of course read
+ * {@link CommonState}. It is guaranteed that the state is up-to-date,
+ * inlcuding eg method {@link CommonState#getNode}.
+ */
+public class MethodInvoker implements Control, NodeInitializer {
+
+
+// --------------------------------------------------------------------------
+// Parameter names
+// --------------------------------------------------------------------------
+
+/**
+ * The protocol to operate on.
+ * If not defined, the given method will be invoked on all protocols that
+ * define it. In all cases, at least one protocol has to define it.
+ * @config
+ */
+private static final String PAR_PROT = "protocol";
+
+/**
+ * The method to be invoked. It must return void and should not have any
+ * parameters specified.
+ * @config
+ */
+private static final String PAR_METHOD = "method";
+
+
+// --------------------------------------------------------------------------
+// Fields
+// --------------------------------------------------------------------------
+
+/** Identifiers of the protocols to be initialized */
+private final int pid[];
+
+/** Method name */
+private final String methodName;
+
+/** Methods corresponding to the protocols in {@link #pid}. */
+private final Method method[];
+
+
+// --------------------------------------------------------------------------
+// Initialization
+// --------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters.
+ * Invoked by the simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public MethodInvoker(String prefix) {
+
+ methodName = Configuration.getString(prefix+"."+PAR_METHOD);
+ if(!Configuration.contains(prefix+"."+PAR_PROT))
+ {
+ // find protocols that implement method
+ ArrayList
+ * All {@link CDProtocol} specifications in the configuration need to contain a
+ * {@link Scheduler} specification at least for the step size (see config
+ * parameter {@value peersim.core.Scheduler#PAR_STEP} of {@link Scheduler}).
+ * This value is used as the cycle length for the corresponding protocol.
+ *
+ * @see NextCycleEvent
+ */
+public class CDScheduler implements Control, NodeInitializer {
+
+ // ============================== fields ==============================
+ // ====================================================================
+
+ /**
+ * Parameter that is used to define the class that is used to schedule the
+ * next cycle. Its type is (or extends) {@link NextCycleEvent}. Defaults to
+ * {@link NextCycleEvent}.
+ *
+ * @config
+ */
+ private static final String PAR_NEXTC = "nextcycle";
+
+ /**
+ * The protocols that this scheduler schedules for the first execution. It
+ * might contain several protocol names, separated by whitespace. All
+ * protocols will be scheduled based on the common parameter set for this
+ * scheduler and the parameters of the protocol (cycle length). Protocols
+ * are scheduled independently of each other.
+ *
+ * @config
+ */
+ private static final String PAR_PROTOCOL = "protocol";
+
+ /**
+ * If set, it means that the initial execution of the given protocol is
+ * scheduled for a different random time for all nodes. The random time is a
+ * sample between the current time (inclusive) and the cycle length
+ * (exclusive), the latter being specified by the step parameter (see
+ * {@link Scheduler}) of the assigned protocol.
+ *
+ * @see #execute
+ * @config
+ */
+ private static final String PAR_RNDSTART = "randstart";
+
+ /**
+ * Contains the scheduler objects for all {@link CDProtocol}s defined in the
+ * configuration. The length of the array is the number of protocols
+ * defined, but those entries that belong to protocols that are not
+ * {@link CDProtocol}s are null.
+ */
+ public static final Scheduler[] sch;
+
+ private final NextCycleEvent[] nce;
+
+ private final int[] pid;
+
+ private final boolean randstart;
+
+ // =============================== initialization ======================
+ // =====================================================================
+
+ /**
+ * Loads protocol schedulers for all protocols.
+ */
+ static {
+
+ String[] names = Configuration.getNames(Node.PAR_PROT);
+ sch = new Scheduler[names.length];
+ for (int i = 0; i < names.length; ++i) {
+ if (Network.prototype.getProtocol(i) instanceof CDProtocol)
+ // with no default values for step to avoid
+ // "overscheduling" due to lack of step option.
+ sch[i] = new Scheduler(names[i], false);
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Initialization based on configuration parameters.
+ */
+ public CDScheduler(String n) {
+ String[] prots = Configuration.getString(n + "." + PAR_PROTOCOL).split("\\s");
+ pid = new int[prots.length];
+ nce = new NextCycleEvent[prots.length];
+ for (int i = 0; i < prots.length; ++i) {
+ pid[i] = Configuration.lookupPid(prots[i]);
+ if (!(Network.prototype.getProtocol(pid[i]) instanceof CDProtocol)) {
+ throw new IllegalParameterException(n + "." + PAR_PROTOCOL,
+ "Only CDProtocols are accepted here");
+ }
+ nce[i] = (NextCycleEvent) Configuration.getInstance(n + "."
+ + PAR_NEXTC, new NextCycleEvent(null));
+ }
+ randstart = Configuration.contains(n + "." + PAR_RNDSTART);
+ }
+
+ // ========================== methods ==================================
+ // =====================================================================
+
+ /**
+ * Schedules the protocol at all nodes for the first execution adding it to
+ * the priority queue of the event driven simulation. The time of the first
+ * execution is determined by {@link #firstDelay}. The implementation calls
+ * {@link #initialize} for all nodes.
+ *
+ * @see #initialize
+ */
+ public boolean execute() {
+
+ for (int i = 0; i < Network.size(); ++i) {
+ initialize(Network.get(i));
+ }
+
+ return false;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Schedules the protocol at given node for the first execution adding it to
+ * the priority queue of the event driven simulation. The time of the first
+ * execution is determined by a reference point in time and
+ * {@link #firstDelay}, which defines the delay from the reference point.
+ * The reference point is the maximum of the current time, and the value of
+ * parameter {@value peersim.core.Scheduler#PAR_FROM} of the protocol being
+ * scheduled. If the calculated time of the first execution is not valid
+ * according to the schedule of the protocol then no execution is scheduled
+ * for that protocol.
+ *
+ * A final note: for performance reasons, the recommended practice is not to
+ * use parameter {@value peersim.core.Scheduler#PAR_FROM} in protocols, but
+ * to schedule {@link CDScheduler} itself for the desired time, whenever
+ * possible (e.g., it is not possible if {@link CDScheduler} is used as a
+ * {@link NodeInitializer}).
+ */
+ public void initialize(Node n) {
+ /*
+ * XXX If "from" is not the current time and this is used as a control
+ * (not node initializer) then we dump _lots_ of events in the queue
+ * that are just stored there until "from" comes. This reduces
+ * performance, and should be fixed. When fixed, the final comment can
+ * be removed from the docs.
+ */
+
+ final long time = CommonState.getTime();
+ for (int i = 0; i < pid.length; ++i) {
+ Object nceclone = null;
+ try {
+ nceclone = nce[i].clone();
+ } catch (CloneNotSupportedException e) {
+ } // cannot possibly happen
+
+ final long delay = firstDelay(sch[pid[i]].step);
+ final long nexttime = Math.max(time, sch[pid[i]].from) + delay;
+ if (nexttime < sch[pid[i]].until)
+ EDSimulator.add(nexttime - time, nceclone, n, pid[i]);
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Returns the time (through giving the delay from the current time) when
+ * this even is first executed. If {@value #PAR_RNDSTART} is not set, it
+ * returns zero, otherwise a random value between 0, inclusive, and
+ * cyclelength, exclusive.
+ *
+ * @param cyclelength
+ * The cycle length of the cycle based protocol for which this
+ * method is called
+ */
+ protected long firstDelay(long cyclelength) {
+
+ if (randstart)
+ return CommonState.r.nextLong(cyclelength);
+ else
+ return 0;
+ }
+}
diff --git a/contrib/psg/src/peersim/edsim/ControlEvent.java b/contrib/psg/src/peersim/edsim/ControlEvent.java
new file mode 100644
index 0000000000..8c12d3a330
--- /dev/null
+++ b/contrib/psg/src/peersim/edsim/ControlEvent.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.edsim;
+
+import peersim.core.Control;
+import peersim.core.Scheduler;
+
+
+/**
+ * Wrapper for {@link Control}s to be executed in an event driven simulation.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.5 $
+ */
+class ControlEvent
+{
+
+//---------------------------------------------------------------------
+//Fields
+//---------------------------------------------------------------------
+
+/**
+ * The reference to the dynamics to be executed; null if this cycle event
+ * refers to an observer.
+ */
+private Control control;
+
+/** Order index used to maintain order between cycle-based events */
+private int order;
+
+
+//---------------------------------------------------------------------
+//Initialization
+//---------------------------------------------------------------------
+
+/**
+ * Scheduler object to obtain the next schedule time of this event
+ */
+private Scheduler scheduler;
+
+/**
+ * Creates a cycle event for a control object. It also schedules the object
+ * for the first execution adding it to the priority queue of the event driven
+ * simulation.
+ */
+public ControlEvent(Control control, Scheduler scheduler, int order)
+{
+ this.control = control;
+ this.order = order;
+ this.scheduler = scheduler;
+ long next = scheduler.getNext();
+ if( next>=0 ) EDSimulator.addControlEvent(next, order, this);
+}
+
+//---------------------------------------------------------------------
+//Methods
+//---------------------------------------------------------------------
+
+/**
+* Executes the control object, and schedules the object for the next execution
+* adding it to the priority queue of the event driven simulation.
+*/
+public boolean execute() {
+
+ boolean ret = control.execute();
+ long next = scheduler.getNext();
+ if( next>=0 ) EDSimulator.addControlEvent(next, order, this);
+ return ret;
+}
+
+}
+
+
diff --git a/contrib/psg/src/peersim/edsim/EDProtocol.java b/contrib/psg/src/peersim/edsim/EDProtocol.java
new file mode 100644
index 0000000000..60c83a2e45
--- /dev/null
+++ b/contrib/psg/src/peersim/edsim/EDProtocol.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.edsim;
+
+import peersim.core.*;
+
+/**
+ * The interface to be implemented by protocols run under the event-driven
+ * model. A single method is provided, to deliver events to the protocol.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.5 $
+ */
+public interface EDProtocol
+extends Protocol
+{
+
+ /**
+ * This method is invoked by the scheduler to deliver events to the
+ * protocol. Apart from the event object, information about the node
+ * and the protocol identifier are also provided. Additional information
+ * can be accessed through the {@link CommonState} class.
+ *
+ * @param node the local node
+ * @param pid the identifier of this protocol
+ * @param event the delivered event
+ */
+ public void processEvent( Node node, int pid, Object event );
+
+}
+
diff --git a/contrib/psg/src/peersim/edsim/EDSimulator.java b/contrib/psg/src/peersim/edsim/EDSimulator.java
new file mode 100644
index 0000000000..e56d021833
--- /dev/null
+++ b/contrib/psg/src/peersim/edsim/EDSimulator.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.edsim;
+
+import java.util.Arrays;
+
+import peersim.Simulator;
+import peersim.config.*;
+import peersim.core.*;
+import psgsim.PSGSimulator;
+
+/**
+ * Event-driven simulator engine. It is a fully static singleton class. For an
+ * event driven simulation the configuration has to describe a set of
+ * {@link Protocol}s, a set of {@link Control}s and their ordering and a set of
+ * initializers and their ordering. See parameters {@value #PAR_INIT},
+ * {@value #PAR_CTRL}.
+ *
+ * One experiment run by {@link #nextExperiment} works as follows. First the
+ * initializers are run in the specified order. Then the first execution of all
+ * specified controls is scheduled in the event queue. This scheduling is
+ * defined by the {@link Scheduler} parameters of each control component. After
+ * this, the first event is taken from the event queue. If the event wraps a
+ * control, the control is executed, otherwise the event is delivered to the
+ * destination protocol, that must implement {@link EDProtocol}. This is
+ * iterated while the current time is less than {@value #PAR_ENDTIME} or the
+ * queue becomes empty. If more control events fall at the same time point, then
+ * the order given in the configuration is respected. If more non-control events
+ * fall at the same time point, they are processed in a random order.
+ *
+ * The engine also provides the interface to add events to the queue. Note that
+ * this engine does not explicitly run the protocols. In all cases at least one
+ * control or initializer has to be defined that sends event(s) to protocols.
+ *
+ * Controls can be scheduled (using the {@link Scheduler} parameters in the
+ * configuration) to run after the experiment has finished. That is, each
+ * experiment is finished by running the controls that are scheduled to be run
+ * after the experiment.
+ *
+ * Any control can interrupt an experiment at any time it is executed by
+ * returning true in method {@link Control#execute}. However, the controls
+ * scheduled to run after the experiment are still executed completely,
+ * irrespective of their return value and even if the experiment was
+ * interrupted.
+ *
+ * {@link CDScheduler} has to be mentioned that is a control that can bridge the
+ * gap between {@link peersim.cdsim} and the event driven engine. It can wrap
+ * {@link peersim.cdsim.CDProtocol} appropriately so that the execution of the
+ * cycles are scheduled in configurable ways for each node individually. In some
+ * cases this can add a more fine-grained control and more realism to
+ * {@link peersim.cdsim.CDProtocol} simulations, at the cost of some loss in
+ * performance.
+ *
+ * When protocols at different nodes send messages to each other, they might
+ * want to use a model of the transport layer so that in the simulation message
+ * delay and message omissions can be modeled in a modular way. This
+ * functionality is implemented in package {@link peersim.transport}.
+ *
+ * @see Configuration
+ */
+public class EDSimulator {
+
+ // ---------------------------------------------------------------------
+ // Parameters
+ // ---------------------------------------------------------------------
+
+ /**
+ * The ending time for simulation. Only events that have a strictly smaller
+ * value are executed. It must be positive. Although in principle negative
+ * timestamps could be allowed, we assume time will be positive.
+ *
+ * @config
+ */
+ public static final String PAR_ENDTIME = "simulation.endtime";
+
+ /**
+ * This parameter specifies how often the simulator should log the current
+ * time on the standard error. The time is logged only if there were events
+ * in the respective interval, and only the time of some actual event is
+ * printed. That is, the actual log is not guaranteed to happen in identical
+ * intervals of time. It is merely a way of seeing whether the simulation
+ * progresses and how fast...
+ *
+ * @config
+ */
+ private static final String PAR_LOGTIME = "simulation.logtime";
+
+ /**
+ * This parameter specifies the event queue to be used. It must be an
+ * implementation of interface {@link PriorityQ}. If it is not defined, the
+ * internal implementation is used.
+ *
+ * @config
+ */
+ private static final String PAR_PQ = "simulation.eventqueue";
+
+ /**
+ * This is the prefix for initializers. These have to be of type
+ * {@link Control}. They are run at the beginning of each experiment, in the
+ * order specified by the configuration.
+ *
+ * @see Configuration
+ * @config
+ * @config
+ */
+ private static final String PAR_INIT = "init";
+
+ /**
+ * This is the prefix for {@link Control} components. They are run at the
+ * time points defined by the {@link Scheduler} associated to them. If some
+ * controls have to be executed at the same time point, they are executed in
+ * the order specified in the configuration.
+ *
+ * @see Configuration
+ * @config
+ */
+ private static final String PAR_CTRL = "control";
+
+ // ---------------------------------------------------------------------
+ // Fields
+ // ---------------------------------------------------------------------
+
+ /** Maximum time for simulation */
+ private static long endtime;
+
+ /** Log time */
+ private static long logtime;
+
+ /** holds the modifiers of this simulation */
+ private static Control[] controls = null;
+
+ /** Holds the control schedulers of this simulation */
+ private static Scheduler[] ctrlSchedules = null;
+
+ /** Ordered list of events (heap) */
+ private static PriorityQ heap = null;
+
+ private static long nextlog = 0;
+
+ // =============== initialization ======================================
+ // =====================================================================
+
+ /** to prevent construction */
+ private EDSimulator() {
+ }
+
+ // ---------------------------------------------------------------------
+ // Private methods
+ // ---------------------------------------------------------------------
+
+ /**
+ * Load and run initializers.
+ */
+ private static void runInitializers() {
+
+ Object[] inits = Configuration.getInstanceArray(PAR_INIT);
+ String names[] = Configuration.getNames(PAR_INIT);
+
+ for (int i = 0; i < inits.length; ++i) {
+
+ System.err.println("- Running initializer " + names[i] + ": "
+ + inits[i].getClass());
+ ((Control) inits[i]).execute();
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ private static void scheduleControls() {
+ // load controls
+ String[] names = Configuration.getNames(PAR_CTRL);
+ controls = new Control[names.length];
+ ctrlSchedules = new Scheduler[names.length];
+ for (int i = 0; i < names.length; ++i) {
+ controls[i] = (Control) Configuration.getInstance(names[i]);
+ ctrlSchedules[i] = new Scheduler(names[i], false);
+ }
+ System.err.println("EDSimulator: loaded controls "
+ + Arrays.asList(names));
+
+ // Schedule controls execution
+ if (controls.length > heap.maxPriority() + 1)
+ throw new IllegalArgumentException("Too many control objects");
+ for (int i = 0; i < controls.length; i++) {
+ new ControlEvent(controls[i], ctrlSchedules[i], i);
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ /**
+ * Adds a new event to be scheduled, specifying the number of time units of
+ * delay, and the execution order parameter.
+ *
+ * @param time
+ * The actual time at which the next event should be scheduled.
+ * @param order
+ * The index used to specify the order in which control events
+ * should be executed, if they happen to be at the same time,
+ * which is typically the case.
+ * @param event
+ * The control event
+ */
+ static void addControlEvent(long time, int order, ControlEvent event) {
+ // we don't check whether time is negative or in the past: we trust
+ // the caller, which must be from this package
+ if (time >= endtime)
+ return;
+ heap.add(time, event, null, (byte) 0, order);
+ }
+
+ // ---------------------------------------------------------------------
+
+ /**
+ * This method is used to check whether the current configuration can be
+ * used for event driven simulations. It checks for the existence of config
+ * parameter {@value #PAR_ENDTIME}.
+ */
+ public static final boolean isConfigurationEventDriven() {
+ return Configuration.contains(PAR_ENDTIME);
+ }
+
+ // ---------------------------------------------------------------------
+
+ /**
+ * Execute and remove the next event from the ordered event list.
+ *
+ * @return true if the execution should be stopped.
+ */
+ private static boolean executeNext() {
+ PriorityQ.Event ev = heap.removeFirst();
+ if (ev == null) {
+ System.err.println("EDSimulator: queue is empty, quitting"
+ + " at time " + CommonState.getTime());
+ return true;
+ }
+
+ long time = ev.time;
+
+ if (time >= nextlog) {
+ // System.err.println("Current time: " + time);
+ // seemingly complicated: to prevent overflow
+ while (time - nextlog >= logtime)
+ nextlog += logtime;
+ if (endtime - nextlog >= logtime)
+ nextlog += logtime;
+ else
+ nextlog = endtime;
+ }
+ if (time >= endtime) {
+ System.err.println("EDSimulator: reached end time, quitting,"
+ + " leaving " + heap.size()
+ + " unprocessed events in the queue");
+ return true;
+ }
+
+ CommonState.setTime(time);
+ int pid = ev.pid;
+ if (ev.node == null) {
+ // might be control event; handled through a special method
+ ControlEvent ctrl = null;
+ try {
+ ctrl = (ControlEvent) ev.event;
+ } catch (ClassCastException e) {
+ throw new RuntimeException(
+ "No destination specified (null) for event " + ev);
+ }
+ return ctrl.execute();
+ } else if (ev.node != Network.prototype && ev.node.isUp()) {
+ CommonState.setPid(pid);
+ CommonState.setNode(ev.node);
+ if (ev.event instanceof NextCycleEvent) {
+ NextCycleEvent nce = (NextCycleEvent) ev.event;
+ nce.execute();
+ } else {
+ EDProtocol prot = null;
+ try {
+ prot = (EDProtocol) ev.node.getProtocol(pid);
+ // System.out.println("prot "+prot.getClass().getName());
+ } catch (ClassCastException e) {
+ e.printStackTrace();
+ throw new IllegalArgumentException("Protocol "
+ + Configuration.lookupPid(pid)
+ + " does not implement EDProtocol; "
+ + ev.event.getClass());
+ }
+ prot.processEvent(ev.node, pid, ev.event);
+ }
+ }
+
+ return false;
+ }
+
+ // ---------------------------------------------------------------------
+ // Public methods
+ // ---------------------------------------------------------------------
+
+ /**
+ * Runs an experiment, resetting everything except the random seed.
+ */
+ public static void nextExperiment() {
+ // Reading parameter
+ if (Configuration.contains(PAR_PQ))
+ heap = (PriorityQ) Configuration.getInstance(PAR_PQ);
+ else
+ heap = new Heap();
+ endtime = Configuration.getLong(PAR_ENDTIME);
+ if (CommonState.getEndTime() < 0) // not initialized yet
+ CommonState.setEndTime(endtime);
+ if (heap.maxTime() < endtime)
+ throw new IllegalParameterException(PAR_ENDTIME,
+ "End time is too large: configured event queue only"
+ + " supports " + heap.maxTime());
+ logtime = Configuration.getLong(PAR_LOGTIME, Long.MAX_VALUE);
+
+ // initialization
+ System.err.println("EDSimulator: resetting");
+ CommonState.setPhase(CommonState.PHASE_UNKNOWN);
+ CommonState.setTime(0); // needed here
+ controls = null;
+ ctrlSchedules = null;
+ nextlog = 0;
+ Network.reset();
+ System.err.println("EDSimulator: running initializers");
+ runInitializers();
+ scheduleControls();
+ // Perform the actual simulation; executeNext() will tell when to
+ // stop.
+ boolean exit = false;
+ while (!exit) {
+ exit = executeNext();
+ }
+
+ // analysis after the simulation
+ CommonState.setPhase(CommonState.POST_SIMULATION);
+ for (int j = 0; j < controls.length; ++j) {
+ if (ctrlSchedules[j].fin)
+ controls[j].execute();
+ }
+
+ }
+
+ // ---------------------------------------------------------------------
+
+ /**
+ * Adds a new event to be scheduled, specifying the number of time units of
+ * delay, and the node and the protocol identifier to which the event will
+ * be delivered.
+ *
+ * @param delay
+ * The number of time units before the event is scheduled. Has to
+ * be non-negative.
+ * @param event
+ * The object associated to this event
+ * @param node
+ * The node associated to the event.
+ * @param pid
+ * The identifier of the protocol to which the event will be
+ * delivered
+ */
+ public static void add(long delay, Object event, Node node, int pid) {
+ //if (event instanceof NextCycleEvent)
+ //System.err.println("************* edsim delay="+delay +" pid="+pid+" event="+event+" time="+CommonState.getTime());
+ if (Simulator.getSimID() == 2){
+ PSGSimulator.add(delay, event, node, pid);
+ }
+
+ else {
+ if (delay < 0)
+ throw new IllegalArgumentException("Protocol "
+ + node.getProtocol(pid) + " is trying to add event "
+ + event + " with a negative delay: " + delay);
+ if (pid > Byte.MAX_VALUE)
+ throw new IllegalArgumentException(
+ "This version does not support more than "
+ + Byte.MAX_VALUE + " protocols");
+
+ long time = CommonState.getTime();
+ if (endtime - time > delay) // check like this to deal with overflow
+ heap.add(time + delay, event, node, (byte) pid);
+ }
+ }
+
+}
diff --git a/contrib/psg/src/peersim/edsim/Heap.java b/contrib/psg/src/peersim/edsim/Heap.java
new file mode 100644
index 0000000000..eb123acd82
--- /dev/null
+++ b/contrib/psg/src/peersim/edsim/Heap.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2001 The Anthill Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.edsim;
+
+import peersim.core.Node;
+import peersim.core.CommonState;
+import peersim.config.Configuration;
+import peersim.config.IllegalParameterException;
+
+/**
+ * The Heap data structure used to maintain events "sorted" by
+ * scheduled time and to obtain the next event to be executed.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.10 $
+ */
+public class Heap implements PriorityQ {
+
+//--------------------------------------------------------------------------
+// Constants
+//--------------------------------------------------------------------------
+
+/**
+ * This parameter specifies how many
+ * bits are used to order events that occur at the same time. Defaults
+ * to 8. A value smaller than 8 causes an IllegalParameterException.
+ * Higher values allow for a better discrimination, but reduce
+ * the maximal time steps that can be simulated.
+ * @config
+ */
+private static final String PAR_PBITS = "pbits";
+private static final String PAR_PBITS_LEGACY = "simulation.timebits";
+
+/**
+ * Specifies the initial capacity of the heap. Defaults to 65536.
+ * @config
+ */
+private static final String PAR_SIZE = "size";
+
+
+//--------------------------------------------------------------------------
+// Fields
+//--------------------------------------------------------------------------
+
+// The following arrays are four heaps ordered by time. The alternative
+// approach (i.e. to store event objects) requires much more memory,
+// and based on some tests that I've done is not really much faster.
+
+/** Event component of the heap */
+private Object[] events;
+
+/** Time component of the heap */
+private long[] times;
+
+/** Node component of the heap */
+private Node[] nodes;
+
+/** Pid component of the heap */
+private byte[] pids;
+
+/** Number of elements */
+private int size;
+
+/** Singleton event object used to return (event, time, node, pid) tuples */
+private final Event ev = new Event();
+
+/** The number of bits reserved to order event with the same timestamp */
+private final int pbits;
+
+/** The mask to test whether the time value fits into the range we can
+represent */
+private final long overflowMask;
+
+//--------------------------------------------------------------------------
+// Contructor
+//--------------------------------------------------------------------------
+
+/**
+ * Initializes a new heap using defaults.
+ */
+public Heap() {
+ this(""); // "" is not a valid prefix for a component
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Initializes a new heap using the configuration.
+ */
+public Heap(String prefix) {
+
+ int size = Configuration.getInt(prefix+"."+PAR_SIZE,65536);
+
+ // some complex stuff to deal with legacy parameter names...
+ if( !Configuration.contains(PAR_PBITS_LEGACY) )
+ pbits = Configuration.getInt(prefix+"."+PAR_PBITS,8);
+ else
+ {
+ pbits = Configuration.getInt(PAR_PBITS_LEGACY);
+ if( Configuration.contains(prefix+"."+PAR_PBITS) )
+ throw new IllegalParameterException(PAR_PBITS_LEGACY,
+ "Your configuration file contains both "+
+ prefix+"."+PAR_PBITS+ " and "+
+ PAR_PBITS_LEGACY+"; please remove "+
+ PAR_PBITS_LEGACY);
+ }
+
+ if (pbits < 8 || pbits >= 31) {
+ throw new IllegalParameterException(prefix+"."+PAR_PBITS,
+ "This parameter should be >= 8 or < 31");
+ }
+ overflowMask = ~maxTime();
+ events = new Object[size];
+ times = new long[size];
+ nodes = new Node[size];
+ pids = new byte[size];
+}
+
+//--------------------------------------------------------------------------
+// Methods
+//--------------------------------------------------------------------------
+
+/**
+ * Returns the current number of events in the system.
+ */
+public int size()
+{
+ return size;
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Add a new event, to be scheduled at the specified time.
+ *
+ * @param time the time at which this event should be scheduled
+ * @param event the object describing the event
+ * @param node the node at which the event has to be delivered
+ * @param pid the protocol that handles the event
+ */
+public void add(long time, Object event, Node node, byte pid)
+{
+ add(time,event,node,pid,CommonState.r.nextInt(1 << pbits));
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Add a new event, to be scheduled at the specified time.
+ *
+ * @param time the time at which this event should be scheduled
+ * @param event the object describing the event
+ * @param node the node at which the event has to be delivered
+ * @param pid the protocol that handles the event
+ */
+public void add(long time, Object event, Node node, byte pid, long priority)
+{
+ if( (time&overflowMask) != 0 ) throw new
+ IllegalArgumentException("Time overflow: time="+time);
+//XXX should we test priority overflow? How much does it cost?
+
+ time = (time << pbits) | priority;
+
+ size++;
+ int pos = size;
+ put(pos, time, event, node, pid);
+ while (pos > 1 && getTime(pos / 2) > time) {
+ swap(pos, pos / 2);
+ pos = pos / 2;
+ }
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ * Removes the first event in the heap and returns it.
+ * Note that, to avoid garbage collection, a singleton instance of
+ * the Event class is used. This means that data contained in the
+ * returned event are overwritten when a new invocation of this
+ * method is performed.
+ * @return first event or null if size is zero
+ */
+public Event removeFirst() {
+
+ if(size==0) return null;
+
+ ev.time = times[0] >> pbits;
+ ev.event = events[0];
+ ev.node = nodes[0];
+ ev.pid = pids[0];
+ swap(1, size);
+ size--;
+ minHeapify(1);
+ return ev;
+}
+
+//--------------------------------------------------------------------------
+
+public long maxTime() { return Long.MAX_VALUE >> pbits; }
+
+//--------------------------------------------------------------------------
+
+public long maxPriority() { return (1L << pbits)-1; }
+
+//--------------------------------------------------------------------------
+
+/**
+ * Prints the time values contained in the heap.
+ */
+public String toString()
+{
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("[Size: " + size + " Times: ");
+ for (int i=1; i <= size; i++) {
+ buffer.append(getTime(i)+",");
+ }
+ buffer.append("]");
+ return buffer.toString();
+}
+
+
+//--------------------------------------------------------------------------
+// Private methods
+//--------------------------------------------------------------------------
+
+/**
+ *
+ */
+private void minHeapify(int index)
+{
+ // The time to be placed of the current node
+ long time = getTime(index);
+ // Left, right children of the current index
+ int l,r;
+ // Their associated time
+ long lt, rt;
+ // The minimum time between val, lt, rt
+ long mintime;
+ // The index of the mininum time
+ int minindex = index;
+ do {
+ index = minindex;
+ mintime = time;
+ l = index << 1;
+ r = l + 1;
+ if (l <= size && (lt = getTime(l)) < mintime) {
+ minindex = l;
+ mintime = lt;
+ }
+ if (r <= size && (rt = getTime(r)) < mintime) {
+ minindex = r;
+ mintime = rt;
+ }
+ if (minindex != index) {
+ swap(minindex, index);
+ }
+ } while (minindex != index);
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ *
+ */
+private void swap(int i1, int i2) {
+
+ i1--;
+ i2--;
+
+ Object te = events[i1];
+ events[i1] = events[i2];
+ events[i2] = te;
+
+ long tt = times[i1];
+ times[i1] = times[i2];
+ times[i2] = tt;
+
+ Node tn = nodes[i1];
+ nodes[i1] = nodes[i2];
+ nodes[i2] = tn;
+
+ byte tp = pids[i1];
+ pids[i1] = pids[i2];
+ pids[i2] = tp;
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ *
+ */
+private long getTime(int index) {
+ /* Compute first and second index, and return the value */
+ index--;
+ return times[index];
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ *
+ */
+private void put(int index, long time, Object event, Node node, byte pid) {
+
+ index--;
+ if (index >= events.length) {
+ doubleCapacity();
+ }
+ events[index] = event;
+ times[index] = time;
+ nodes[index] = node;
+ pids[index] = pid;
+}
+
+//--------------------------------------------------------------------------
+
+/**
+ *
+ */
+private void doubleCapacity() {
+ int oldsize = events.length;
+ int newsize = oldsize*2;
+ Object[] te = new Object[newsize];
+ System.arraycopy(events, 0, te, 0, oldsize);
+ events = te;
+ long[] tt = new long[newsize];
+ System.arraycopy(times, 0, tt, 0, oldsize);
+ times = tt;
+ Node[] tn = new Node[newsize];
+ System.arraycopy(nodes, 0, tn, 0, oldsize);
+ nodes = tn;
+ byte[] tp = new byte[newsize];
+ System.arraycopy(pids, 0, tp, 0, oldsize);
+ pids = tp;
+}
+
+//--------------------------------------------------------------------------
+// Testing
+//--------------------------------------------------------------------------
+
+/*
+public static void main(String[] args) {
+ Random random = new Random();
+ Heap heap = new Heap();
+ int rep = 1000000;
+ if( args.length > 0 ) rep = Integer.parseInt(args[0]);
+ int[] values1 = new int[rep];
+ long[] values2 = new long[rep];
+ for (int i = 0; i < rep; i++) {
+ values1[i] = random.nextInt(1000000000);
+ }
+
+ long time1 = System.currentTimeMillis();
+ for (int i = 0; i < rep; i++) {
+ heap.add(values1[i], null, null, (byte) 1);
+ }
+ long time2 = System.currentTimeMillis();
+ System.out.println("Inserting: " + (time2-time1));
+
+ time1 = System.currentTimeMillis();
+ for (int i = 0; i < rep; i++) {
+ values2[i] = heap.removeFirst().time;
+ }
+ time2 = System.currentTimeMillis();
+ System.out.println("Removing: " + (time2-time1));
+
+ Arrays.sort(values1);
+ for (int i=0; i{@value peersim.config.Configuration#PAR_INCLUDE}+"."+name
or
+ * {@value peersim.config.Configuration#PAR_ORDER}+"."+name
then the order is
+ * alphabetical. Otherwise this entry defines the order. For more
+ * information see {@link Configuration}.
+ * @param name
+ * the component type (i.e., the prefix)
+ * @return the full property names in the order specified by the
+ * configuration
+ */
+public String[] getNames(String name)
+{
+ ArrayListnames
(e.g.
+ * initializers, controls and protocols) and a string specifying the type
+ * (prefix) of these. The output is in names
, which will
+ * contain a permutation of the original array. Parameter
+ * PAR_INCLUDE+"."+type, or if not present, PAR_ORDER+"."+type is read from
+ * the configuration. If none of them are defined then the order is
+ * identical to that of names
. Otherwise the configuration
+ * entry must contain entries from names
. It is assumed
+ * that the entries in names
contain only word characters
+ * (alphanumeric and underscore '_'. The order configuration entry thus
+ * contains a list of entries from names
separated by any
+ * non-word characters.
+ * resource
is used to attempt
+* loading default values from the given system resource.
+* Then all Strings in pars
are processed in the order they
+* appear in the array. For pars[i]
, first a property file
+* with the name pars[i]
is attempted to be loaded. If the file
+* does not exist or loading produces any other IOException, pars[i]
+* is interpreted as a property definition, and it is set.
+* pars[i]
is supposed to be
+* a command line argument, but it is a valid filename at the same time by
+* accident, the algorithm will process it as a file instead of a command line
+* argument. The caller must take care of that.
+* Properties.load
with a file
+* input stream to the given file.
+*/
+public void load( String fileName ) throws IOException {
+
+ FileInputStream fis = new FileInputStream( fileName );
+ load( fis );
+ fis.close();
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Adds the properties from the given property file. Searches in the class path
+* for the file with the given name.
+*/
+public void loadSystemResource( String n ) throws IOException {
+
+ ClassLoader cl = getClass().getClassLoader();
+ load( cl.getResourceAsStream( n ) );
+}
+
+// -------------------------------------------------------------------
+
+/**
+* Appends a property defined in the given string.
+* The string is considered as a property file line.
+* It is converted to a byte array according to the
+* default character encoding and then loaded by the
+* Properties.load
method. This means that the ISO-8859-1
+* (or compatible) encoding is assumed.
+*/
+public void loadPropertyString( String prop ) throws IOException {
+
+ StringBuffer sb = new StringBuffer();
+ sb.append( prop ).append( "\n" );
+ load( new ByteArrayInputStream(sb.toString().getBytes()) );
+}
+}
+
diff --git a/contrib/psg/src/peersim/config/Configuration.java b/contrib/psg/src/peersim/config/Configuration.java
new file mode 100644
index 0000000000..4188111bef
--- /dev/null
+++ b/contrib/psg/src/peersim/config/Configuration.java
@@ -0,0 +1,668 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.config;
+
+import java.util.*;
+
+/**
+ * Fully static class to store configuration information. It defines a
+ * method, {@link #setConfig(Properties)}, to set configuration data. This
+ * method is called by the simulator engines as the very first thing they
+ * do. It can be called only once, after that the class becomes read only.
+ * All components can then access this configuration and utility methods to
+ * read property values based on their names.
+ * Typed reading of values
+ * Properties can have arbitrary values of type String. This class offers a
+ * set of read methods that perform the appropriate conversion of the
+ * string value to the given type, eg long. They also allow for specifying
+ * default values in case the given property is not specified.
+ * Resolving class names
+ *
+ * The possibilities for the typed reading of a value includes interpreting
+ * the value as a class name. In this case an object will be constructed.
+ * It is described at method {@link #getInstance(String)} how this is
+ * achieved exactly. What needs to be noted here is that the property value
+ * need not be a fully specified classname. It might contain only the short
+ * class name without the package specification. In this case, it is
+ * attempted to locate a class with that name in the classpath, and if a
+ * unique class is found, it will be used. This simplifies the
+ * configuration files and also allows to remove their dependence on the
+ * exact location of the class.
+ *
+ * Components and their ordering
+ * The idea of the configuration is that it mostly contains components and
+ * their descriptions (parameters). Although this class is blind to the
+ * semantics of these components, it offers some low level functionality
+ * that helps dealing with them. This functionality is based on the
+ * assumption that components have a type and a name. Both types and names
+ * are strings of alphanumeric and underscore characters. For example,
+ * {@value #PAR_PROT} is a type, "foo" can be a name. Method
+ * {@link #getNames} allow the caller to get the list of names for a given
+ * type. Some other methods, like {@link #getInstanceArray} use this list
+ * to return a list of components.
+ *
+ *
+ * control.conn ConnectivityObserver
+ * control.1 WireKOut
+ * control.2 PrintGraph
+ *
+ *
+ * defines control components of names "conn","1" an "2" (arguments of the
+ * components not shown). When {@link #getNames} or
+ * {@link #getInstanceArray} are called, eg
+ * getNames("control")
, then the order in which these are
+ * returned is alphabetical:
+ * ["control.1","control.2","control.conn"]
. If you are not
+ * satisfied with lexicographic order, you can specify the order in this
+ * way.
+ *
+ *
+ * order.control 1,conn,2
+ *
+ *
+ * where the names are separated by any non-word character (non
+ * alphanumeric or underscore). If not all names are listed then the given
+ * order is followed by alphabetical order of the rest of the items, e.g.
+ *
+ *
+ * order.control 2
+ *
+ *
+ * results in ["control.2","control.1","control.conn"]
.
+ * include
. For example
+ *
+ *
+ * include.control conn 2
+ *
+ *
+ * will result in returning only control.conn
and
+ * control.2
, in this order. Note that for example the
+ * empty list results in a zero length array in this case.
+ * Important! If include is defined then ordering is ignored.
+ * That is, include is stronger than order.
+ * Protocol names
+ * As mentioned, the configuration is generally blind to the actual names
+ * of the components. There is an exception: the components of type
+ * {@value #PAR_PROT}. These are pre-processed a bit to enhance
+ * performance: protocol names are mapped to numeric protocol identifiers.
+ * The numeric identifier of a protocol is its index in the array returned
+ * by {@link #getNames}. See above how to control this order. The numeric
+ * identifiers then can be looked up based on the name and vice versa.
+ * Besides, the identifier can be directly requested based on a property
+ * name when the protocol name is the value of a property which is
+ * frequently the case.
+ * Expressions
+ * Numeric property values can be complex expressions, that are parsed
+ * using JEP. You can write
+ * expression using the syntax that you can find here.
+ * For example,
+ *
+ *
+ * MAG 2
+ * SIZE 2ˆMAG
+ *
+ *
+ * SIZE=4. You can also have complex expression trees like this:
+ *
+ *
+ * A B+C
+ * B D+E
+ * C E+F
+ * D 1
+ * E F
+ * F 2
+ *
+ *
+ * that results in A=7, B=3, C=4, D=1, E=2, F=2
+ *
+ *
+ * overlay.size SIZE
+ * SIZE SIZE-1
+ *
+ *
+ * you get an error message: Parameter "overlay.size": Probable recursive
+ * definition - exceeded maximum depth {@value #DEFAULT_MAXDEPTH}
+ *
+ * Debug
+ *
+ * It is possible to obtain debug information about the configuration
+ * properties by activating special configuration properties.
+ * Use of brackets
+ *
+ * For the sake of completeness, we mention it here that if this class is
+ * initialized using {@link ParsedProperties}, then it is possible to use
+ * some more compressed format to specify the components. See
+ * {@link ParsedProperties#load}.
+ *
+ */
+public class Configuration
+{
+
+// =================== static fields =================================
+// ===================================================================
+
+/** Default max depth limit to avoid recursive definitions */
+public static final int DEFAULT_MAXDEPTH = 100;
+
+/**
+ * The debug level for the configuration. If defined, a line is printed for
+ * each configuration parameter read. If defined and equal to
+ * {@value #DEBUG_EXTENDED}, additional context information for debug is
+ * printed. If defined and equal to {@value #DEBUG_FULL}, all the
+ * configuration properties are printed at the beginning, not just when
+ * they are called.
+ * @config
+ */
+static final String PAR_DEBUG = "debug.config";
+
+/**
+ * If parameter {@value #PAR_DEBUG} is equal to this string, additional
+ * context information for debug is printed.
+ */
+static final String DEBUG_EXTENDED = "context";
+
+/**
+ * If parameter {value #PAR_DEBUG} is equal to this string, all the
+ * configuration properties are printed at the beginning, not just when
+ * they are called.
+ */
+static final String DEBUG_FULL = "full";
+
+/**
+ * The maximum depth for expressions. This is a simple mechanism to avoid
+ * unbounded recursion. The default is {@value #DEFAULT_MAXDEPTH}, and you
+ * probably don't want to change it.
+ * @config
+ */
+static final String PAR_MAXDEPTH = "expressions.maxdepth";
+
+/**
+ * Used to configure ordering of the components. Determines the ordering in
+ * the array as returned by {@link #getNames}. See the general description
+ * of {@link Configuration} for details.
+ * @config
+ */
+static final String PAR_ORDER = "order";
+
+/**
+ * Used to configure ordering of the components. Determines the ordering in
+ * the array as returned by {@link #getNames}, and can bu used to also
+ * exclude elements. See the general description of {@link Configuration}
+ * for details.
+ * @config
+ */
+static final String PAR_INCLUDE = "include";
+
+// XXX it's ugly because it replicates the definition of Node.PAR_PROT, but
+// this would be the only dependence on the rest of the core...
+/**
+ * The type name of components describing protocols. This is the only point
+ * at which the class is not blind to the actual semantics of the
+ * configuration.
+ */
+static final String PAR_PROT = "protocol";
+
+/**
+ * The properties object that stores all configuration information.
+ */
+private static ConfigContainer config = null;
+
+// =================== initialization ================================
+// ===================================================================
+
+/** to prevent construction */
+private Configuration()
+{
+}
+
+// =================== static public methods =========================
+// ===================================================================
+
+/**
+ * Sets the system-wide configuration in Properties format. It can be
+ * called only once. After that the configuration becomes unmodifiable
+ * (read only). If modification is attempted, a RuntimeException is thrown
+ * and no change is made.
+ * @param p
+ * The Properties object containing configuration info
+ */
+public static void setConfig(Properties p)
+{
+ if (config != null) {
+ throw new RuntimeException("Setting configuration was attempted twice.");
+ }
+ config = new ConfigContainer(p, false);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Sets the system-wide configuration in Properties format. It can be
+ * called only once. After that the configuration becomes unmodifiable
+ * (read only). If modification is attempted, a RuntimeException is thrown
+ * and no change is made.
+ * @param p
+ * The Properties object containing configuration info
+ */
+public static void setConfig(Properties p, boolean check)
+{
+ if (config != null) {
+ throw new RuntimeException("Setting configuration was attempted twice.");
+ }
+ config = new ConfigContainer(p, check);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * @return true if and only if name is a specified (existing) property.
+ */
+public static boolean contains(String name)
+{
+ return config.contains(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * {@link MissingParameterException}.
+ * @param name
+ * Name of configuration property
+ * @param def
+ * default value
+ */
+public static boolean getBoolean(String name, boolean def)
+{
+ return config.getBoolean(name, def);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given property. If not found, or the value is empty string then
+ * throws a {@link MissingParameterException}. Empty string is not
+ * accepted as false due to the similar function of {@link #contains} which
+ * returns true in that case. True is returned if the lowercase value of
+ * the property is "true", otherwise false is returned.
+ * @param name
+ * Name of configuration property
+ */
+public static boolean getBoolean(String name)
+{
+ return config.getBoolean(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ * Name of configuration property
+ * @param def
+ * default value
+ */
+public static int getInt(String name, int def)
+{
+ return config.getInt(name, def);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * {@link MissingParameterException}.
+ * @param name
+ * Name of configuration property
+ */
+public static int getInt(String name)
+{
+ return config.getInt(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ * Name of configuration property
+ * @param def
+ * default value
+ */
+public static long getLong(String name, long def)
+{
+ return config.getLong(name, def);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * {@link MissingParameterException}.
+ * @param name
+ * Name of configuration property
+ */
+public static long getLong(String name)
+{
+ return config.getLong(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ * Name of configuration property
+ * @param def
+ * default value
+ */
+public static double getDouble(String name, double def)
+{
+ return config.getDouble(name, def);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * MissingParameterException.
+ * @param name
+ * Name of configuration property
+ */
+public static double getDouble(String name)
+{
+ return config.getDouble(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, returns the default
+ * value.
+ * @param name
+ * Name of configuration property
+ * @param def
+ * default value
+ */
+public static String getString(String name, String def)
+{
+ return config.getString(name, def);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads given configuration property. If not found, throws a
+ * MissingParameterException. Removes trailing whitespace characters.
+ * @param name
+ * Name of configuration property
+ */
+public static String getString(String name)
+{
+ return config.getString(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Reads the given property from the configuration interpreting it as a
+ * protocol name. Returns the numeric protocol identifier of this protocol
+ * name. See the discussion of protocol name at {@link Configuration} for
+ * details on how this numeric id is calculated
+ *
+ * @param name
+ * Name of configuration property
+ * @return the numeric protocol identifier associated to the value of the
+ * property
+ */
+public static int getPid(String name)
+{
+ return config.getPid(name);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Calls {@link #getPid(String)}, and returns the default if no property
+ * is defined with the given name.
+ *
+ * @param name
+ * Name of configuration property
+ * @param pid
+ * the default protocol identifier
+ * @return the numeric protocol identifier associated to the value of the
+ * property, or the default if not defined
+ */
+public static int getPid(String name, int pid)
+{
+ return config.getPid(name, pid);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Returns the numeric protocol identifier of the given protocol name.
+ *
+ * @param protname
+ * the protocol name.
+ * @return the numeric protocol identifier associated to the protocol name
+ */
+public static int lookupPid(String protname)
+{
+ return config.lookupPid(protname);
+}
+
+// -------------------------------------------------------------------
+
+/**
+ * Returns the name of a protocol that has the given identifier.
+ * {@value #PAR_INCLUDE}+"."+name
or
+ * {@value #PAR_ORDER}+"."+name
then the order is
+ * alphabetical. Otherwise this entry defines the order. For more
+ * information see {@link Configuration}.
+ * @param name
+ * the component type (i.e., the prefix)
+ * @return the full property names in the order specified by the
+ * configuration
+ */
+public static String[] getNames(String name)
+{
+ return config.getNames(name);
+}
+
+}
diff --git a/contrib/psg/src/peersim/config/FastConfig.java b/contrib/psg/src/peersim/config/FastConfig.java
new file mode 100644
index 0000000000..d2eba1b174
--- /dev/null
+++ b/contrib/psg/src/peersim/config/FastConfig.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.config;
+
+/**
+ * Reads configuration regarding relations between protocols.
+ *
+ * Technically, this class is not necessary because protocols could
+ * access the configuration directly. However, it provides much faster
+ * access to "linkable" and "transport" information, enhancing runtime speed.
+ *
+ * This class is a static singleton and is initialized only when first accessed.
+ * During initialization it reads and caches the configuration info it handles.
+ */
+public class FastConfig
+{
+
+// ======================= fields ===========================================
+// ===========================================================================
+
+/**
+ * Parameter name in configuration that attaches a linkable protocol to a
+ * protocol. The property can contain multiple protocol names, in one line,
+ * separated by non-word characters (e.g. whitespace or ",").
+ * @config
+ */
+private static final String PAR_LINKABLE = "linkable";
+
+/**
+ * Parameter name in configuration that attaches a transport layer protocol to a
+ * protocol.
+ * @config
+ */
+private static final String PAR_TRANSPORT = "transport";
+
+/**
+ * This array stores the protocol ids of the {@link peersim.core.Linkable}
+ * protocols that are linked to the protocol given by the array index.
+ */
+protected static final int[][] links;
+
+/**
+ * This array stores the protocol id of the {@link peersim.transport.Transport}
+ * protocol that is linked to the protocol given by the array index.
+ */
+protected static final int[] transports;
+
+
+// ======================= initialization ===================================
+// ==========================================================================
+
+
+/**
+ * This static initialization block reads the configuration for information that
+ * it understands. Currently it understands property {@value #PAR_LINKABLE}
+ * and {@value #PAR_TRANSPORT}.
+ *
+ * Protocols' linkable and transport definitions are prefetched
+ * and stored in arrays, to enable fast access during simulation.
+ *
+ * Note that this class does not perform any type checks. The purpose of the
+ * class is purely to speed up access to linkable and transport information,
+ * by providing a fast alternative to reading directly from the
+ * Configuration
class.
+ */
+static {
+ String[] names = Configuration.getNames(Configuration.PAR_PROT);
+ links = new int[names.length][];
+ transports = new int[names.length];
+ for (int i = 0; i < names.length; ++i)
+ {
+ if (Configuration.contains(names[i] + "." + PAR_LINKABLE))
+ {
+ // get string of linkables
+ String str = Configuration.getString(names[i] + "." + PAR_LINKABLE);
+ // split around non-word characters
+ String[] linkNames = str.split("\\W+");
+ links[i] = new int[linkNames.length];
+ for (int j=0; jlinkIndex
-th linkable used by
+ * the protocol identified by pid. Throws an
+ * IllegalParameterException if there is no linkable associated with the given
+ * protocol: we assume here that this happens when the configuration is
+ * incorrect.
+ */
+public static int getLinkable(int pid, int linkIndex)
+{
+ if (linkIndex >= numLinkables(pid)) {
+ String[] names = Configuration.getNames(Configuration.PAR_PROT);
+ throw new IllegalParameterException(names[pid],
+ "Protocol " + pid + " has no "+PAR_LINKABLE+
+ " parameter with index" + linkIndex);
+ }
+ return links[pid][linkIndex];
+}
+
+//---------------------------------------------------------------------
+
+/**
+ * Invokes getLinkable(pid, 0)
.
+ */
+public static int getLinkable(int pid)
+{
+ return getLinkable(pid, 0);
+}
+
+// ---------------------------------------------------------------------
+
+/**
+ * Returns true if the given protocol has a transport protocol associated with
+ * it, otherwise false.
+ */
+public static boolean hasTransport(int pid)
+{
+ return transports[pid] >= 0;
+}
+
+// ---------------------------------------------------------------------
+
+/**
+ * Returns the id of the transport protocol used by the protocol identified
+ * by pid.
+ * Throws an IllegalParameterException if there is no transport associated
+ * with the given protocol: we assume here that his happens when the
+ * configuration is incorrect.
+ */
+public static int getTransport(int pid)
+{
+ if (transports[pid] < 0) {
+ String[] names = Configuration.getNames(Configuration.PAR_PROT);
+ throw new IllegalParameterException(names[pid],
+ "Protocol " + pid + " has no "+PAR_TRANSPORT + " parameter");
+ }
+ return transports[pid];
+}
+
+}
diff --git a/contrib/psg/src/peersim/config/IllegalParameterException.java b/contrib/psg/src/peersim/config/IllegalParameterException.java
new file mode 100644
index 0000000000..1285350ff9
--- /dev/null
+++ b/contrib/psg/src/peersim/config/IllegalParameterException.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.config;
+
+/**
+* Exception thrown to indicate that a
+* configuration property has an invalid value. It is thrown by
+* several methods in {@link Configuration} and can be thrown by any
+* component that reads the configuration.
+*/
+public class IllegalParameterException extends RuntimeException {
+
+// ================== initialization =====================================
+// =======================================================================
+
+/**
+* Calls super constructor. It passes a string message which is the given
+* message, prefixed with the given property name.
+* @param name Name of configuration property that is invalid
+* @param message Additional info about why the value is invalid
+*/
+public IllegalParameterException(String name, String message) {
+
+ super("Parameter \"" + name + "\": " + message);
+}
+
+// ================== methods ============================================
+// =======================================================================
+
+/**
+* Extends message with info from stack trace.
+* It tries to guess what class called {@link Configuration} and
+* adds relevant info from the stack trace about it to the message.
+*/
+public String getMessage() {
+
+ StackTraceElement[] stack = getStackTrace();
+
+ // Search the element that invoked Configuration
+ // It's the first whose class is different from Configuration
+ int pos;
+ for (pos=0; pos < stack.length; pos++)
+ {
+ if (!stack[pos].getClassName().equals(
+ Configuration.class.getName()))
+ break;
+ }
+
+ return super.getMessage()+"\nAt "+
+ getStackTrace()[pos].getClassName()+"."+
+ getStackTrace()[pos].getMethodName()+":"+
+ getStackTrace()[pos].getLineNumber();
+}
+
+/**
+ * Returns the exception message without stack trace information
+ */
+public String getShortMessage()
+{
+ return super.getMessage();
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/config/MissingParameterException.java b/contrib/psg/src/peersim/config/MissingParameterException.java
new file mode 100644
index 0000000000..58b85cde60
--- /dev/null
+++ b/contrib/psg/src/peersim/config/MissingParameterException.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.config;
+
+/**
+* Exception thrown to indicate that a
+* configuration property is not defined. It is thrown exclusively by
+* {@link Configuration}, since it is the only class that has access to the
+* set of defined properties.
+ */
+public class MissingParameterException extends RuntimeException {
+
+// ================== initialization =====================================
+// =======================================================================
+
+MissingParameterException(String name) {
+
+ super("Parameter \"" + name + "\" not found.");
+}
+
+MissingParameterException(String name, String motivation) {
+
+ super("Parameter \"" + name + "\" not found " + motivation);
+}
+
+// ================== methods ============================================
+// =======================================================================
+
+/**
+* Extends message with info from stack trace.
+* It tries to guess what class called {@link Configuration} and
+* adds relevant info from the stack trace about it to the message.
+*/
+public String getMessage() {
+
+ StackTraceElement[] stack = getStackTrace();
+
+ // Search the element that invoked Configuration
+ // It's the first whose class is different from Configuration
+ int pos;
+ for (pos=0; pos < stack.length; pos++) {
+ if (!stack[pos].getClassName().equals(
+ Configuration.class.getName()))
+ break;
+ }
+
+ return super.getMessage()+"\nAt "+
+ getStackTrace()[pos].getClassName()+"."+
+ getStackTrace()[pos].getMethodName()+":"+
+ getStackTrace()[pos].getLineNumber();
+}
+
+/**
+ * Returns the exception message without stack trace information
+ */
+public String getShortMessage()
+{
+ return super.getMessage();
+}
+
+}
diff --git a/contrib/psg/src/peersim/config/NullPrintStream.java b/contrib/psg/src/peersim/config/NullPrintStream.java
new file mode 100644
index 0000000000..612492265d
--- /dev/null
+++ b/contrib/psg/src/peersim/config/NullPrintStream.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.config;
+
+import java.io.*;
+
+/**
+ * A subclass of PrintStream whose methods ignore the content
+ * being written.
+ *
+ * @author Alberto Montresor
+ * @version $Revision: 1.1 $
+ */
+public class NullPrintStream extends PrintStream
+{
+
+/**
+ * Creates a null print stream that does not print anything.
+ */
+public NullPrintStream()
+{
+ super(System.out);
+}
+
+/**
+ * This methods does not print anything.
+ */
+public synchronized void write(byte[] b, int off, int len)
+{
+}
+
+/**
+ * This methods does not print anything.
+ */
+public synchronized void write(int b)
+{
+}
+
+/**
+ * This methods does not print anything.
+ */
+private void printLine()
+{
+}
+
+}
diff --git a/contrib/psg/src/peersim/config/Operators.java b/contrib/psg/src/peersim/config/Operators.java
new file mode 100644
index 0000000000..1d5d523f31
--- /dev/null
+++ b/contrib/psg/src/peersim/config/Operators.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+package peersim.config;
+import java.math.*;
+import org.lsmp.djep.groupJep.groups.*;
+import org.lsmp.djep.groupJep.interfaces.*;
+
+/**
+ * This class implements the Group
interface of JEP,
+ * enabling the configuration system to read integers with arbitrary
+ * length.
+ */
+public class Operators extends Group implements IntegralDomainI,HasDivI,
+ OrderedSetI,HasModI,HasPowerI {
+
+
+ /**
+ * Operations on the reals (Implemented as BigInteger).
+ */
+ public Operators() {
+ }
+
+ public Number getZERO() {
+ return BigInteger.ZERO;
+ }
+
+ public Number getONE() {
+ return BigInteger.ONE;
+ }
+
+ public Number getInverse(Number num) {
+ if (num instanceof BigInteger) {
+ BigInteger a = (BigInteger) num;
+ return a.negate();
+ } else {
+ return -num.doubleValue();
+ }
+ }
+
+ public Number add(Number num1, Number num2) {
+ if (num1 instanceof Double || num2 instanceof Double) {
+ // One is double
+ return num1.doubleValue() + num2.doubleValue();
+ } else {
+ // Both integer
+ BigInteger a = (BigInteger) num1;
+ BigInteger b = (BigInteger) num2;
+ return a.add(b);
+ }
+ }
+
+ public Number sub(Number num1, Number num2) {
+ if (num1 instanceof Double || num2 instanceof Double) {
+ // One is double
+ return num1.doubleValue() - num2.doubleValue();
+ } else {
+ // Both integer
+ BigInteger a = (BigInteger) num1;
+ BigInteger b = (BigInteger) num2;
+ return a.subtract(b);
+ }
+ }
+
+ public Number mul(Number num1, Number num2) {
+ if (num1 instanceof Double || num2 instanceof Double) {
+ // One is double
+ return num1.doubleValue() * num2.doubleValue();
+ } else {
+ // Both integer
+ BigInteger a = (BigInteger) num1;
+ BigInteger b = (BigInteger) num2;
+ return a.multiply(b);
+ }
+ }
+
+ public Number div(Number num1, Number num2) {
+ if (num1 instanceof Double || num2 instanceof Double) {
+ // One is double
+ return num1.doubleValue() / num2.doubleValue();
+ } else {
+ // Both integer
+ BigInteger a = (BigInteger) num1;
+ BigInteger b = (BigInteger) num2;
+ return a.divide(b);
+ }
+ }
+
+
+ public Number mod(Number num1, Number num2) {
+ if (num1 instanceof Double || num2 instanceof Double) {
+ // One is double
+ return num1.doubleValue() % num2.doubleValue();
+ } else {
+ // Both integer
+ BigInteger a = (BigInteger) num1;
+ BigInteger b = (BigInteger) num2;
+ return a.remainder(b);
+ }
+ }
+
+ public Number pow(Number num1, Number num2) {
+ if (num1 instanceof Double || num2 instanceof Double) {
+ // One is double
+ return Math.pow(num1.doubleValue(), num2.doubleValue());
+ } else {
+ // Both integer
+ BigInteger a = (BigInteger) num1;
+ BigInteger b = (BigInteger) num2;
+ return a.pow(b.intValue());
+ }
+ }
+
+ public boolean equals(Number num1, Number num2) {
+ if (num1 instanceof Double || num2 instanceof Double) {
+ // One is double
+ return num1.doubleValue() == num2.doubleValue();
+ } else {
+ // Both integer
+ BigInteger a = (BigInteger) num1;
+ BigInteger b = (BigInteger) num2;
+ return a.equals(b);
+ }
+ }
+
+ public int compare(Number num1,Number num2) {
+ if (num1 instanceof Double || num2 instanceof Double) {
+ // One is double
+ double n1 = num1.doubleValue();
+ double n2 = num2.doubleValue();
+ return (n1 < n2 ? -1 : (n1 == n2 ? 0 : 1));
+ } else {
+ // Both integer
+ BigInteger a = (BigInteger) num1;
+ BigInteger b = (BigInteger) num2;
+ return a.compareTo(b);
+ }
+ }
+
+ public Number valueOf(String str) {
+ try {
+ return new BigInteger(str);
+ } catch (NumberFormatException e) {
+ return new Double(str);
+ }
+ }
+
+ public String toString() { return ""; }
+}
diff --git a/contrib/psg/src/peersim/config/ParsedProperties.java b/contrib/psg/src/peersim/config/ParsedProperties.java
new file mode 100644
index 0000000000..9a58e4114d
--- /dev/null
+++ b/contrib/psg/src/peersim/config/ParsedProperties.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.config;
+
+import java.io.*;
+import java.util.*;
+
+/**
+* Extends the class {@link ConfigProperties} with basic parsing capabilities.
+* @see #load
+*/
+public class ParsedProperties extends ConfigProperties {
+
+//================= variables ======================================
+//==================================================================
+
+// ================= initialization =================================
+// ==================================================================
+
+/**
+* Calls super constructor.
+* @see ConfigProperties#ConfigProperties(String[])
+*/
+public ParsedProperties( String[] pars ) {
+
+ super( pars );
+}
+
+// ------------------------------------------------------------------
+
+/**
+* Calls super constructor.
+* @see ConfigProperties#ConfigProperties(String)
+*/
+public ParsedProperties( String filename ) throws IOException {
+
+ super( filename );
+}
+
+
+// =========== Public methods ========================================
+// ===================================================================
+
+
+/**
+* Loads given file. It works exactly as Properties.load
+* with a file input stream to the given file, except that the file is parsed
+* the following way allowing to compress some property names
+* using {
and }
.
+
+ When a bracket is present, it must
+ be the only non-space element of a line. The last property defined
+ before the opening bracket define the prefix that is added to all the
+ properties defined included between brackets.
+ In other words, a construct like this:
+
+ control.degree GraphObserver
+ {
+ protocol newscast
+ undir
+ }
+
+ is equivalent to the definition of these three properties:
+
+ control.degree GraphObserver
+ control.degree.protocol newscast
+ control.degree.undir
+
+
+ Nested brackets are possible. The rule of the last property before
+ the opening bracket applies also to the inside brackets, with
+ the prefix being the complete property definition (so, including
+ the prefix observed before). Example:
+
+ control.1 DynamicNetwork
+ {
+ add CRASH
+ substitute
+ init.0 WireKOut
+ {
+ degree DEGREE
+ protocol 0
+ }
+ }
+
+ defines the following properties:
+
+ control.1 DynamicNetwork
+ control.1.add CRASH
+ control.1.substitute
+ control.1.init.0 WireKOut
+ control.1.init.0.degree DEGREE
+ control.1.init.0.protocol 0
+
+
+
+ *
+ */
+public static int getPhase()
+{
+ return phase;
+}
+
+// -----------------------------------------------------------------
+
+public static void setPhase(int p)
+{
+ phase = p;
+}
+
+// -----------------------------------------------------------------
+
+/**
+* Returns the current protocol identifier. In other words, control is
+* held by the indicated protocol on node {@link #getNode}.
+*/
+public static int getPid()
+{
+ return pid;
+}
+
+//-----------------------------------------------------------------
+
+/** Sets the current protocol identifier.*/
+public static void setPid(int p)
+{
+ pid = p;
+}
+
+//-----------------------------------------------------------------
+
+/**
+ * Returns the current node. When a protocol is executing, it is the node
+ * hosting the protocol.
+ */
+public static Node getNode()
+{
+ return node;
+}
+
+//-----------------------------------------------------------------
+
+/** Sets the current node */
+public static void setNode(Node n)
+{
+ node = n;
+}
+
+//-----------------------------------------------------------------
+
+public static void initializeRandom(long seed)
+{
+ if (r == null) {
+ r = (ExtendedRandom) Configuration.getInstance(PAR_RANDOM, new ExtendedRandom(seed));
+ }
+ r.setSeed(seed);
+}
+
+//-----------------------------------------------------------------
+
+/*
+public static void main(String pars[]) {
+
+ setEndTime(Long.parseLong(pars[0]));
+ setTime(Long.parseLong(pars[1]));
+ System.err.println(getTime()+" "+getIntTime());
+}
+*/
+}
+
diff --git a/contrib/psg/src/peersim/core/Control.java b/contrib/psg/src/peersim/core/Control.java
new file mode 100644
index 0000000000..7644aa9df0
--- /dev/null
+++ b/contrib/psg/src/peersim/core/Control.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+/**
+ * Generic interface for classes that are responsible for observing or modifying
+ * the ongoing simulation. It is designed to allow maximal flexibility therefore
+ * poses virtually no restrictions on the implementation.
+ */
+public interface Control
+{
+
+/**
+ * Performs arbitrary modifications or reports arbitrary information over the
+ * components.
+ * @return true if the simulation has to be stopped, false otherwise.
+ */
+public boolean execute();
+
+}
diff --git a/contrib/psg/src/peersim/core/Fallible.java b/contrib/psg/src/peersim/core/Fallible.java
new file mode 100644
index 0000000000..089cffef62
--- /dev/null
+++ b/contrib/psg/src/peersim/core/Fallible.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+
+/**
+* Instances of classes implementing this interface
+* maintain a fail state, i.e. information about the availability
+* of the object.
+*/
+public interface Fallible {
+
+
+ /**
+ * Fail state which indicates that the object is operating normally.
+ */
+ public int OK = 0;
+
+ /**
+ * Fail state indicating that the object is dead and recovery is
+ * not possible. When this state is set, it is a good idea to make sure
+ * that the state of the object becomes such that any attempt to
+ * operate on it causes a visible error of some kind.
+ */
+ public int DEAD = 1;
+
+ /**
+ * Fail state indicating that the object is not dead, but is temporarily
+ * not accessible.
+ */
+ public int DOWN = 2;
+
+ /**
+ * Returns the state of this object. Must be one of the constants
+ * defined in interface {@link Fallible}.
+ */
+ public int getFailState();
+
+ /**
+ * Sets the fails state of this object. Parameter must be one of the
+ * constants defined in interface {@link Fallible}.
+ */
+ public void setFailState(int failState);
+
+ /**
+ * Convenience method to check if the node is up and running
+ * @return must return true if and only if
+ * getFailState()==OK
+ */
+ public boolean isUp();
+}
+
+
diff --git a/contrib/psg/src/peersim/core/GeneralNode.java b/contrib/psg/src/peersim/core/GeneralNode.java
new file mode 100644
index 0000000000..2f2c02eb3c
--- /dev/null
+++ b/contrib/psg/src/peersim/core/GeneralNode.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+import peersim.config.*;
+
+/**
+* This is the default {@link Node} class that is used to compose the
+* {@link Network}.
+*/
+public class GeneralNode implements Node {
+
+
+// ================= fields ========================================
+// =================================================================
+
+/** used to generate unique IDs */
+private static long counterID = -1;
+
+/**
+* The protocols on this node.
+*/
+protected Protocol[] protocol = null;
+
+/**
+* The current index of this node in the node
+* list of the {@link Network}. It can change any time.
+* This is necessary to allow
+* the implementation of efficient graph algorithms.
+*/
+private int index;
+
+/**
+* The fail state of the node.
+*/
+protected int failstate = Fallible.OK;
+
+/**
+* The ID of the node. It should be final, however it can't be final because
+* clone must be able to set it.
+*/
+private long ID;
+
+// ================ constructor and initialization =================
+// =================================================================
+
+/** Used to construct the prototype node. This class currently does not
+* have specific configuration parameters and so the parameter
+* prefix
is not used. It reads the protocol components
+* (components that have type {@value peersim.core.Node#PAR_PROT}) from
+* the configuration.
+*/
+public GeneralNode(String prefix) {
+
+ String[] names = Configuration.getNames(PAR_PROT);
+ CommonState.setNode(this);
+ ID=nextID();
+ protocol = new Protocol[names.length];
+ for (int i=0; i < names.length; i++) {
+ CommonState.setPid(i);
+ Protocol p = (Protocol)
+ Configuration.getInstance(names[i]);
+ protocol[i] = p;
+ }
+}
+
+
+// -----------------------------------------------------------------
+
+public Object clone() {
+
+ GeneralNode result = null;
+ try { result=(GeneralNode)super.clone(); }
+ catch( CloneNotSupportedException e ) {} // never happens
+ result.protocol = new Protocol[protocol.length];
+ CommonState.setNode(result);
+ result.ID=nextID();
+ for(int i=0; ii
-th protocol in this node. If i
+ * is not a valid protocol id
+ * (negative or larger than or equal to the number of protocols), then it throws
+ * IndexOutOfBoundsException.
+ */
+public Protocol getProtocol(int i);
+
+/**
+ * Returns the number of protocols included in this node.
+ */
+public int protocolSize();
+
+/**
+ * Sets the index of this node in the internal representation of the node list.
+ * Applications should not use this method. It is defined as public simply
+ * because it is not possible to define it otherwise.
+ * Using this method will result in
+ * undefined behavior. It is provided for the core system.
+ */
+public void setIndex(int index);
+
+/**
+ * Returns the index of this node. It is such that
+ * Network.get(n.getIndex())
returns n. This index can
+ * change during a simulation, it is not a fixed id. If you need that, use
+ * {@link #getID}.
+ * @see Network#get
+ */
+public int getIndex();
+
+/**
+* Returns the unique ID of the node. It is guaranteed that the ID is unique
+* during the entire simulation, that is, there will be no different Node
+* objects with the same ID in the system during one invocation of the JVM.
+* Preferably nodes
+* should implement hashCode()
based on this ID.
+*/
+public long getID();
+
+/**
+ * Clones the node. It is defined as part of the interface
+ * to change the access right to public and to get rid of the
+ * throws
clause.
+ */
+public Object clone();
+
+}
diff --git a/contrib/psg/src/peersim/core/OracleIdleProtocol.java b/contrib/psg/src/peersim/core/OracleIdleProtocol.java
new file mode 100644
index 0000000000..4d1896ff15
--- /dev/null
+++ b/contrib/psg/src/peersim/core/OracleIdleProtocol.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+/**
+* A protocol that does nothing but knows everything.
+* It provides an interface which models a protocol that knows all nodes
+* in the network, i.e. the neighborhood set of this protocol is always the
+* whole node set. this protocol is also extremely cheap, in fact it
+* has no data fields.
+*/
+public final class OracleIdleProtocol implements Protocol, Linkable {
+
+// =================== initialization, creation ======================
+// ===================================================================
+
+
+/** Does nothing */
+public OracleIdleProtocol(String prefix) {}
+
+// --------------------------------------------------------------------
+
+/** Returns this to maximize memory saving. It contains no fields.*/
+public Object clone() { return this; }
+
+
+// ===================== public methods ===============================
+// ====================================================================
+
+
+/** This is an expensive operation, should not be used at all.
+* It returns false only if the given node is not in the current network.
+*/
+public boolean contains(Node n) {
+
+ final int len = Network.size();
+ for (int i=0; i < len; i++)
+ {
+ if (Network.node[i] == n)
+ return true;
+ }
+ return false;
+}
+
+// --------------------------------------------------------------------
+
+/** Unsupported operation */
+public boolean addNeighbor(Node n) {
+
+ throw new UnsupportedOperationException();
+}
+
+// --------------------------------------------------------------------
+
+/**
+* The neighborhood contains the node itself, ie it contains the loop
+* edge.
+*/
+public Node getNeighbor(int i) {
+
+ return Network.node[i];
+}
+
+// --------------------------------------------------------------------
+
+public int degree() {
+
+ return Network.size();
+}
+
+// --------------------------------------------------------------------
+
+public void pack() {}
+
+// --------------------------------------------------------------------
+
+public void onKill() {}
+
+// --------------------------------------------------------------------
+
+public String toString() {
+
+ return degree()+" [all the nodes of the overlay network]";
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/core/OverlayGraph.java b/contrib/psg/src/peersim/core/OverlayGraph.java
new file mode 100644
index 0000000000..000945917c
--- /dev/null
+++ b/contrib/psg/src/peersim/core/OverlayGraph.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.core;
+
+import peersim.graph.Graph;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+* This class is an adaptor which makes a {@link Linkable} protocol layer
+* look like a graph. It is useful because it allows the application of many
+* graph algorithms and graph topology initialization methods.
+* If the overlay network changes after creating this object, the changes
+* will be reflected. However, if the nodes are reshuffled (see
+* {@link Network#shuffle}), or if the node list changes (addition/removal),
+* then the behaviour becomes unspecified.
+*
+* The indices of nodes are from 0 to Network.size()-1.
+*
+* The fail state of nodes has an effect on the graph: all nodes are included
+* but edges are included only if both ends are up. This expresses the fact
+* that this graph is in fact defined by the "can communicate with" relation.
+*/
+public class OverlayGraph implements Graph {
+
+
+// ====================== fields ================================
+// ==============================================================
+
+/**
+* The protocol ID that selects the Linkable protocol to convert to a graph.
+*/
+public final int protocolID;
+
+/**
+* Tells if the graph should be wired in an undirected way.
+* Method {@link #directed} returns true always, this affects only
+* method {@link #setEdge}: if false, then the opposite edge is set too.
+*/
+public final boolean wireDirected;
+
+// ====================== public constructors ===================
+// ==============================================================
+
+/**
+* @param protocolID The protocol on which this adaptor is supposed
+* to operate.
+*/
+public OverlayGraph( int protocolID ) {
+
+ this.protocolID = protocolID;
+ wireDirected = true;
+}
+
+// --------------------------------------------------------------
+
+/**
+* @param protocolID The protocol on which this adaptor is supposed
+* to operate.
+* @param wireDirected specifies if {@link #setEdge} would wire the
+* opposite edge too.
+*/
+public OverlayGraph( int protocolID, boolean wireDirected ) {
+
+ this.protocolID = protocolID;
+ this.wireDirected = wireDirected;
+}
+
+
+// ======================= Graph implementations ================
+// ==============================================================
+
+
+public boolean isEdge(int i, int j) {
+
+ return
+ ((Linkable)Network.node[i].getProtocol(protocolID)
+ ).contains(Network.node[j]) &&
+ Network.node[j].isUp() &&
+ Network.node[i].isUp();
+}
+
+// ---------------------------------------------------------------
+
+/**
+* Returns those neighbors that are up. If node i is not up, it returns
+* an empty list.
+*/
+public CollectionNetwork.size()
*/
+public int size() { return Network.size(); }
+
+// --------------------------------------------------------------------
+
+/** Returns always true */
+public boolean directed() { return true; }
+
+// --------------------------------------------------------------------
+
+/**
+* Sets given edge.
+* In some cases this behaves strangely. Namely, when node i or j is not up,
+* but is not dead (e.g. it can be down temporarily).
+* In such situations the relevant link is made, but afterwards
+* getEdge(i,j) will NOT return true, only when the fail state has changed back
+* to OK.
+*
+* prefix
. {@value #PAR_STEP} defaults to 1.
+*/
+public Scheduler(String prefix) {
+
+ this(prefix, true);
+}
+
+// ------------------------------------------------------------------
+
+/** Reads configuration parameters from the component defined by
+* prefix
. If useDefault is false, then at least parameter
+* {@value #PAR_STEP} must be explicitly defined. Otherwise {@value #PAR_STEP}
+* defaults to 1.
+*/
+public Scheduler(String prefix, boolean useDefault)
+{
+ if (Configuration.contains(prefix+"."+PAR_AT)) {
+ // FROM, UNTIL, and STEP should *not* be defined
+ if (Configuration.contains(prefix+"."+PAR_FROM) ||
+ Configuration.contains(prefix+"."+PAR_UNTIL) ||
+ Configuration.contains(prefix+"."+PAR_STEP))
+ throw new IllegalParameterException(prefix,
+ "Cannot use \""+PAR_AT+"\" together with \""
+ +PAR_FROM+"\", \""+PAR_UNTIL+"\", or \""+
+ PAR_STEP+"\"");
+
+ from = Configuration.getLong(prefix+"."+PAR_AT);
+ until = from+1;
+ step = 1;
+ } else {
+ if (useDefault)
+ step = Configuration.getLong(prefix+"."+PAR_STEP,1);
+ else
+ step = Configuration.getLong(prefix+"."+PAR_STEP);
+ if( step < 1 )
+ throw new IllegalParameterException(prefix,
+ "\""+PAR_STEP+"\" must be >= 1");
+
+ from = Configuration.getLong(prefix+"."+PAR_FROM,0);
+ until = Configuration.getLong(prefix+"."+PAR_UNTIL,Long.MAX_VALUE);
+ }
+
+ if( from < until ) next = from;
+ else next = -1;
+
+ fin = Configuration.contains(prefix+"."+PAR_FINAL);
+}
+
+
+// ===================== public methods ==============================
+// ===================================================================
+
+/** true if given time point is covered by this scheduler */
+public boolean active(long time) {
+
+ if( time < from || time >= until ) return false;
+ return (time - from)%step == 0;
+}
+
+// -------------------------------------------------------------------
+
+/** true if current time point is covered by this scheduler */
+public boolean active() {
+
+ return active( CommonState.getTime() );
+}
+
+//-------------------------------------------------------------------
+
+/**
+* Returns the next time point. If the returned value is negative, there are
+* no more time points. As a side effect, it also updates the next time point,
+* so repeated calls to this method return the scheduled times.
+*/
+public long getNext()
+{
+ long ret = next;
+ // check like this to prevent integer overflow of "next"
+ if( until-next > step ) next += step;
+ else next = -1;
+ return ret;
+}
+
+}
+
+
diff --git a/contrib/psg/src/peersim/dynamics/DynamicNetwork.java b/contrib/psg/src/peersim/dynamics/DynamicNetwork.java
new file mode 100644
index 0000000000..a581a86ffe
--- /dev/null
+++ b/contrib/psg/src/peersim/dynamics/DynamicNetwork.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.dynamics;
+
+import java.util.Map;
+
+import org.simgrid.msg.Host;
+import org.simgrid.msg.MsgException;
+
+import peersim.Simulator;
+import peersim.config.Configuration;
+import peersim.core.*;
+import psgsim.NodeHost;
+import psgsim.PSGDynamicNetwork;
+
+/**
+ * This {@link Control} can change the size of networks by adding and removing
+ * nodes. Can be used to model churn. This class supports only permanent removal
+ * of nodes and the addition of brand new nodes. That is, temporary downtime is
+ * not supported by this class.
+ */
+public class DynamicNetwork implements Control {
+
+ // --------------------------------------------------------------------------
+ // Parameters
+ // --------------------------------------------------------------------------
+
+ /**
+ * Config parameter which gives the prefix of node initializers. An
+ * arbitrary number of node initializers can be specified (Along with their
+ * parameters). These will be applied on the newly created nodes. The
+ * initializers are ordered according to alphabetical order if their ID.
+ * Example:
+ *
+ *
+ * control.0 DynamicNetwork
+ * control.0.init.0 RandNI
+ * control.0.init.0.k 5
+ * control.0.init.0.protocol somelinkable
+ * ...
+ *
+ *
+ * @config
+ */
+ private static final String PAR_INIT = "init";
+
+ /**
+ * If defined, nodes are substituted (an existing node is removed, a new one
+ * is added. That is, first the number of nodes to add (or remove if
+ * {@value #PAR_ADD} is negative) is calculated, and then exactly the same
+ * number of nodes are removed (or added) immediately so that the network
+ * size remains constant. Not set by default.
+ *
+ * @config
+ */
+ private static final String PAR_SUBST = "substitute";
+
+ /**
+ * Specifies the number of nodes to add or remove. It can be negative in
+ * which case nodes are removed. If its absolute value is less than one,
+ * then it is interpreted as a proportion of current network size, that is,
+ * its value is substituted with add*networksize. Its value is
+ * rounded to an integer.
+ *
+ * @config
+ */
+ private static final String PAR_ADD = "add";
+
+ /**
+ * Nodes are added until the size specified by this parameter is reached.
+ * The network will never exceed this size as a result of this class. If not
+ * set, there will be no limit on the size of the network.
+ *
+ * @config
+ */
+ private static final String PAR_MAX = "maxsize";
+
+ /**
+ * Nodes are removed until the size specified by this parameter is reached.
+ * The network will never go below this size as a result of this class.
+ * Defaults to 0.
+ *
+ * @config
+ */
+ private static final String PAR_MIN = "minsize";
+
+ // --------------------------------------------------------------------------
+ // Fields
+ // --------------------------------------------------------------------------
+
+ /** value of {@value #PAR_ADD} */
+ protected final double add;
+
+ /** value of {@value #PAR_SUBST} */
+ protected final boolean substitute;
+
+ /** value of {@value #PAR_MIN} */
+ protected final int minsize;
+
+ /** value of {@value #PAR_MAX} */
+ protected final int maxsize;
+
+ /** node initializers to apply on the newly added nodes */
+ protected final NodeInitializer[] inits;
+
+ // --------------------------------------------------------------------------
+ // Protected methods
+ // --------------------------------------------------------------------------
+
+ /**
+ * Adds n nodes to the network. Extending classes can implement any
+ * algorithm to do that. The default algorithm adds the given number of
+ * nodes after calling all the configured initializers on them.
+ *
+ * @param n
+ * the number of nodes to add, must be non-negative.
+ */
+ protected void add(int n) {
+ for (int i = 0; i < n; ++i) {
+ Node newnode = (Node) Network.prototype.clone();
+ for (int j = 0; j < inits.length; ++j) {
+ inits[j].initialize(newnode);
+ }
+ Network.add(newnode);
+
+ }
+ }
+
+ // ------------------------------------------------------------------
+
+ /**
+ * Removes n nodes from the network. Extending classes can implement any
+ * algorithm to do that. The default algorithm removes random nodes
+ * permanently simply by calling {@link Network#remove(int)}.
+ *
+ * @param n
+ * the number of nodes to remove
+ */
+ protected void remove(int n) {
+ for (int i = 0; i < n; ++i) {
+ int nr = CommonState.r.nextInt(Network.size());
+ Network.remove(nr);
+
+ }
+ }
+
+ // --------------------------------------------------------------------------
+ // Initialization
+ // --------------------------------------------------------------------------
+
+ /**
+ * Standard constructor that reads the configuration parameters. Invoked by
+ * the simulation engine.
+ *
+ * @param prefix
+ * the configuration prefix for this class
+ */
+ public DynamicNetwork(String prefix) {
+ add = Configuration.getDouble(prefix + "." + PAR_ADD);
+ substitute = Configuration.contains(prefix + "." + PAR_SUBST);
+ Object[] tmp = Configuration.getInstanceArray(prefix + "." + PAR_INIT);
+ inits = new NodeInitializer[tmp.length];
+ for (int i = 0; i < tmp.length; ++i) {
+ // System.out.println("Inits " + tmp[i]);
+ inits[i] = (NodeInitializer) tmp[i];
+ }
+ maxsize = Configuration.getInt(prefix + "." + PAR_MAX,
+ Integer.MAX_VALUE);
+ minsize = Configuration.getInt(prefix + "." + PAR_MIN, 0);
+ }
+
+ // --------------------------------------------------------------------------
+ // Public methods
+ // --------------------------------------------------------------------------
+
+ /**
+ * Calls {@link #add(int)} or {@link #remove} with the parameters defined by
+ * the configuration.
+ *
+ * @return always false
+ */
+ public final boolean execute() {
+ if (add == 0)
+ return false;
+ if (!substitute) {
+ if ((maxsize <= Network.size() && add > 0)
+ || (minsize >= Network.size() && add < 0))
+ return false;
+ }
+ int toadd = 0;
+ int toremove = 0;
+ if (add > 0) {
+ toadd = (int) Math.round(add < 1 ? add * Network.size() : add);
+ if (!substitute && toadd > maxsize - Network.size())
+ toadd = maxsize - Network.size();
+ if (substitute)
+ toremove = toadd;
+ } else if (add < 0) {
+ toremove = (int) Math
+ .round(add > -1 ? -add * Network.size() : -add);
+ if (!substitute && toremove > Network.size() - minsize)
+ toremove = Network.size() - minsize;
+ if (substitute)
+ toadd = toremove;
+ }
+ remove(toremove);
+ add(toadd);
+ return false;
+ }
+
+ // --------------------------------------------------------------------------
+
+}
diff --git a/contrib/psg/src/peersim/dynamics/MethodInvoker.java b/contrib/psg/src/peersim/dynamics/MethodInvoker.java
new file mode 100644
index 0000000000..5e9e5fce73
--- /dev/null
+++ b/contrib/psg/src/peersim/dynamics/MethodInvoker.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.dynamics;
+
+import java.lang.reflect.*;
+import peersim.config.*;
+import peersim.core.*;
+import java.util.ArrayList;
+
+/**
+ * This {@link Control} invokes a specified method on a protocol.
+ * The method is defined by config parameter {@value #PAR_METHOD} and
+ * the protocol is by {@value #PAR_PROT}. The method must not have any
+ * parameters and must return void. If no protocol is specified, then the
+ * method will be invoked on all protocol in the protocol stack that define
+ * it.
+ * avg+sin(time*pi/{@value #PAR_PERIOD})*ampl
where
+ * avg=({@value #PAR_MAX}+{@value #PAR_MIN})/2
and
+ * ampl=({@value #PAR_MAX}-{@value #PAR_MIN})/2
.
+ * This function is independent of how many times this class is executed, that
+ * is, whenever it is executed, it takes the current time and sets the network
+ * size accordingly.
+ */
+public class OscillatingNetwork implements Control
+{
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * Config parameter which gives the prefix of node initializers. An arbitrary
+ * number of node initializers can be specified (Along with their parameters).
+ * These will be applied
+ * on the newly created nodes. The initializers are ordered according to
+ * alphabetical order if their ID.
+ * Example:
+ *
+control.0 DynamicNetwork
+control.0.init.0 RandNI
+control.0.init.0.k 5
+control.0.init.0.protocol somelinkable
+...
+ *
+ * @config
+ */
+private static final String PAR_INIT = "init";
+
+/**
+ * Nodes are added until the size specified by this parameter is reached. The
+ * network will never exceed this size as a result of this class.
+ * If not set, there will be no limit on the size of the network.
+ * @config
+ */
+private static final String PAR_MAX = "maxsize";
+
+/**
+ * Nodes are removed until the size specified by this parameter is reached. The
+ * network will never go below this size as a result of this class.
+ * Defaults to 0.
+ * @config
+ */
+private static final String PAR_MIN = "minsize";
+
+/**
+ * Config parameter used to define the length of one period of the oscillation.
+ * The network size will be the function of time, parameterized by this
+ * parameter. The size function is
+ * avg+sin(time*pi/{@value #PAR_PERIOD})*ampl
where
+ * avg=({@value #PAR_MAX}+{@value #PAR_MIN})/2
and
+ * ampl=({@value #PAR_MAX}-{@value #PAR_MIN})/2
.
+ * @config
+ */
+private static final String PAR_PERIOD = "period";
+
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+
+/** Period */
+private final int period;
+
+/** Maximum size */
+private final int minsize;
+
+/** Minimum size */
+private final int maxsize;
+
+/** New nodes initializers */
+private final NodeInitializer[] inits;
+
+
+//--------------------------------------------------------------------------
+// Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters. Invoked by the
+ * simulation engine.
+ * @param prefix
+ * the configuration prefix for this class
+ */
+public OscillatingNetwork(String prefix)
+{
+
+ period = Configuration.getInt(prefix + "." + PAR_PERIOD);
+ maxsize =
+ Configuration.getInt(
+ prefix + "." + PAR_MAX,
+ Integer.MAX_VALUE);
+ minsize = Configuration.getInt(prefix + "." + PAR_MIN, 0);
+
+ Object[] tmp = Configuration.getInstanceArray(prefix + "." + PAR_INIT);
+ inits = new NodeInitializer[tmp.length];
+ for (int i = 0; i < tmp.length; ++i)
+ {
+ inits[i] = (NodeInitializer) tmp[i];
+ }
+}
+
+//--------------------------------------------------------------------------
+// Methods
+//--------------------------------------------------------------------------
+
+/**
+ * Adds n nodes to the network. Extending classes can implement any algorithm to
+ * do that. The default algorithm adds the given number of nodes after calling
+ * all the configured initializers on them.
+ *
+ * @param n
+ * the number of nodes to add, must be non-negative.
+ */
+protected void add(int n)
+{
+ for (int i = 0; i < n; ++i) {
+ Node newnode = (Node) Network.prototype.clone();
+ for (int j = 0; j < inits.length; ++j) {
+ inits[j].initialize(newnode);
+ }
+ Network.add(newnode);
+ }
+}
+
+// ------------------------------------------------------------------
+
+/**
+ * Removes n nodes from the network. Extending classes can implement any
+ * algorithm to do that. The default algorithm removes random
+ * nodes permanently simply by calling {@link Network#remove(int)}.
+ * @param n the number of nodes to remove
+ */
+protected void remove(int n)
+{
+ for (int i = 0; i < n; ++i) {
+ Network.remove(CommonState.r.nextInt(Network.size()));
+ }
+}
+
+// ------------------------------------------------------------------
+
+/**
+ * Takes the current time and sets the network size according to a periodic
+ * function of time.
+ * The size function is
+ * avg+sin(time*pi/{@value #PAR_PERIOD})*ampl
where
+ * avg=({@value #PAR_MAX}+{@value #PAR_MIN})/2
and
+ * ampl=({@value #PAR_MAX}-{@value #PAR_MIN})/2
.
+ * Calls {@link #add(int)} or {@link #remove} depending on whether the size
+ * needs to be increased or decreased to get the desired size.
+ * @return always false
+ */
+public boolean execute()
+{
+ long time = CommonState.getTime();
+ int amplitude = (maxsize - minsize) / 2;
+ int newsize = (maxsize + minsize) / 2 +
+ (int) (Math.sin(((double) time) / period * Math.PI) *
+ amplitude);
+ int diff = newsize - Network.size();
+ if (diff < 0)
+ remove(-diff);
+ else
+ add(diff);
+
+ return false;
+}
+
+}
diff --git a/contrib/psg/src/peersim/dynamics/RandNI.java b/contrib/psg/src/peersim/dynamics/RandNI.java
new file mode 100644
index 0000000000..7a4d5c749c
--- /dev/null
+++ b/contrib/psg/src/peersim/dynamics/RandNI.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.dynamics;
+
+import peersim.core.*;
+import peersim.config.Configuration;
+
+/**
+ * Initializes the neighbor list of a node with random links.
+ */
+public class RandNI implements NodeInitializer {
+
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * The protocol to operate on.
+ * @config
+ */
+private static final String PAR_PROT = "protocol";
+
+/**
+ * The number of samples (with replacement) to draw to initialize the
+ * neighbor list of the node.
+ * @config
+ */
+private static final String PAR_DEGREE = "k";
+
+/**
+ * If this config property is defined, method {@link Linkable#pack()} is
+ * invoked on the specified protocol at the end of the wiring phase.
+ * Default to false.
+ * @config
+ */
+private static final String PAR_PACK = "pack";
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+
+/**
+ * The protocol we want to wire
+ */
+private final int pid;
+
+/**
+ * The degree of the regular graph
+ */
+private final int k;
+
+/**
+ * If true, method pack() is invoked on the initialized protocol
+ */
+private final boolean pack;
+
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Standard constructor that reads the configuration parameters. Invoked by the
+ * simulation engine.
+ * @param prefix the configuration prefix for this class
+ */
+public RandNI(String prefix)
+{
+ pid = Configuration.getPid(prefix + "." + PAR_PROT);
+ k = Configuration.getInt(prefix + "." + PAR_DEGREE);
+ pack = Configuration.contains(prefix + "." + PAR_PACK);
+}
+
+//--------------------------------------------------------------------------
+//Methods
+//--------------------------------------------------------------------------
+
+/**
+ * Takes {@value #PAR_DEGREE} random samples with replacement from the nodes of
+ * the overlay network. No loop edges are added.
+ */
+public void initialize(Node n)
+{
+ if (Network.size() == 0) return;
+
+ Linkable linkable = (Linkable) n.getProtocol(pid);
+ for (int j = 0; j < k; ++j)
+ {
+ int r = CommonState.r.nextInt(Network.size());
+ linkable.addNeighbor(Network.get(r));
+ }
+
+ if (pack) linkable.pack();
+}
+
+}
+
diff --git a/contrib/psg/src/peersim/dynamics/StarNI.java b/contrib/psg/src/peersim/dynamics/StarNI.java
new file mode 100644
index 0000000000..4dbd8664df
--- /dev/null
+++ b/contrib/psg/src/peersim/dynamics/StarNI.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.dynamics;
+
+import peersim.core.*;
+import peersim.config.Configuration;
+
+/**
+ * Initializes a node's neighbor list with a fixed center.
+ */
+public class StarNI implements NodeInitializer {
+
+
+// ========================= fields =================================
+// ==================================================================
+
+
+/**
+ * The protocol to operate on.
+ * @config
+ */
+private static final String PAR_PROT = "protocol";
+
+/**
+ * If this config property is defined, method {@link Linkable#pack()} is
+ * invoked on the specified protocol at the end of the wiring phase.
+ * Default to false.
+ * @config
+ */
+private static final String PAR_PACK = "pack";
+
+/**
+ * The protocol we want to wire
+ */
+protected final int pid;
+
+/** If true, method pack() is invoked on the initialized protocol */
+protected final boolean pack;
+
+/**
+ * Used as center: nodes will link to this node.
+ */
+protected Node center = null;
+
+
+// ==================== initialization ==============================
+//===================================================================
+
+
+public StarNI(String prefix) {
+
+ pid = Configuration.getPid(prefix+"."+PAR_PROT);
+ pack = Configuration.contains(prefix+"."+PAR_PACK);
+}
+
+
+// ===================== public methods ==============================
+// ===================================================================
+
+
+/**
+ * Adds a link to a fixed node, the center. This fixed node remains the same
+ * throughout consecutive calls to this method. If the center fails in the
+ * meantime, a new one is chosen so care should be taken. The center is the
+ * first node that is not down (starting from node 0, 1, etc)
+ * at the time of the first call to the function. When a new center needs to
+ * be chosen (the current one is down), the new center is again the first
+ * one which is up. If no nodes are up, the node with the last index is set
+ * as center, and selection of a new center is always attempted when this
+ * method is called again.
+ */
+public void initialize(Node n) {
+
+ if( Network.size() == 0 ) return;
+
+ for(int i=0; (center==null || !center.isUp()) && ijava.util.Random
+
+ For example, the class {@link WireWS} can be emulated by configuring
+ java.util.Random
then it is initialized with
+ {@link CommonState#r}, the central source of randomness for the
+ simulator.
+ init.0 WireByMethod
+ init.0.class GraphFactory
+ init.0.method wireWS
+ init.0.arg1 10
+ init.0.arg2 0.1
+ ...
+
+ Note that the {@value #PAR_CLASS} parameter defaults to {@link GraphFactory},
+ and {@value #PAR_METHOD} defaults to "wire".
+ */
+public class WireByMethod extends WireGraph {
+
+//--------------------------------------------------------------------------
+//Parameters
+//--------------------------------------------------------------------------
+
+/**
+ * The prefix for the configuration properties that describe parameters.
+ * @config
+ */
+private static final String PAR_ARG = "arg";
+
+/**
+* The class that has the method we want to use. Defaults to
+* {@link GraphFactory}.
+* @config
+*/
+private static final String PAR_CLASS = "class";
+
+/**
+* The name of the method for wiring the graph. Defaults to wire
.
+* @config
+*/
+private static final String PAR_METHOD = "method";
+
+//--------------------------------------------------------------------------
+//Fields
+//--------------------------------------------------------------------------
+
+private final Object[] args;
+
+private final Method method;
+
+//--------------------------------------------------------------------------
+//Initialization
+//--------------------------------------------------------------------------
+
+/**
+ * Loads configuration. It verifies the constraints defined
+ * in {@link WireByMethod}.
+ * @param prefix the configuration prefix for this class
+ */
+public WireByMethod(String prefix)
+{
+ super(prefix);
+
+ // get the method
+ try
+ {
+ final Class wire =
+ Configuration.getClass(prefix + "." + PAR_CLASS,
+ Class.forName("peersim.graph.GraphFactory"));
+ method = WireByMethod.getMethod(
+ wire,
+ Configuration.getString(prefix+"."+PAR_METHOD,"wire"));
+ }
+ catch( Exception e )
+ {
+ throw new RuntimeException(e);
+ }
+
+ // set the constant args (those other than 0th)
+ Class[] argt = method.getParameterTypes();
+ args = new Object[argt.length];
+ for(int i=1; isuper(n)
.
+ */
+ public NextCycleEvent(String n) {
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Returns a clone of the object. Overriding this method is necessary and
+ * typically is as simple as return super.clone()
. In general,
+ * always use super.clone()
to obtain the object to be returned
+ * on which you can perform optional deep cloning operations (arrays, etc).
+ */
+ public Object clone() throws CloneNotSupportedException {
+
+ return super.clone();
+ }
+
+ // ========================== methods ==================================
+ // =====================================================================
+
+ /**
+ * Executes the nextCycle method of the protocol, and schedules the next
+ * call using the delay returned by {@link #nextDelay}. If the next
+ * execution time as defined by the delay is outside of the valid times as
+ * defined by {@link CDScheduler#sch}, then the next event is not scheduled.
+ * Note that this means that this protocol will no longer be scheduled
+ * because the next event after the next event is scheduled by the next
+ * event.
+ */
+ public final void execute() {
+
+ int pid = CommonState.getPid();
+ Node node = CommonState.getNode();
+ CDProtocol cdp = (CDProtocol) node.getProtocol(pid);
+ cdp.nextCycle(node, pid);
+ long delay = nextDelay(CDScheduler.sch[pid].step);
+
+ if (CommonState.getTime() + delay < CDScheduler.sch[pid].until)
+ EDSimulator.add(delay, this, node, pid);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Calculates the delay until the next execution of the protocol. This
+ * default implementation returns a constant delay equal to the step
+ * parameter (cycle length in this case) of the schedule of this event (as
+ * set in the config file).
+ */
+ protected long nextDelay(long step) {
+
+ return step;
+ }
+
+}
diff --git a/contrib/psg/src/peersim/edsim/PriorityQ.java b/contrib/psg/src/peersim/edsim/PriorityQ.java
new file mode 100644
index 0000000000..5525768485
--- /dev/null
+++ b/contrib/psg/src/peersim/edsim/PriorityQ.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c)2008 The Peersim Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.edsim;
+
+import peersim.core.Node;
+
+/**
+ * The interface to be implemented by the event queue of the evend based
+ * engine. An implementation must also provide the standard cosntructor
+ * required by any peersim components: one that takes a String argument,
+ * the component name in the configuration.
+ */
+public interface PriorityQ {
+
+
+/**
+ * Returns the current number of events in the queue.
+ */
+public int size();
+
+/**
+ * Add a new event, to be scheduled at the specified time. If there are other
+ * events scheduled at the same time, then the time of execution if this event
+ * relative to the other events is unspecified.
+ *
+ * @param time The time at which this event should be scheduled. It is
+ * guaranteed to be non-negative (so no extra checks are needed)
+ * @param event the object describing the event
+ * @param node the node at which the event has to be delivered
+ * @param pid the protocol that handles the event
+ */
+public void add(long time, Object event, Node node, byte pid);
+
+/**
+ * Add a new event, to be scheduled at the specified time, specifying also
+ * the priority of the event, should there be other events scheduled at the
+ * same time. If both time and priority is the same for an event, then the
+ * scheduling order is unspecified.
+ *
+ * @param time The time at which this event should be scheduled. It is
+ * guaranteed to be non-negative (so no extra checks are needed)
+ * @param event the object describing the event
+ * @param node the node at which the event has to be delivered
+ * @param pid the protocol that handles the event
+ * @param priority if for two events the "time" value is the same, this
+ * value should be used to order them. Lower value means higher priority.
+ * Like with time, non-negativity as assumed.
+ */
+public void add(long time, Object event, Node node, byte pid, long priority);
+
+/**
+ * Removes the first event in the heap and returns it.
+ * The returned object is not guaranteed to be a freshly generated object,
+ * that is, we allow for an implementation that keeps one copy of an event
+ * object and always returns a reference to that copy.
+ * @return first event or null if size is zero
+ */
+public Event removeFirst();
+
+/**
+* Maximal value of time this interpretation can represent.
+*/
+public long maxTime();
+
+/**
+* Maximal value of priority this interpretation can deal with. That is,
+* the number of different priority levels is maxPriority()+1 because
+* 0 is also a valid level.
+* @see #add(long,Object,Node,byte,long)
+*/
+public long maxPriority();
+
+/**
+ * Return type of {@link #removeFirst()}.
+ */
+public class Event
+{
+ public Object event;
+ public long time;
+ public Node node;
+ public byte pid;
+ public String toString() {
+ return event+" to node "+node+"prot "+pid+"at "+time; }
+}
+
+}
diff --git a/contrib/psg/src/peersim/edsim/RandNextCycle.java b/contrib/psg/src/peersim/edsim/RandNextCycle.java
new file mode 100644
index 0000000000..b74a4f409a
--- /dev/null
+++ b/contrib/psg/src/peersim/edsim/RandNextCycle.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.edsim;
+
+import peersim.core.*;
+
+
+/**
+* Implements random delay between calling the nextCycle method of the protocol.
+* @see #nextDelay
+*/
+public class RandNextCycle extends NextCycleEvent {
+
+
+// =============================== initialization ======================
+// =====================================================================
+
+
+/**
+* Calls super constructor.
+*/
+public RandNextCycle(String n) { super(n); }
+
+// --------------------------------------------------------------------
+
+/**
+* Calls super.clone().
+*/
+public Object clone() throws CloneNotSupportedException {
+
+ return super.clone();
+}
+
+
+// ========================== methods ==================================
+// =====================================================================
+
+
+/**
+* Returns a random delay with uniform distribution between 1 (inclusive) and
+* 2*step
(exclusive)
+* (expected value is therefore step
).
+*/
+protected long nextDelay(long step) {
+
+ return 1+CommonState.r.nextLong((step<<1)-1);
+}
+
+
+}
+
+
diff --git a/contrib/psg/src/peersim/edsim/RegRandNextCycle.java b/contrib/psg/src/peersim/edsim/RegRandNextCycle.java
new file mode 100644
index 0000000000..dbc5edb675
--- /dev/null
+++ b/contrib/psg/src/peersim/edsim/RegRandNextCycle.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2003-2005 The BISON Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+package peersim.edsim;
+
+import peersim.core.*;
+
+
+/**
+* Implements a random delay, but making sure there is exactly one call in each
+* consecutive step
time units.
+*/
+public class RegRandNextCycle extends NextCycleEvent {
+
+// ============================== fields ==============================
+// ====================================================================
+
+/**
+* Indicates the start of the next cycle for a particular protocol
+* instance. If negative it means it has not been initialized yet.
+*/
+private long nextCycleStart = -1;
+
+// =============================== initialization ======================
+// =====================================================================
+
+
+/**
+* Calls super constructor.
+*/
+public RegRandNextCycle(String n) {
+
+ super(n);
+}
+
+// --------------------------------------------------------------------
+
+/**
+* Calls super.clone().
+*/
+public Object clone() throws CloneNotSupportedException {
+
+ return super.clone();
+}
+
+
+// ========================== methods ==================================
+// =====================================================================
+
+
+/**
+* Returns a random delay but making sure there is exactly one invocation in each
+* consecutive interval of length step
. The beginning of these
+* intervals is defined by the first invocation which is in turn defined by
+* {@link CDScheduler} that initiates the protocol in question.
+*/
+protected long nextDelay(long step) {
+
+ // at this point nextCycleStart points to the start of the next cycle
+ // (the cycle after the one in which this execution is taking place)
+ // (note that the start of the cycle is included in the cycle)
+
+ final long now = CommonState.getTime();
+ if(nextCycleStart<0)
+ {
+ // not initialized
+ nextCycleStart=now+step;
+ }
+
+ // to be on the safe side, we do the next while loop.
+ // although currently it never executes
+ while(nextCycleStart<=now) nextCycleStart+=step;
+
+ // we increment nextCycleStart to point to the start of the cycle
+ // after the next cycle
+ nextCycleStart+=step;
+
+ return nextCycleStart-now-CommonState.r.nextLong(step)-1;
+}
+
+}
+
+
diff --git a/contrib/psg/src/peersim/edsim/edsim_jsp.xmi b/contrib/psg/src/peersim/edsim/edsim_jsp.xmi
new file mode 100644
index 0000000000..5fba52dfcc
--- /dev/null
+++ b/contrib/psg/src/peersim/edsim/edsim_jsp.xmi
@@ -0,0 +1,2 @@
+
+